diff --git a/AlgebraicDataflowArchitectureModel/models/VotingSystem.model b/AlgebraicDataflowArchitectureModel/models/VotingSystem.model index ff425db..b0ce8f8 100644 --- a/AlgebraicDataflowArchitectureModel/models/VotingSystem.model +++ b/AlgebraicDataflowArchitectureModel/models/VotingSystem.model @@ -1,5 +1,5 @@ channel Signup { - out accounts(acDB:Map, signUp(aid:Str, name:Str)) = insert(acDB, aid, {"name": name, "vote": null}) + out accounts(acDB:Map, signUp(aid:Str, name:Str)) = insert(acDB, aid, {"name": name, "vote": ""}) } channel Cast(aid:Str) { diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java deleted file mode 100644 index f57b895..0000000 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java +++ /dev/null @@ -1,2402 +0,0 @@ -package algorithms; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.xml.crypto.Data; - -import models.Node; -import models.algebra.Constant; -import models.algebra.Expression; -import models.algebra.Position; -import models.algebra.Symbol; -import models.algebra.Term; -import models.algebra.Type; -import models.algebra.Variable; -import models.dataConstraintModel.Channel; -import models.dataConstraintModel.ChannelMember; -import models.dataConstraintModel.DataConstraintModel; -import models.dataConstraintModel.JsonType; -import models.dataConstraintModel.ResourceHierarchy; -import models.dataConstraintModel.ResourcePath; -import models.dataConstraintModel.Selector; -import models.dataConstraintModel.StateTransition; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.ResourceNode; - -/** - * Type inference for data transfer model - * - * @author Nitta - * - */ -public class TypeInference { - static private Map listTypes = new HashMap<>(); - static private Map listComponentTypes = new HashMap<>(); - static private Map, Type> tupleTypes = new HashMap<>(); - static private Map> tupleComponentTypes = new HashMap<>(); - static private Map pairTypes = new HashMap<>(); - static private Map pairComponentTypes = new HashMap<>(); - static private Map, Type> mapTypes = new HashMap<>(); - static private Map> mapComponentTypes = new HashMap<>(); - static private Map, Type> jsonTypes = new HashMap<>(); - static private Map> jsonMemberTypes = new HashMap<>(); - - public static Type getListType(Type compType) { - return listTypes.get(compType); - } - - public static Type getListComponentType(Type listType) { - return listComponentTypes.get(listType); - } - - public static Collection getListTypes() { - return listTypes.values(); - } - - public static Type getTupleType(List compTypes) { - return tupleTypes.get(compTypes); - } - - public static List getTupleComponentTypes(Type tupleType) { - return tupleComponentTypes.get(tupleType); - } - - public static Collection getTupleTypes() { - return tupleTypes.values(); - } - - public static Type getPairType(Type compType) { - return pairTypes.get(compType); - } - - public static Type getPairComponentType(Type pairType) { - return pairComponentTypes.get(pairType); - } - - public static Type getMapType(List compTypes) { - return mapTypes.get(compTypes); - } - - public static List getMapComponentTypes(Type mapType) { - return mapComponentTypes.get(mapType); - } - - public static Type getJsonType(Map memberTypes) { - return jsonTypes.get(memberTypes); - } - - public static Map getJsonMemberTypes(Type jsonType) { - return jsonMemberTypes.get(jsonType); - } - - static public void infer(DataTransferModel model) { - Map> resources = new HashMap<>(); - Map> resourcePathParams = new HashMap<>(); - Map variables = new HashMap<>(); - Map, Type>>> messages = new HashMap<>(); - Map consOrSet = new HashMap<>(); - Map tuple = new HashMap<>(); - Map pair = new HashMap<>(); - Map map = new HashMap<>(); - Map json = new HashMap<>(); - - // Maps from the objectId of each expression to its belonging group that has the same type as the expression - Map> expToResource = new HashMap<>(); - Map> expToPathParams = new HashMap<>(); - Map> expToVariable = new HashMap<>(); - Map> expToMessage = new HashMap<>(); - Map>> expToConsOrSet = new HashMap<>(); - Map>> expToTuple = new HashMap<>(); - Map>> expToPair = new HashMap<>(); - Map>> expToMap = new HashMap<>(); - Map>> expToJson = new HashMap<>(); - - // Maps from the objectId of each group to the set of updated expressions. - Map> updateFromResource = new HashMap<>(); - Set updateFromResourceOwnership = new HashSet<>(); - Map> updateFromVariable = new HashMap<>(); - Map> updateFromMessage = new HashMap<>(); - Map> updateFromConsOrSet = new HashMap<>(); - Map> updateFromTuple = new HashMap<>(); - Map> updateFromPair = new HashMap<>(); - Map> updateFromMap = new HashMap<>(); - Map> updateFromJson = new HashMap<>(); - - listComponentTypes.put(DataConstraintModel.typeList, null); - listComponentTypes.put(DataConstraintModel.typeListInt, DataConstraintModel.typeInt); - listComponentTypes.put(DataConstraintModel.typeListStr, DataConstraintModel.typeString); - listTypes.put(DataConstraintModel.typeInt, DataConstraintModel.typeListInt); - listTypes.put(DataConstraintModel.typeString, DataConstraintModel.typeListStr); - pairComponentTypes.put(DataConstraintModel.typePair, null); - pairComponentTypes.put(DataConstraintModel.typePairInt, DataConstraintModel.typeInt); - pairComponentTypes.put(DataConstraintModel.typePairStr, DataConstraintModel.typeString); - pairComponentTypes.put(DataConstraintModel.typePairDouble, DataConstraintModel.typeDouble); - pairTypes.put(DataConstraintModel.typeInt, DataConstraintModel.typePairInt); - pairTypes.put(DataConstraintModel.typeString, DataConstraintModel.typePairStr); - pairTypes.put(DataConstraintModel.typeDouble, DataConstraintModel.typePairDouble); - tupleComponentTypes.put(DataConstraintModel.typeTuple, Arrays.asList(new Type[] { null, null })); - mapComponentTypes.put(DataConstraintModel.typeMap, Arrays.asList(new Type[] { null, null })); - - // 1. Collect type information from the architecture model. - Collection channels = new HashSet<>(model.getInputChannels()); - channels.addAll(model.getChannels()); - for (Channel ch : channels) { - // 1.1 Group expressions by resources. - IGroupExpressionsByResource groupExpressionsByResource = new IGroupExpressionsByResource() { - public void groupForChannel(Channel ch) { - for (ChannelMember cm : ch.getChannelMembers()) { - StateTransition st = cm.getStateTransition(); - ResourceHierarchy res = cm.getResource().getResourceHierarchy(); - List identicalResources = resources.get(res); - if (identicalResources == null) { - identicalResources = new ArrayList<>(); - resources.put(res, identicalResources); - } - identicalResources.add(st.getCurStateExpression()); - expToResource.put(System.identityHashCode(st.getCurStateExpression()), identicalResources); - if (st.getNextStateExpression() != null) { - identicalResources.add(st.getNextStateExpression()); - expToResource.put(System.identityHashCode(st.getNextStateExpression()), identicalResources); - } - Map updatedExps = getUpdateSet(updateFromResource, identicalResources); - Type resType = res.getResourceStateType(); - Expression exp = st.getCurStateExpression(); - Type expType = getExpTypeIfUpdatable(resType, exp); - if (expType != null) { - res.setResourceStateType(expType); - for (Expression resExp : identicalResources) { - if (resExp != exp) { - if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { - ((Variable) resExp).setType(expType); - updatedExps.put(System.identityHashCode(resExp), resExp); - } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { - ((Term) resExp).setType(expType); - updatedExps.put(System.identityHashCode(resExp), resExp); - } - } - } - } else if (exp instanceof Variable) { - if (compareTypes(((Variable) exp).getType(), resType)) { - ((Variable) exp).setType(resType); - updatedExps.put(System.identityHashCode(exp), exp); - } - } else if (exp instanceof Term) { - if (compareTypes(((Term) exp).getType(), resType)) { - ((Term) exp).setType(resType); - updatedExps.put(System.identityHashCode(exp), exp); - } - } - resType = res.getResourceStateType(); - exp = st.getNextStateExpression(); - if (exp != null) { - expType = getExpTypeIfUpdatable(resType, exp); - if (expType != null) { - res.setResourceStateType(expType); - for (Expression resExp : identicalResources) { - if (resExp != exp) { - if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { - ((Variable) resExp).setType(expType); - updatedExps.put(System.identityHashCode(resExp), resExp); - } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { - ((Term) resExp).setType(expType); - updatedExps.put(System.identityHashCode(resExp), resExp); - } - } - } - } else if (exp instanceof Variable) { - if (compareTypes(((Variable) exp).getType(), resType)) { - ((Variable) exp).setType(resType); - updatedExps.put(System.identityHashCode(exp), exp); - } - } else if (exp instanceof Term) { - if (compareTypes(((Term) exp).getType(), resType)) { - ((Term) exp).setType(resType); - updatedExps.put(System.identityHashCode(exp), exp); - } - } - } - } - for (Channel childCh: ch.getChildren()) { - groupForChannel(childCh); - } - } - }; - groupExpressionsByResource.groupForChannel(ch); - - // 1.2 Group expressions by variable. - IGroupExpressionsByVariable groupExpressionsByVariable = new IGroupExpressionsByVariable() { - public void groupForChannel(Channel ch) { - for (ChannelMember cm : ch.getChannelMembers()) { - StateTransition st = cm.getStateTransition(); - Map> locals = new HashMap<>(); - Map localTypes = new HashMap<>(); - List allVariables = new ArrayList<>(); - allVariables.addAll(st.getCurStateExpression().getVariables().values()); - allVariables.addAll(st.getMessageExpression().getVariables().values()); - if (st.getNextStateExpression() != null) { - allVariables.addAll(st.getNextStateExpression().getVariables().values()); - } - for (Selector s: ch.getAllSelectors()) { // add channel selectors - if (s.getExpression() instanceof Variable) { - allVariables.add((Variable) s.getExpression()); - } - } - ResourcePath resPath = cm.getResource(); - for (Expression param: resPath.getPathParams()) { // add path parameters - if (param instanceof Variable) { - allVariables.add((Variable) param); - } else if (param instanceof Term) { - allVariables.addAll(((Term) param).getVariables().values()); - } - } - for (Variable var : allVariables) { - List sameVariable = locals.get(var.getName()); - if (sameVariable == null) { - sameVariable = new ArrayList<>(); - sameVariable.add(var); - expToVariable.put(System.identityHashCode(var), sameVariable); - locals.put(var.getName(), sameVariable); - localTypes.put(var.getName(), var.getType()); - } else { - sameVariable.add(var); - expToVariable.put(System.identityHashCode(var), sameVariable); - Type varType = localTypes.get(var.getName()); - Map updatedVars = getUpdateSet(updateFromVariable, sameVariable); - if (compareTypes(varType, var.getType())) { - localTypes.put(var.getName(), var.getType()); - for (Expression v : sameVariable) { - if (v != var) { - if (compareTypes(((Variable) v).getType(), var.getType())) { - ((Variable) v).setType(var.getType()); - updatedVars.put(System.identityHashCode(v), v); - } - } - } - } else if (compareTypes(var.getType(), varType)) { - var.setType(varType); - updatedVars.put(System.identityHashCode(var), var); - } - } - } - for (String varName : locals.keySet()) { - variables.put(System.identityHashCode(locals.get(varName)), localTypes.get(varName)); - } - } - for (Channel childCh: ch.getChildren()) { - groupForChannel(childCh); - } - } - }; - groupExpressionsByVariable.groupForChannel(ch); - - // 1.3 Group expressions by message. - IGroupExpressionsByMessage groupExpressionsByMessage = new IGroupExpressionsByMessage() { - public void groupForChannel(Channel rootCh, Channel ch) { - for (ChannelMember cm : ch.getChannelMembers()) { - Expression message = cm.getStateTransition().getMessageExpression(); - if (message instanceof Variable) { - Type msgType = ((Variable) message).getType(); - Map, Type>> msgTypeMap = messages.get(rootCh); - if (msgTypeMap == null) { - msgTypeMap = new HashMap<>(); - messages.put(rootCh, msgTypeMap); - } - Map.Entry, Type> typeAndExps = msgTypeMap.get(0); - if (typeAndExps == null) { - List exps = new ArrayList<>(); - exps.add(message); - typeAndExps = new AbstractMap.SimpleEntry<>(exps, msgType); - msgTypeMap.put(0, typeAndExps); - expToMessage.put(System.identityHashCode(message), exps); - } else { - typeAndExps.getKey().add(message); - expToMessage.put(System.identityHashCode(message), typeAndExps.getKey()); - Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); - if (compareTypes(typeAndExps.getValue(), msgType)) { - typeAndExps.setValue(msgType); - for (Expression e : typeAndExps.getKey()) { - if (e != message) { - if (e instanceof Variable) { - ((Variable) e).setType(msgType); - updateExps.put(System.identityHashCode(e), e); - } - } - } - } else if (compareTypes(msgType, typeAndExps.getValue())) { - ((Variable) message).setType(typeAndExps.getValue()); - updateExps.put(System.identityHashCode(message), message); - } - } - } else if (message instanceof Term) { - Map, Type>> msgTypeMap = messages.get(rootCh); - if (msgTypeMap == null) { - msgTypeMap = new HashMap<>(); - messages.put(rootCh, msgTypeMap); - } - for (int i = 0; i < ((Term) message).getArity(); i++) { - Expression arg = ((Term) message).getChild(i); - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } else { - continue; - } - Map.Entry, Type> typeAndExps = msgTypeMap.get(i); - if (typeAndExps == null) { - List exps = new ArrayList<>(); - exps.add(arg); - typeAndExps = new AbstractMap.SimpleEntry<>(exps, argType); - msgTypeMap.put(i, typeAndExps); - expToMessage.put(System.identityHashCode(arg), exps); - } else { - typeAndExps.getKey().add(arg); - expToMessage.put(System.identityHashCode(arg), typeAndExps.getKey()); - Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); - if (compareTypes(typeAndExps.getValue(), argType)) { - typeAndExps.setValue(argType); - for (Expression e : typeAndExps.getKey()) { - if (e != arg) { - if (e instanceof Variable) { - ((Variable) e).setType(argType); - updateExps.put(System.identityHashCode(e), e); - } - } - } - } else if (compareTypes(argType, typeAndExps.getValue())) { - if (arg instanceof Variable) { - ((Variable) arg).setType(typeAndExps.getValue()); - updateExps.put(System.identityHashCode(arg), arg); - } else if (arg instanceof Term) { - ((Term) arg).setType(typeAndExps.getValue()); - updateExps.put(System.identityHashCode(arg), arg); - } - } - } - } - } - } - for (Channel childCh: ch.getChildren()) { - groupForChannel(rootCh, childCh); - } - } - }; - groupExpressionsByMessage.groupForChannel(ch, ch); - - // 1.4 Extract constraints on expressions in each term. - IExtractConstraintsOnExpressionsInTerm extractConstraintsOnExpressionsInTerm = new IExtractConstraintsOnExpressionsInTerm() { - public void extractForChannel(Channel ch) { - for (ChannelMember cm : ch.getChannelMembers()) { - StateTransition st = cm.getStateTransition(); - List terms = new ArrayList<>(); - if (st.getCurStateExpression() instanceof Term) { - Map subTerms = ((Term) st.getCurStateExpression()).getSubTerms(Term.class); - terms.addAll(subTerms.values()); - } - if (st.getMessageExpression() instanceof Term) { - Map subTerms = ((Term) st.getMessageExpression()).getSubTerms(Term.class); - terms.addAll(subTerms.values()); - } - if (st.getNextStateExpression() != null && st.getNextStateExpression() instanceof Term) { - Map subTerms = ((Term) st.getNextStateExpression()).getSubTerms(Term.class); - terms.addAll(subTerms.values()); - } - for (Term t : terms) { - Symbol symbol = t.getSymbol(); - if (symbol.equals(DataConstraintModel.cons) || symbol.equals(DataConstraintModel.set) || symbol.equals(DataConstraintModel.append)) { - // If the root symbol of the term is cons or set. - List consExps = new ArrayList<>(); - consExps.add(t); // list term - updateExpressionBelonging(expToConsOrSet, t, consExps); - if (symbol.equals(DataConstraintModel.cons)) { - // If the root symbol of the term is cons. - for (Expression e : t.getChildren()) { - consExps.add(e); - updateExpressionBelonging(expToConsOrSet, e, consExps); - } - } else if (symbol.equals(DataConstraintModel.append)) { - // If the root symbol of the term is append. - Expression e = t.getChildren().get(1); - consExps.add(e); // list element - updateExpressionBelonging(expToConsOrSet, e, consExps); - e = t.getChildren().get(0); - consExps.add(e); // list argument - updateExpressionBelonging(expToConsOrSet, e, consExps); - } else { - // If the root symbol of the term is set. - Expression e = t.getChildren().get(2); - consExps.add(e); // list element - updateExpressionBelonging(expToConsOrSet, e, consExps); - e = t.getChildren().get(0); - consExps.add(e); // list argument - updateExpressionBelonging(expToConsOrSet, e, consExps); - } - Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); - if (newType != null) { - // If the type of the 2nd argument of cons (1st argument of set/append) is more concrete than the type of the term. - t.setType(newType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - } else { - Type arg2Type = null; - if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { - arg2Type = ((Variable) consExps.get(2)).getType(); - if (compareTypes(arg2Type, t.getType())) { - // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set/append). - ((Variable) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { - arg2Type = ((Term) consExps.get(2)).getType(); - if (compareTypes(arg2Type, t.getType())) { - // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set/append). - ((Term) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } - } - Type newCompType = getExpTypeIfUpdatable(listComponentTypes.get(t.getType()), consExps.get(1)); - if (newCompType != null) { - // If the type of the 1st argument of cons (3rd argument of set) is more concrete than the type of list component. - Type newListType = listTypes.get(newCompType); - if (newListType == null) { - // Create new list type. - newListType = createNewListType(newCompType, DataConstraintModel.typeList); - } - t.setType(newListType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { - ((Variable) consExps.get(2)).setType(newListType); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { - ((Term) consExps.get(2)).setType(newListType); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } - consOrSet.put(System.identityHashCode(consExps), t.getType()); - } else if (symbol.equals(DataConstraintModel.head) || symbol.equals(DataConstraintModel.get)) { - // If the root symbol of the term is head or get. - List consExps = new ArrayList<>(); - Expression e = t.getChildren().get(0); - consExps.add(e); // list argument - updateExpressionBelonging(expToConsOrSet, e, consExps); - consExps.add(t); // list's component - updateExpressionBelonging(expToConsOrSet, t, consExps); - consExps.add(null); - Type listType = listTypes.get(t.getType()); - if (listType == null && t.getType() != null) { - // Create a new list type. - listType = createNewListType(t.getType(), DataConstraintModel.typeList); - } - Type newListType = getExpTypeIfUpdatable(listType, consExps.get(0)); - if (newListType != null) { - // If the type of the component of the 1st argument is more concrete than the type of the term. - Type newCompType = listComponentTypes.get(newListType); - if (newCompType != null) { - t.setType(newCompType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - } - consOrSet.put(System.identityHashCode(consExps), newListType); - } else { - // If the type of the term is more concrete than the type of the component of the 1st argument. - if (consExps.get(0) != null && consExps.get(0) instanceof Variable) { - ((Variable) consExps.get(0)).setType(listType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); - } else if (consExps.get(0) != null && consExps.get(0) instanceof Term) { - ((Term) consExps.get(0)).setType(listType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); - } - consOrSet.put(System.identityHashCode(consExps), listType); - } - } else if (symbol.equals(DataConstraintModel.tail)) { - // If the root symbol of the term is tail. - List consExps = new ArrayList<>(); - consExps.add(t); // list term - updateExpressionBelonging(expToConsOrSet, t, consExps); - consExps.add(null); // list's component - Expression e = t.getChildren().get(0); - consExps.add(e); // list argument - updateExpressionBelonging(expToConsOrSet, e, consExps); - Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); - if (newType != null) { - // If the type of the argument is more concrete than the type of the term. - t.setType(newType); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(t), t); - } else { - Type argType = null; - if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { - argType = ((Variable) consExps.get(2)).getType(); - if (compareTypes(argType, t.getType())) { - // If the type of the term is more concrete than the type of the argument. - ((Variable) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { - argType = ((Term) consExps.get(2)).getType(); - if (compareTypes(argType, t.getType())) { - // If the type of the term is more concrete than the type of the argument. - ((Term) consExps.get(2)).setType(t.getType()); - Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); - updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); - } - } - } - consOrSet.put(System.identityHashCode(consExps), t.getType()); - } else if (symbol.equals(DataConstraintModel.tuple)) { - // If the root symbol of the term is tuple. - List tupleExps = new ArrayList<>(); - List newArgTypesList = new ArrayList<>(); - tupleExps.add(t); // tuple term - updateExpressionBelonging(expToTuple, t, tupleExps); - for (Expression e : t.getChildren()) { - tupleExps.add(e); // tuple's component - updateExpressionBelonging(expToTuple, e, tupleExps); - if (e instanceof Variable) { - newArgTypesList.add(((Variable) e).getType()); - } else if (e instanceof Term) { - newArgTypesList.add(((Term) e).getType()); - } else { - newArgTypesList.add(null); - } - } - if (t.getType() == DataConstraintModel.typeTuple) { - Type newTupleType = tupleTypes.get(newArgTypesList); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(newArgTypesList, DataConstraintModel.typeTuple); - } - // Update the type of the tuple term and record the updated expression. - t.setType(newTupleType); - Map updateExps = getUpdateSet(updateFromTuple, tupleExps); - updateExps.put(System.identityHashCode(t), t); - } - tuple.put(System.identityHashCode(tupleExps), t.getType()); - } else if (symbol.equals(DataConstraintModel.pair)) { - // If the root symbol of the term is pair. - List pairExps = new ArrayList<>(); - pairExps.add(t); // pair - updateExpressionBelonging(expToPair, t, pairExps); - if (t.getType() == DataConstraintModel.typePair) { - for (Expression e : t.getChildren()) { - pairExps.add(e); // left/right - updateExpressionBelonging(expToPair, e, pairExps); - Type newArgType = null; - if (e instanceof Variable) { - newArgType = (((Variable) e).getType()); - - } else if (e instanceof Term) { - newArgType = (((Term) e).getType()); - } - - if (newArgType != null) { - Type newPairType = pairTypes.get(newArgType); - if (newPairType != null) { - t.setType(newPairType); - Map updateExps = getUpdateSet(updateFromPair, pairExps); - updateExps.put(System.identityHashCode(t), t); - } - } - } - pair.put(System.identityHashCode(pairExps), t.getType()); - - } - } else if (symbol.equals(DataConstraintModel.fst)) { - // If the root symbol of the term is fst. - List tupleExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - tupleExps.add(arg); // tuple argument - updateExpressionBelonging(expToTuple, arg, tupleExps); - tupleExps.add(t); // first component - updateExpressionBelonging(expToTuple, t, tupleExps); - tupleExps.add(null); // second component - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newTupleType = DataConstraintModel.typeTuple; - if (argType == DataConstraintModel.typeTuple && t.getType() != null) { - List newCompTypeList = new ArrayList<>(); - newCompTypeList.add(t.getType()); - newCompTypeList.add(null); - newTupleType = tupleTypes.get(newCompTypeList); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); - } - } - if (argType != newTupleType && newTupleType != null) { - // Update the type of the tuple argument and record the updated expression. - if (arg instanceof Variable) { - ((Variable) arg).setType(newTupleType); - argType = newTupleType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newTupleType); - argType = newTupleType; - } - Map updateExps = getUpdateSet(updateFromTuple, tupleExps); - updateExps.put(System.identityHashCode(arg), arg); - } - tuple.put(System.identityHashCode(tupleExps), argType); - } else if (symbol.equals(DataConstraintModel.snd)) { - // If the root symbol of the term is snd. - List tupleExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - tupleExps.add(arg); // tuple argument - updateExpressionBelonging(expToTuple, arg, tupleExps); - tupleExps.add(null); // first component - tupleExps.add(t); // second component - updateExpressionBelonging(expToTuple, t, tupleExps); - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newTupleType = DataConstraintModel.typeTuple; - if (argType == DataConstraintModel.typeTuple && t.getType() != null) { - List newCompTypeList = new ArrayList<>(); - newCompTypeList.add(null); - if (DataConstraintModel.typeTuple.isAncestorOf(t.getType())) { - List sndTypes = tupleComponentTypes.get(t.getType()); - if (sndTypes != null) { - for (Type t2: sndTypes) { - newCompTypeList.add(t2); - } - } else { - newCompTypeList.add(t.getType()); - } - } else { - newCompTypeList.add(t.getType()); - } - newTupleType = tupleTypes.get(newCompTypeList); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); - } - } - if (argType != newTupleType && newTupleType != null) { - // Update the type of the tuple argument and record the updated expression. - if (arg instanceof Variable) { - ((Variable) arg).setType(newTupleType); - argType = newTupleType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newTupleType); - argType = newTupleType; - } - Map updateExps = getUpdateSet(updateFromTuple, tupleExps); - updateExps.put(System.identityHashCode(arg), arg); - } - tuple.put(System.identityHashCode(tupleExps), argType); - } else if (symbol.equals(DataConstraintModel.left)) { - // If the root symbol of the term is left. - List pairExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - pairExps.add(arg); // pair - updateExpressionBelonging(expToPair, arg, pairExps); - pairExps.add(t); // left - updateExpressionBelonging(expToPair, t, pairExps); - pairExps.add(null); // right - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newPairType = DataConstraintModel.typePair; - if (argType == DataConstraintModel.typePair && t.getType() != null) { - List newCompTypeList = new ArrayList<>(); - newCompTypeList.add(t.getType()); - newCompTypeList.add(null); - newPairType = pairTypes.get(newCompTypeList); - if (newPairType == null) { - // Create new tuple type; - newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); - } - } - if (argType != newPairType && newPairType != null) { - if (arg instanceof Variable) { - ((Variable) arg).setType(newPairType); - argType = newPairType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newPairType); - argType = newPairType; - } - Map updateExps = getUpdateSet(updateFromPair, pairExps); - updateExps.put(System.identityHashCode(arg), arg); - } - pair.put(System.identityHashCode(pairExps), argType); - } else if (symbol.equals(DataConstraintModel.right)) { - // If the root symbol of the term is right. - List pairExps = new ArrayList<>(); - Expression arg = t.getChildren().get(0); - pairExps.add(arg); // pair - updateExpressionBelonging(expToPair, arg, pairExps); - pairExps.add(null); // left - pairExps.add(t); // right - updateExpressionBelonging(expToPair, t, pairExps); - Type argType = null; - if (arg instanceof Variable) { - argType = ((Variable) arg).getType(); - } else if (arg instanceof Term) { - argType = ((Term) arg).getType(); - } - Type newPairType = DataConstraintModel.typePair; - if (argType == DataConstraintModel.typePair && t.getType() != null) { - List newCompTypeList = new ArrayList<>(); - newCompTypeList.add(null); - newCompTypeList.add(t.getType()); - newPairType = pairTypes.get(newCompTypeList); - if (newPairType == null) { - // Create new tuple type; - newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); - } - } - if (argType != newPairType && newPairType != null) { - if (arg instanceof Variable) { - ((Variable) arg).setType(newPairType); - argType = newPairType; - } else if (arg instanceof Term) { - ((Term) arg).setType(newPairType); - argType = newPairType; - } - Map updateExps = getUpdateSet(updateFromPair, pairExps); - updateExps.put(System.identityHashCode(arg), arg); - } - pair.put(System.identityHashCode(pairExps), argType); - } else if (symbol.equals(DataConstraintModel.lookup)) { - // If the root symbol of the term is lookup. - List mapExps = new ArrayList<>(); - Expression arg1 = t.getChildren().get(0); // map - mapExps.add(arg1); - updateExpressionBelonging(expToMap, arg1, mapExps); - Expression arg2 = t.getChildren().get(1); // key - mapExps.add(arg2); - updateExpressionBelonging(expToMap, arg2, mapExps); - mapExps.add(t); // value - updateExpressionBelonging(expToMap, t, mapExps); - Type arg1Type = null; - if (arg1 instanceof Variable) { - arg1Type = ((Variable) arg1).getType(); - } else if (arg1 instanceof Term) { - arg1Type = ((Term) arg1).getType(); - } - List newCompTypeList = new ArrayList<>(); - if (arg2 instanceof Variable) { - newCompTypeList.add(((Variable) arg2).getType()); - } else if (arg2 instanceof Term) { - newCompTypeList.add(((Term) arg2).getType()); - } else { - newCompTypeList.add(null); - } - newCompTypeList.add(t.getType()); - if (arg1Type == DataConstraintModel.typeMap || arg1Type == null) { - Type newMapType = mapTypes.get(newCompTypeList); - if (newMapType == null) { - // Create new tuple type; - newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); - } - // Update the type of the map argument and record the updated expression. - if (arg1 instanceof Variable) { - ((Variable) arg1).setType(newMapType); - arg1Type = newMapType; - } else if (arg1 instanceof Term) { - ((Term) arg1).setType(newMapType); - arg1Type = newMapType; - } - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(arg1), arg1); - } - map.put(System.identityHashCode(mapExps), arg1Type); - } else if (symbol.equals(DataConstraintModel.insert)) { - // If the root symbol of the term is insert. - List mapExps = new ArrayList<>(); - mapExps.add(t); // map - updateExpressionBelonging(expToMap, t, mapExps); - Expression arg1 = t.getChildren().get(1); // key - mapExps.add(arg1); - updateExpressionBelonging(expToMap, arg1, mapExps); - Expression arg2 = t.getChildren().get(2); // value - mapExps.add(arg2); - updateExpressionBelonging(expToMap, arg2, mapExps); - Expression arg0 = t.getChildren().get(0); // map - mapExps.add(arg0); - updateExpressionBelonging(expToMap, arg0, mapExps); - Type termType = t.getType(); - List newCompTypeList = new ArrayList<>(); - if (arg1 instanceof Variable) { - newCompTypeList.add(((Variable) arg1).getType()); - } else if (arg1 instanceof Term) { - newCompTypeList.add(((Term) arg1).getType()); - } else { - newCompTypeList.add(null); - } - if (arg2 instanceof Variable) { - newCompTypeList.add(((Variable) arg2).getType()); - } else if (arg2 instanceof Term) { - newCompTypeList.add(((Term) arg2).getType()); - } else { - newCompTypeList.add(null); - } - Type newTermType = getExpTypeIfUpdatable(termType, mapExps.get(3)); - if (newTermType != null) { - // If the type of the 1st argument of insert is more concrete than the type of the term. - t.setType(newTermType); - termType = newTermType; - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(t), t); - } else { - Type arg3Type = null; - if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { - arg3Type = ((Variable) mapExps.get(3)).getType(); - if (compareTypes(arg3Type, t.getType())) { - // If the type of the term is more concrete than the type of the 1st argument of insert. - ((Variable) mapExps.get(3)).setType(t.getType()); - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); - } - } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { - arg3Type = ((Term) mapExps.get(3)).getType(); - if (compareTypes(arg3Type, t.getType())) { - // If the type of the term is more concrete than the type of the 1st argument of insert. - ((Term) mapExps.get(3)).setType(t.getType()); - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); - } - } - } - if (termType == DataConstraintModel.typeMap || termType == null) { - Type newMapType = mapTypes.get(newCompTypeList); - if (newMapType == null) { - // Create new tuple type; - newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); - } - // Update the type of the map term and record the updated expression. - t.setType(newMapType); - Map updateExps = getUpdateSet(updateFromMap, mapExps); - updateExps.put(System.identityHashCode(t), t); - if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { - ((Variable) mapExps.get(3)).setType(newMapType); - updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); - } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { - ((Term) mapExps.get(3)).setType(newMapType); - updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); - } - termType = newMapType; - } - map.put(System.identityHashCode(mapExps), termType); - } else if (symbol.equals(DataConstraintModel.addMember)) { - // If the root symbol of the term is addMember (addMember(json, key, value)). - List dotExps = new ArrayList<>(); - Expression jsonArg = t.getChildren().get(0); - Expression keyArg = t.getChildren().get(1); - Expression valueArg = t.getChildren().get(2); - dotExps.add(t); // json - updateExpressionBelonging(expToJson, t, dotExps); - dotExps.add(keyArg); // key - updateExpressionBelonging(expToJson, keyArg, dotExps); - dotExps.add(valueArg); // value - updateExpressionBelonging(expToJson, valueArg, dotExps); - dotExps.add(jsonArg); // json - updateExpressionBelonging(expToJson, jsonArg, dotExps); - Type jsonType = t.getType(); - Type valueType = null; - if (valueArg instanceof Variable) { - valueType = ((Variable) valueArg).getType(); - } else if (valueArg instanceof Term) { - valueType = ((Term) valueArg).getType(); - } - String keyName = null; - if (keyArg instanceof Constant) { - keyName = ((Constant) keyArg).getSymbol().getName(); - } - Type jsonArgType = null; - if (jsonArg instanceof Variable) { - jsonArgType = ((Variable) jsonArg).getType(); - } else if (jsonArg instanceof Term) { - jsonArgType = ((Term) jsonArg).getType(); - } - Type newJsonType = DataConstraintModel.typeJson; - if (jsonType == DataConstraintModel.typeJson && jsonArgType != null && keyName != null) { - Map newMemberTypes = new HashMap<>(((JsonType) jsonArgType).getMemberTypes()); - newMemberTypes.put(keyName, valueType); - newJsonType = jsonTypes.get(newMemberTypes); - if (newJsonType == null) { - // Create new json type; - newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); - } - } - if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { - // Update the type of the json term and record the updated expression. - t.setType(newJsonType); - jsonType = newJsonType; - Map updateExps = getUpdateSet(updateFromJson, dotExps); - updateExps.put(System.identityHashCode(t), t); - } - json.put(System.identityHashCode(dotExps), jsonType); - } else if (symbol.equals(DataConstraintModel.dot)) { - // If the root symbol of the term is dot (json.property). - List dotExps = new ArrayList<>(); - Expression jsonArg = t.getChildren().get(0); - Expression keyArg = t.getChildren().get(1); - dotExps.add(jsonArg); // json - updateExpressionBelonging(expToJson, jsonArg, dotExps); - dotExps.add(keyArg); // key - updateExpressionBelonging(expToJson, keyArg, dotExps); - dotExps.add(t); // value - updateExpressionBelonging(expToJson, t, dotExps); - dotExps.add(null); // json - Type jsonType = null; - if (jsonArg instanceof Variable) { - jsonType = ((Variable) jsonArg).getType(); - } else if (jsonArg instanceof Term) { - jsonType = ((Term) jsonArg).getType(); - } - String keyName = null; - if (keyArg instanceof Constant) { - keyName = ((Constant) keyArg).getSymbol().getName(); - } - Type newJsonType = DataConstraintModel.typeJson; - if (jsonType == DataConstraintModel.typeJson && t.getType() != null && keyName != null) { - Map newMemberTypes = new HashMap<>(); - newMemberTypes.put(keyName, t.getType()); - newJsonType = jsonTypes.get(newMemberTypes); - if (newJsonType == null) { - // Create new json type; - newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); - } - } - if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { - // Update the type of the json argument and record the updated expression. - if (jsonArg instanceof Variable) { - ((Variable) jsonArg).setType(newJsonType); - jsonType = newJsonType; - } else if (jsonArg instanceof Term) { - ((Term) jsonArg).setType(newJsonType); - jsonType = newJsonType; - } - Map updateExps = getUpdateSet(updateFromJson, dotExps); - updateExps.put(System.identityHashCode(jsonArg), jsonArg); - } - json.put(System.identityHashCode(dotExps), jsonType); - } else if (symbol.equals(DataConstraintModel.dotParam)) { - // If the root symbol of the term is dot (json.{param}). - List dotExps = new ArrayList<>(); - Expression jsonArg = t.getChildren().get(0); - Expression keyArg = t.getChildren().get(1); - dotExps.add(jsonArg); // json (list/map) - updateExpressionBelonging(expToJson, jsonArg, dotExps); - dotExps.add(null); // key - dotExps.add(t); // value - updateExpressionBelonging(expToJson, t, dotExps); - dotExps.add(null); // json - Type jsonType = null; - if (jsonArg instanceof Variable) { - jsonType = ((Variable) jsonArg).getType(); - } else if (jsonArg instanceof Term) { - jsonType = ((Term) jsonArg).getType(); - } - Type keyType = null; - if (keyArg instanceof Variable) { - keyType = ((Variable) keyArg).getType(); - } else if (keyArg instanceof Term) { - keyType = ((Term) keyArg).getType(); - } - Type newJsonType = null; - if (keyType == DataConstraintModel.typeInt) { - newJsonType = DataConstraintModel.typeList; - } else if (keyType == DataConstraintModel.typeString) { - newJsonType = DataConstraintModel.typeMap; - } - if (t.getType() != null) { - if ((jsonType == DataConstraintModel.typeList)) { - newJsonType = listTypes.get(t.getType()); - if (newJsonType == null) { - // Create new list type; - newJsonType = createNewListType(t.getType(), DataConstraintModel.typeList); - } - } else if (jsonType == DataConstraintModel.typeMap) { - List keyValueTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, t.getType()}); - newJsonType = mapTypes.get(keyValueTypes); - if (newJsonType == null) { - // Create new map type; - newJsonType = createNewMapType(keyValueTypes, DataConstraintModel.typeMap); - } - } - } - if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { - // Update the type of the json argument and record the updated expression. - if (jsonArg instanceof Variable) { - ((Variable) jsonArg).setType(newJsonType); - jsonType = newJsonType; - } else if (jsonArg instanceof Term) { - ((Term) jsonArg).setType(newJsonType); - jsonType = newJsonType; - } - Map updateExps = getUpdateSet(updateFromJson, dotExps); - updateExps.put(System.identityHashCode(jsonArg), jsonArg); - } - json.put(System.identityHashCode(dotExps), jsonType); - } else if (symbol.equals(DataConstraintModel.cond)) { - // If the root symbol of the term is if function. - Expression c1 = t.getChild(1); - Expression c2 = t.getChild(2); - List condTerms = new ArrayList<>(); - condTerms.add(t); - condTerms.add(c1); - condTerms.add(c2); - expToVariable.put(System.identityHashCode(t), condTerms); - expToVariable.put(System.identityHashCode(c1), condTerms); - expToVariable.put(System.identityHashCode(c2), condTerms); - Type condType = t.getType(); - Map updatedVars = getUpdateSet(updateFromVariable, condTerms); - Type child1Type = getExpTypeIfUpdatable(condType, c1); - if (child1Type != null) { - condType = child1Type; - t.setType(child1Type); - updatedVars.put(System.identityHashCode(t), t); - } else { - if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), condType)) { - ((Variable) c1).setType(condType); - updatedVars.put(System.identityHashCode(c1), c1); - } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), condType)) { - ((Term) c1).setType(condType); - updatedVars.put(System.identityHashCode(c1), c1); - } - } - Type child2Type = getExpTypeIfUpdatable(condType, c2); - if (child2Type != null) { - condType = child2Type; - t.setType(child2Type); - updatedVars.put(System.identityHashCode(t), t); - if (c1 instanceof Variable) { - ((Variable) c1).setType(child2Type); - updatedVars.put(System.identityHashCode(c1), c1); - } else if (c1 instanceof Term) { - ((Term) c1).setType(child2Type); - updatedVars.put(System.identityHashCode(c1), c1); - } - } else { - if (c2 instanceof Variable && compareTypes(((Variable) c2).getType(), condType)) { - ((Variable) c2).setType(condType); - updatedVars.put(System.identityHashCode(c2), c2); - } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), condType)) { - ((Term) c2).setType(condType); - updatedVars.put(System.identityHashCode(c2), c2); - } - } - variables.put(System.identityHashCode(condTerms), condType); - } else if (symbol.equals(DataConstraintModel.add) || symbol.equals(DataConstraintModel.sub) - || symbol.equals(DataConstraintModel.mul) || symbol.equals(DataConstraintModel.div)) { - // If the root symbol of the term is arithmetic operators. - Expression c1 = t.getChild(0); - Expression c2 = t.getChild(1); - List operands = new ArrayList<>(); - operands.add(t); - operands.add(c1); - operands.add(c2); - expToVariable.put(System.identityHashCode(t), operands); - expToVariable.put(System.identityHashCode(c1), operands); - expToVariable.put(System.identityHashCode(c2), operands); - Type opType = t.getType(); - Map updatedVars = getUpdateSet(updateFromVariable, operands); - Type child1Type = getExpTypeIfUpdatable(opType, c1); - if (child1Type != null) { - opType = child1Type; - t.setType(child1Type); - updatedVars.put(System.identityHashCode(t), t); - } else { - if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), opType)) { - ((Variable) c1).setType(opType); - updatedVars.put(System.identityHashCode(c1), c1); - } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), opType)) { - ((Term) c1).setType(opType); - updatedVars.put(System.identityHashCode(c1), c1); - } - } - Type child2Type = getExpTypeIfUpdatable(opType, c2); - if (child2Type != null) { - opType = child2Type; - t.setType(child2Type); - updatedVars.put(System.identityHashCode(t), t); - if (c1 instanceof Variable) { - ((Variable) c1).setType(child2Type); - updatedVars.put(System.identityHashCode(c1), c1); - } else if (c1 instanceof Term) { - ((Term) c1).setType(child2Type); - updatedVars.put(System.identityHashCode(c1), c1); - } - } else { - if (c2 instanceof Variable && compareTypes(((Variable) c2).getType(), opType)) { - ((Variable) c2).setType(opType); - updatedVars.put(System.identityHashCode(c2), c2); - } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), opType)) { - ((Term) c2).setType(opType); - updatedVars.put(System.identityHashCode(c2), c2); - } - } - variables.put(System.identityHashCode(operands), opType); - } else if (symbol.getSignature() != null - && symbol.getSignature()[0] == DataConstraintModel.typeList) { - // If the root symbol of the term is the list type (except for the cons function). - List consExps = new ArrayList<>(); - consExps.add(t); - expToVariable.put(System.identityHashCode(t), consExps); - Type condType = t.getType(); - Map updatedVars = getUpdateSet(updateFromVariable, consExps); - for (int i = 1; i < symbol.getSignature().length; i++) { - Type tc = symbol.getSignature()[i]; - if (tc == DataConstraintModel.typeList) { - Expression e = t.getChildren().get(i - 1); - Type newType = getExpTypeIfUpdatable(condType, e); - if (newType != null) { - condType = newType; - for (Expression e2 : consExps) { - if (e2 instanceof Variable) { - ((Variable) e2).setType(newType); - updatedVars.put(System.identityHashCode(e2), e2); - } else if (e2 instanceof Term) { - ((Term) e2).setType(newType); - updatedVars.put(System.identityHashCode(e2), e2); - } - } - } else { - if (e instanceof Variable && compareTypes(((Variable) e).getType(), condType)) { - ((Variable) e).setType(condType); - updatedVars.put(System.identityHashCode(e), e); - } else if (e instanceof Term && compareTypes(((Term) e).getType(), condType)) { - ((Term) e).setType(condType); - updatedVars.put(System.identityHashCode(e), e); - } - } - consExps.add(e); - expToVariable.put(System.identityHashCode(e), consExps); - } - } - variables.put(System.identityHashCode(consExps), condType); - } - } - } - for (Channel childCh: ch.getChildren()) { - extractForChannel(childCh); - } - } - }; - extractConstraintsOnExpressionsInTerm.extractForChannel(ch); - - // 1.5 Extract constraints on path parameters and resources. - IExtractConstraintsOnPathParametersAndResources extractConstraintsOnPathParametersAndResources = new IExtractConstraintsOnPathParametersAndResources() { - public void extractForChannel(Channel ch) { - for (ChannelMember cm : ch.getChannelMembers()) { - ResourcePath rPath = cm.getResource(); - while (rPath != null) { - Expression param = rPath.getLastParam(); - if (param != null) { - ResourceHierarchy parent = rPath.getResourceHierarchy().getParent(); - if (parent != null) { - List pathParams = resourcePathParams.get(parent); - if (pathParams == null) { - pathParams = new ArrayList<>(); - resourcePathParams.put(parent, pathParams); - } - pathParams.add(param); - expToPathParams.put(System.identityHashCode(param), pathParams); - Type parentType = parent.getResourceStateType(); - Type paramType = null; - if (param instanceof Variable) { - paramType = ((Variable) param).getType(); - } else if (param instanceof Term) { - paramType = ((Term) param).getType(); - } - if (paramType != null && parentType == null) { - if (paramType.equals(DataConstraintModel.typeString)) { - parentType = DataConstraintModel.typeMap; - } else if (paramType.equals(DataConstraintModel.typeInt)) { - parentType = DataConstraintModel.typeList; - } - if (parentType != null) { - parent.setResourceStateType(parentType); - updateFromResourceOwnership.add(parent); - } - } - } - } - rPath = rPath.getParent(); - } - } - for (Channel childCh: ch.getChildren()) { - extractForChannel(childCh); - } - } - }; - extractConstraintsOnPathParametersAndResources.extractForChannel(ch); - } - - // 1.6 Extract constraints on resource hierarchies. - for (ResourceHierarchy res: model.getResourceHierarchies()) { - if (res.getResourceStateType() != null) { - updateFromResourceOwnership.add(res); - } - } - - // 2. Propagate type information. - while (updateFromResource.size() > 0 || updateFromVariable.size() > 0 || updateFromMessage.size() > 0 - || updateFromConsOrSet.size() > 0 || updateFromTuple.size() > 0 || updateFromPair.size() > 0 - || updateFromMap.size() > 0 || updateFromJson.size() > 0 || updateFromResourceOwnership.size() > 0) { - if (updateFromResource.size() > 0) { - Set resourceKeys = updateFromResource.keySet(); - Integer resourceKey = resourceKeys.iterator().next(); - Map resourceValue = updateFromResource.get(resourceKey); - updateFromResource.remove(resourceKey); - for (int i : resourceValue.keySet()) { - Expression resExp = resourceValue.get(i); - updateVaribleTypes(resExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(resExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(resExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(resExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(resExp, pair, expToPair, updateFromPair); - updateMapTypes(resExp, map, expToMap, updateFromMap); - updateJsonTypes(resExp, json, expToJson, updateFromJson); - updateResourcePathParamsTypes(resExp, resourcePathParams, updateFromResourceOwnership); - } - } - if (updateFromVariable.size() > 0) { - Set variableKeys = updateFromVariable.keySet(); - Integer variableKey = variableKeys.iterator().next(); - Map variableValue = updateFromVariable.get(variableKey); - updateFromVariable.remove(variableKey); - for (int i : variableValue.keySet()) { - Expression var = variableValue.get(i); - updateResourceTypes(var, resources, expToResource, updateFromResource, updateFromResourceOwnership); - updateVaribleTypes(var, variables, expToVariable, updateFromVariable); - updateMessageTypes(var, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(var, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(var, tuple, expToTuple, updateFromTuple); - updatePairTypes(var, pair, expToPair, updateFromPair); - updateMapTypes(var, map, expToMap, updateFromMap); - updateJsonTypes(var, json, expToJson, updateFromJson); - updateResourcePathParamsTypes(var, resourcePathParams, updateFromResourceOwnership); - } - } - if (updateFromMessage.size() > 0) { - Set messageKeys = updateFromMessage.keySet(); - Integer messageKey = messageKeys.iterator().next(); - Map messageValue = updateFromMessage.get(messageKey); - updateFromMessage.remove(messageKey); - for (int i : messageValue.keySet()) { - Expression mesExp = messageValue.get(i); - updateResourceTypes(mesExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); - updateVaribleTypes(mesExp, variables, expToVariable, updateFromVariable); - updateConsOrSetTypes(mesExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(mesExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(mesExp, pair, expToPair, updateFromPair); - updateMapTypes(mesExp, map, expToMap, updateFromMap); - updateJsonTypes(mesExp, json, expToJson, updateFromJson); - updateResourcePathParamsTypes(mesExp, resourcePathParams, updateFromResourceOwnership); - } - } - if (updateFromConsOrSet.size() > 0) { - Set consKeys = updateFromConsOrSet.keySet(); - Integer consKey = consKeys.iterator().next(); - Map consValue = updateFromConsOrSet.get(consKey); - updateFromConsOrSet.remove(consKey); - for (int i : consValue.keySet()) { - Expression consExp = consValue.get(i); - updateResourceTypes(consExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); - updateVaribleTypes(consExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(consExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(consExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(consExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(consExp, pair, expToPair, updateFromPair); - updateMapTypes(consExp, map, expToMap, updateFromMap); - updateJsonTypes(consExp, json, expToJson, updateFromJson); - } - } - if (updateFromTuple.size() > 0) { - Set tupleKeys = updateFromTuple.keySet(); - Integer tupleKey = tupleKeys.iterator().next(); - Map tupleValue = updateFromTuple.get(tupleKey); - updateFromTuple.remove(tupleKey); - for (int i : tupleValue.keySet()) { - Expression tupleExp = tupleValue.get(i); - updateResourceTypes(tupleExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); - updateVaribleTypes(tupleExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(tupleExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(tupleExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(tupleExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(tupleExp, pair, expToPair, updateFromPair); - updateMapTypes(tupleExp, map, expToMap, updateFromMap); - updateJsonTypes(tupleExp, json, expToJson, updateFromJson); - } - } - if (updateFromPair.size() > 0) { - Set pairKeys = updateFromPair.keySet(); - Integer pairKey = pairKeys.iterator().next(); - Map pairValue = updateFromPair.get(pairKey); - updateFromPair.remove(pairKey); - for (int i : pairValue.keySet()) { - Expression pairExp = pairValue.get(i); - updateResourceTypes(pairExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); - updateVaribleTypes(pairExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(pairExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(pairExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(pairExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(pairExp, pair, expToPair, updateFromPair); - updateMapTypes(pairExp, map, expToMap, updateFromMap); - updateJsonTypes(pairExp, json, expToJson, updateFromJson); - } - } - if (updateFromMap.size() > 0) { - Set mapKeys = updateFromMap.keySet(); - Integer mapKey = mapKeys.iterator().next(); - Map mapValue = updateFromMap.get(mapKey); - updateFromMap.remove(mapKey); - for (int i : mapValue.keySet()) { - Expression mapExp = mapValue.get(i); - updateResourceTypes(mapExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); - updateVaribleTypes(mapExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(mapExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(mapExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(mapExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(mapExp, pair, expToPair, updateFromPair); - updateMapTypes(mapExp, map, expToMap, updateFromMap); - updateJsonTypes(mapExp, json, expToJson, updateFromJson); - } - } - if (updateFromJson.size() > 0) { - Set jsonKeys = updateFromJson.keySet(); - Integer jsonKey = jsonKeys.iterator().next(); - Map jsonValue = updateFromJson.get(jsonKey); - updateFromJson.remove(jsonKey); - for (int i : jsonValue.keySet()) { - Expression jsonExp = jsonValue.get(i); - updateResourceTypes(jsonExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); - updateVaribleTypes(jsonExp, variables, expToVariable, updateFromVariable); - updateMessageTypes(jsonExp, messages, expToMessage, updateFromMessage); - updateConsOrSetTypes(jsonExp, consOrSet, expToConsOrSet, updateFromConsOrSet); - updateTupleTypes(jsonExp, tuple, expToTuple, updateFromTuple); - updatePairTypes(jsonExp, pair, expToPair, updateFromPair); - updateMapTypes(jsonExp, map, expToMap, updateFromMap); - updateJsonTypes(jsonExp, json, expToJson, updateFromJson); - } - } - if (updateFromResourceOwnership.size() > 0) { - ResourceHierarchy res = updateFromResourceOwnership.iterator().next(); - updateFromResourceOwnership.remove(res); - updateResourceOwnershipTypes(res, resources, expToResource, updateFromResource, updateFromResourceOwnership); - } - } - } - - private static void updateExpressionBelonging(Map>> belonging, Expression exp, List group) { - Set> groups = belonging.get(System.identityHashCode(exp)); - if (groups == null) { - groups = new HashSet<>(); - belonging.put(System.identityHashCode(exp), groups); - groups.add(group); - return; - } - if (!groups.contains(group)) { - groups.add(group); - } - } - - private static void updateResourceTypes(Expression exp, Map> resources, Map> expToResource, - Map> updateFromResource, Set updateFromResourceOwnership) { - List identicalResources = expToResource.get(System.identityHashCode(exp)); - if (identicalResources == null) return; - for (ResourceHierarchy res: resources.keySet()) { - if (resources.get(res) == identicalResources) { - Type resType = res.getResourceStateType(); - Type newResType = getExpTypeIfUpdatable(resType, exp); - if (newResType != null) { - res.setResourceStateType(newResType); - updateFromResourceOwnership.add(res); // To update parent and children resources - // Update identical resources - Map updateExps = getUpdateSet(updateFromResource, identicalResources); - for (Expression resExp : identicalResources) { - if (resExp != exp) { - if (resExp instanceof Variable) { - ((Variable) resExp).setType(newResType); - updateExps.put(System.identityHashCode(resExp), resExp); - } else if (resExp instanceof Term) { - ((Term) resExp).setType(newResType); - updateExps.put(System.identityHashCode(resExp), resExp); - } - } - } - } - } - } - } - - private static void updateResourcePathParamsTypes(Expression exp, Map> resourcePathParams, Set updateFromResourceOwnership) { - for (ResourceHierarchy parent: resourcePathParams.keySet()) { - List pathParams = resourcePathParams.get(parent); - if (pathParams.contains(exp)) { - Type parentType = parent.getResourceStateType(); - Type paramType = null; - if (exp instanceof Variable) { - paramType = ((Variable) exp).getType(); - } else if (exp instanceof Term) { - paramType = ((Term) exp).getType(); - } - if (paramType != null && parentType == null) { - if (paramType.equals(DataConstraintModel.typeString)) { - parentType = DataConstraintModel.typeMap; - } else if (paramType.equals(DataConstraintModel.typeInt)) { - parentType = DataConstraintModel.typeList; - } - if (parentType != null) { - parent.setResourceStateType(parentType); - updateFromResourceOwnership.add(parent); - } - } - } - } - } - - private static void updateResourceOwnershipTypes(ResourceHierarchy res, Map> resources, - Map> expToResource, Map> updateFromResource, Set updateFromResourceOwnership) { - for (ResourceHierarchy parent: resources.keySet()) { - Type resType = res.getResourceStateType(); - Set children = parent.getChildren(); - if (res.equals(parent)) { - // Propagate an update of a parent resource type to its children' types. - if (DataConstraintModel.typeList.isAncestorOf(resType)) { - Type newElementType = listComponentTypes.get(resType); - if (newElementType != null && children != null && children.size() == 1) { - ResourceHierarchy element = children.iterator().next(); - Type elementType = element.getResourceStateType(); - if (compareTypes(elementType, newElementType)) { - element.setResourceStateType(newElementType); - updateFromResourceOwnership.add(element); - } - } - } else if (DataConstraintModel.typeMap.isAncestorOf(resType)) { - List newComponentTypes = mapComponentTypes.get(resType); - if (newComponentTypes != null && newComponentTypes.size() == 2 && children != null && children.size() == 1) { - ResourceHierarchy value = children.iterator().next(); - Type valueType = value.getResourceStateType(); - if (compareTypes(valueType, newComponentTypes.get(1))) { - value.setResourceStateType(newComponentTypes.get(1)); - updateFromResourceOwnership.add(value); - } - } - } else if (DataConstraintModel.typeJson.isAncestorOf(resType)) { - Map newMemberTypes = jsonMemberTypes.get(resType); - if (newMemberTypes != null && newMemberTypes.size() > 0 && children != null && children.size() > 0) { - for (ResourceHierarchy chlid: children) { - String key = chlid.getResourceName(); - Type memberType = chlid.getResourceStateType(); - if (compareTypes(memberType, newMemberTypes.get(key))) { - chlid.setResourceStateType(newMemberTypes.get(key)); - updateFromResourceOwnership.add(chlid); - } - } - } - } - } - if (children.contains(res)) { - // Propagate an update of a child resource type to its parent's type. - Type parentType = parent.getResourceStateType(); - if (parentType != null && DataConstraintModel.typeList.isAncestorOf(parentType)) { - Type oldElementType = listComponentTypes.get(parentType); - if (compareTypes(oldElementType, resType)) { - Type newListType = listTypes.get(resType); - if (newListType == null) { - newListType = createNewListType(resType, parentType); - } - if (newListType != null) { - parent.setResourceStateType(newListType); - updateFromResourceOwnership.add(parent); - } - } - } else if (parentType != null && DataConstraintModel.typeMap.isAncestorOf(parentType)) { - List oldComponentTypes = mapComponentTypes.get(parentType); - if (compareTypes(oldComponentTypes.get(1), resType)) { - List newComponentTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, resType}); - Type newMapType = mapTypes.get(newComponentTypes); - if (newMapType == null) { - newMapType = createNewMapType(newComponentTypes, parentType); - } - if (newMapType != null) { - parent.setResourceStateType(newMapType); - updateFromResourceOwnership.add(parent); - } - } - } else if (parentType != null && DataConstraintModel.typeJson.isAncestorOf(parentType)) { - Map oldMemberTypes = jsonMemberTypes.get(parentType); - String key= res.getResourceName(); - if (oldMemberTypes == null || compareTypes(oldMemberTypes.get(key), resType)) { - Map newMemberTypes = new HashMap<>(); - if (oldMemberTypes != null) newMemberTypes.putAll(oldMemberTypes); - newMemberTypes.put(key, resType); - Type newJsonType = jsonTypes.get(newMemberTypes); - if (newJsonType == null) { - newJsonType = createNewJsonType(newMemberTypes, parentType); - } - if (newJsonType != null) { - parent.setResourceStateType(newJsonType); - updateFromResourceOwnership.add(parent); - } - } - } - } - } - // Propagate an update of the resource to its expressions. - List identicalResources = resources.get(res); - if (identicalResources != null) { - Type newResType = res.getResourceStateType(); - for (Expression resExp: identicalResources) { - Type resType = null; - if (resExp instanceof Variable) { - resType = ((Variable) resExp).getType(); - } else if (resExp instanceof Term) { - resType = ((Term) resExp).getType(); - } - if (resType == null || compareTypes(resType, newResType)) { - Map updateExps = getUpdateSet(updateFromResource, identicalResources); - if (resExp instanceof Variable) { - ((Variable) resExp).setType(newResType); - updateExps.put(System.identityHashCode(resExp), resExp); - } else if (resExp instanceof Term) { - ((Term) resExp).setType(newResType); - updateExps.put(System.identityHashCode(resExp), resExp); - } - } - } - } - } - - private static void updateVaribleTypes(Expression exp, Map variables, - Map> expToVariable, Map> updateFromVariable) { - List sameVariable = expToVariable.get(System.identityHashCode(exp)); - if (sameVariable == null) return; - Type varType = variables.get(System.identityHashCode(sameVariable)); - Type newVarType = getExpTypeIfUpdatable(varType, exp); - if (newVarType != null) { - variables.put(System.identityHashCode(sameVariable), newVarType); - Map updateVars = getUpdateSet(updateFromVariable, sameVariable); - for (Expression v : sameVariable) { - if (v != exp) { - if (v instanceof Variable) { - ((Variable) v).setType(newVarType); - updateVars.put(System.identityHashCode(v), v); - } else if (v instanceof Term) { - ((Term) v).setType(newVarType); - updateVars.put(System.identityHashCode(v), v); - } - } - } - } 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); - } - } - } - } - } - - private static void updateMessageTypes(Expression exp, - Map, Type>>> messages, - Map> expToMessage, Map> updateFromMessage) { - List messageExps = expToMessage.get(System.identityHashCode(exp)); - if (messageExps == null) return; - Type msgType = null; - Map.Entry, Type> expsAndType = null; - for (Channel c : messages.keySet()) { - for (int i : messages.get(c).keySet()) { - expsAndType = messages.get(c).get(i); - if (expsAndType.getKey() == messageExps) { - msgType = expsAndType.getValue(); - break; - } - } - if (msgType != null) break; - } - if (msgType == null) return; - Type newMsgType = getExpTypeIfUpdatable(msgType, exp); - if (newMsgType != null) { - expsAndType.setValue(newMsgType); - Map updateExps = getUpdateSet(updateFromMessage, messageExps); - for (Expression e : messageExps) { - if (e != exp) { - if (e instanceof Variable) { - ((Variable) e).setType(newMsgType); - updateExps.put(System.identityHashCode(e), e); - } else if (e instanceof Term) { - ((Term) e).setType(newMsgType); - updateExps.put(System.identityHashCode(e), e); - } - } - } - } - } - - private static void updateConsOrSetTypes(Expression exp, Map consOrSet, - Map>> expToConsOrSet, Map> updateFromConsOrSet) { - Set> consComponentGroups = expToConsOrSet.get(System.identityHashCode(exp)); - if (consComponentGroups == null) return; - for (List consOrSetComponentGroup: consComponentGroups) { - int idx = consOrSetComponentGroup.indexOf(exp); - switch (idx) { - case 0: - // exp is a list itself. - if (!(exp instanceof Term)) break; - Type listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); - Type expType = getExpTypeIfUpdatable(listType, exp); - if (expType != null) { - consOrSet.put(System.identityHashCode(consOrSetComponentGroup), expType); - Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); - if (consOrSetComponentGroup.get(2) instanceof Variable) { - ((Variable) consOrSetComponentGroup.get(2)).setType(expType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); - } else if (consOrSetComponentGroup.get(2) instanceof Term) { - ((Term) consOrSetComponentGroup.get(2)).setType(expType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); - } - Type compType = listComponentTypes.get(expType); - if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Variable) { - ((Variable) consOrSetComponentGroup.get(1)).setType(compType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); - } else if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Term) { - ((Term) consOrSetComponentGroup.get(1)).setType(compType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); - } - } - break; - case 1: - // exp is a list's component. - listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); - Type compType = listComponentTypes.get(listType); - Type newCompType = getExpTypeIfUpdatable(compType, exp); - if (newCompType != null) { - Type newListType = listTypes.get(newCompType); - if (newListType == null) { - // Create new list type. - newListType = createNewListType(newCompType, listType); - } - consOrSet.put(System.identityHashCode(consOrSetComponentGroup), newListType); - Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); - if (consOrSetComponentGroup.get(0) instanceof Term) { - ((Term) consOrSetComponentGroup.get(0)).setType(newListType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(0)), consOrSetComponentGroup.get(0)); - } - if (consOrSetComponentGroup.get(2) instanceof Variable) { - ((Variable) consOrSetComponentGroup.get(2)).setType(newListType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); - } else if (consOrSetComponentGroup.get(2) instanceof Term) { - ((Term) consOrSetComponentGroup.get(2)).setType(newListType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); - } - } - break; - case 2: - // exp is a list itself. - listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); - expType = getExpTypeIfUpdatable(listType, exp); - if (expType != null) { - consOrSet.put(System.identityHashCode(consOrSetComponentGroup), expType); - Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); - if (consOrSetComponentGroup.get(0) instanceof Term) { - ((Term) consOrSetComponentGroup.get(0)).setType(expType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(0)), consOrSetComponentGroup.get(0)); - } - compType = listComponentTypes.get(expType); - if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Variable) { - ((Variable) consOrSetComponentGroup.get(1)).setType(compType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); - } else if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Term) { - ((Term) consOrSetComponentGroup.get(1)).setType(compType); - updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); - } - } - } - } - } - - private static void updateTupleTypes(Expression exp, Map tuple, - Map>> expToTuple, Map> updateFromTuple) { - Set> tupleComponentGroups = expToTuple.get(System.identityHashCode(exp)); - if (tupleComponentGroups == null) return; - for (List tupleComponentGroup: tupleComponentGroups) { - int idx = tupleComponentGroup.indexOf(exp); - if (idx == 0) { - // exp is a tuple itself. - Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); - Type newTupleType = getExpTypeIfUpdatable(tupleType, exp); - if (newTupleType != null) { - // Propagate an update of a tuple's type to its components' types. - tuple.put(System.identityHashCode(tupleComponentGroup), newTupleType); - List componentTypes = tupleComponentTypes.get(newTupleType); - Map updateExps = getUpdateSet(updateFromTuple, tupleComponentGroup); - for (int i = 1; i < tupleComponentGroup.size(); i++) { - Expression compExp = tupleComponentGroup.get(i); - if (compExp instanceof Variable) { - 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) { - 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); - } - } - } - } - } - } - } else { - // exp is a tuple's component. - Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); - List componentTypes = tupleComponentTypes.get(tupleType); - 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. - Type newTupleType = tupleTypes.get(componentTypes); - if (newTupleType == null) { - // Create new tuple type; - newTupleType = createNewTupleType(componentTypes, tupleType); - } - Map updateExps = getUpdateSet(updateFromTuple, tupleComponentGroup); - Expression tupleExp = tupleComponentGroup.get(0); - if (tupleExp instanceof Variable) { - ((Variable) tupleExp).setType(newTupleType); - updateExps.put(System.identityHashCode(tupleExp), tupleExp); - } else if (tupleExp instanceof Term) { - ((Term) tupleExp).setType(newTupleType); - updateExps.put(System.identityHashCode(tupleExp), tupleExp); - } - tuple.put(System.identityHashCode(tupleComponentGroup), newTupleType); - } - } - } - } - - private static void updatePairTypes(Expression exp, Map pair, - Map>> expToPair, Map> updateFromPair) { - Set> pairComponentGroups = expToPair.get(System.identityHashCode(exp)); - if (pairComponentGroups == null) return; - for (List pairComponentGroup: pairComponentGroups) { - int idx = pairComponentGroup.indexOf(exp); - if (idx == 0) { - // exp is a pair itself. - Type pairType = pair.get(System.identityHashCode(pairComponentGroup)); - Type newPairType = getExpTypeIfUpdatable(pairType, exp); - if (newPairType != null) { - // Propagate an update of a pair's type to its components' types. - pair.put(System.identityHashCode(pairComponentGroup), newPairType); - Type componentType = pairComponentTypes.get(newPairType); - Map updateExps = getUpdateSet(updateFromPair, pairComponentGroup); - for (int i = 1; i < pairComponentGroup.size(); i++) { - Expression compExp = pairComponentGroup.get(i); - if (compExp instanceof Variable) { - if (compareTypes(((Variable) compExp).getType(), componentType)) { - ((Variable) compExp).setType(componentType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else if (compExp instanceof Term) { - if (compareTypes(((Term) compExp).getType(), componentType)) { - ((Term) compExp).setType(componentType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } - } - } - } else { - // exp is a pair's component. - Type pairType = pair.get(System.identityHashCode(pairComponentGroup)); - Type compType = pairComponentTypes.get(pairType); - Type newCompType = getExpTypeIfUpdatable(compType, exp); - if (newCompType != null) { - // Propagate an update of a component's type to its container's (pair's) type. - Type newPairType = pairTypes.get(compType); - if (newPairType != null) { - Map updateExps = getUpdateSet(updateFromPair, pairComponentGroup); - Expression pairExp = pairComponentGroup.get(0); - if (pairExp instanceof Variable) { - ((Variable) pairExp).setType(newPairType); - updateExps.put(System.identityHashCode(pairExp), pairExp); - } else if (pairExp instanceof Term) { - ((Term) pairExp).setType(newPairType); - updateExps.put(System.identityHashCode(pairExp), pairExp); - } - pair.put(System.identityHashCode(pairComponentGroup), newPairType); - } - } - } - } - } - - private static void updateMapTypes(Expression exp, Map map, - Map>> expToMap, Map> updateFromMap) { - Set> mapComponentGroups = expToMap.get(System.identityHashCode(exp)); - if (mapComponentGroups == null) return; - for (List mapComponentGroup: mapComponentGroups) { - int idx = mapComponentGroup.indexOf(exp); - if (idx == 0 || idx == 3) { - // exp is a map itself. - Type mapType = map.get(System.identityHashCode(mapComponentGroup)); - Type newMapType = getExpTypeIfUpdatable(mapType, exp); - if (newMapType != null) { - // Propagate an update of a map's type to its components' types. - map.put(System.identityHashCode(mapComponentGroup), newMapType); - List componentTypes = mapComponentTypes.get(newMapType); - Map updateExps = getUpdateSet(updateFromMap, mapComponentGroup); - for (int i = 1; i < mapComponentGroup.size() && i < 3; i++) { - Expression compExp = mapComponentGroup.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); - } - } 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); - } - } - } - // Propagate an update of a map's type to another map's type. - Expression compExp = null; - if (idx == 0 && mapComponentGroup.size() == 4) { // for insert - compExp = mapComponentGroup.get(3); - } else if (idx == 3) { - compExp = mapComponentGroup.get(0); - } - if (compExp != null) { - if (compExp instanceof Variable) { - if (compareTypes(((Variable) compExp).getType(), newMapType)) { - ((Variable) compExp).setType(newMapType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } else if (compExp instanceof Term) { - if (compareTypes(((Term) compExp).getType(), newMapType)) { - ((Term) compExp).setType(newMapType); - updateExps.put(System.identityHashCode(compExp), compExp); - } - } - } - } - } else { - // exp is a map's key or value. - Type mapType = map.get(System.identityHashCode(mapComponentGroup)); - List componentTypes = mapComponentTypes.get(mapType); - Type compType = componentTypes.get(idx - 1); - Type newCompType = getExpTypeIfUpdatable(compType, exp); - if (newCompType != null) { - // Propagate an update of a component's type to its container's (map's) type. - componentTypes = new ArrayList<>(componentTypes); - componentTypes.set(idx - 1, newCompType); - Type newMapType = mapTypes.get(componentTypes); - if (newMapType == null) { - // Create new map type; - newMapType = createNewMapType(componentTypes, mapType); - } - Map updateExps = getUpdateSet(updateFromMap, mapComponentGroup); - Expression mapExp = mapComponentGroup.get(0); - if (mapExp instanceof Variable) { - ((Variable) mapExp).setType(newMapType); - updateExps.put(System.identityHashCode(mapExp), mapExp); - } else if (mapExp instanceof Term) { - ((Term) mapExp).setType(newMapType); - updateExps.put(System.identityHashCode(mapExp), mapExp); - } - if (mapComponentGroup.size() == 4) { // for insert - mapExp = mapComponentGroup.get(3); - if (mapExp instanceof Variable) { - ((Variable) mapExp).setType(newMapType); - updateExps.put(System.identityHashCode(mapExp), mapExp); - } else if (mapExp instanceof Term) { - ((Term) mapExp).setType(newMapType); - updateExps.put(System.identityHashCode(mapExp), mapExp); - } - } - map.put(System.identityHashCode(mapComponentGroup), newMapType); - } - } - } - } - - - private static void updateJsonTypes(Expression exp, Map json, - Map>> expToJson, Map> updateFromJson) { - Set> jsonMemberGroups = expToJson.get(System.identityHashCode(exp)); - if (jsonMemberGroups == null) return; - for (List jsonMemberGroup: jsonMemberGroups) { - int idx = jsonMemberGroup.indexOf(exp); - if (idx == 3) { - // exp is a json argument (0:t = addMember(3:json, 1:key, 2:value)). - Type jsonType = json.get(System.identityHashCode(jsonMemberGroup)); - if (jsonType != null && jsonMemberTypes.get(jsonType) != null) { - Map memberTypes = new HashMap<>(jsonMemberTypes.get(jsonType)); - Map argMemberTypes = new HashMap<>(memberTypes); - String keyName = null; - Type valueType = null; - if (jsonMemberGroup.get(1) instanceof Constant) { - keyName = ((Constant) jsonMemberGroup.get(1)).getSymbol().getName(); - valueType = ((Constant) jsonMemberGroup.get(1)).getType(); - argMemberTypes.remove(keyName); - } - Type jsonArgType = jsonTypes.get(argMemberTypes); - Type newJsonArgType = getExpTypeIfUpdatable(jsonArgType, exp); - if (newJsonArgType != null && keyName != null) { - // Propagate an update of a json arg's type to its container's (json's) type. - argMemberTypes = ((JsonType) newJsonArgType).getMemberTypes(); - argMemberTypes.put(keyName, valueType); - memberTypes.putAll(argMemberTypes); - Type newJsonType = jsonTypes.get(memberTypes); - if (newJsonType == null) { - // Create new json type. - newJsonType = createNewJsonType(memberTypes, jsonType); - } - // Update the type of the json term and record the updated expression. - Map updateExps = getUpdateSet(updateFromJson, jsonMemberGroup); - Expression jsonExp = jsonMemberGroup.get(0); - if (jsonExp instanceof Variable) { - ((Variable) jsonExp).setType(newJsonType); - updateExps.put(System.identityHashCode(jsonExp), jsonExp); - } else if (jsonExp instanceof Term) { - ((Term) jsonExp).setType(newJsonType); - updateExps.put(System.identityHashCode(jsonExp), jsonExp); - } - json.put(System.identityHashCode(jsonMemberGroup), newJsonType); - } - } - } else if (idx == 2) { - // exp is a value (0:t = addMember(3:json, 1:key, 2:value) or 2:value = dot(0:list/map, 1:key)). - Type jsonType = json.get(System.identityHashCode(jsonMemberGroup)); - Type newJsonType = null; - if (exp instanceof Term && ((Term) exp).getSymbol().equals(DataConstraintModel.dotParam)) { - if (DataConstraintModel.typeList.isAncestorOf(jsonType)) { - Type elementType = listComponentTypes.get(jsonType); - Type newElementType = getExpTypeIfUpdatable(elementType, exp); - if (newElementType != null) { - // Propagate an update of a member's type to its container's (json's) type. - newJsonType = listTypes.get(newElementType); - if (newJsonType == null) { - // Create new json type. - newJsonType = createNewListType(newElementType, jsonType); - } - } - } else if (DataConstraintModel.typeMap.isAncestorOf(jsonType)) { - List keyValueTypes = mapComponentTypes.get(jsonType); - Type newValueType = getExpTypeIfUpdatable(keyValueTypes.get(1), exp); - if (newValueType != null) { - // Propagate an update of a member's type to its container's (json's) type. - List newKeyValueTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, newValueType}); - newJsonType = mapTypes.get(newKeyValueTypes); - if (newJsonType == null) { - // Create new json type. - newJsonType = createNewMapType(newKeyValueTypes, jsonType); - } - } - } - } else { - Map memberTypes = jsonMemberTypes.get(jsonType); - String keyName = null; - if (jsonMemberGroup.get(1) instanceof Constant) { - keyName = ((Constant) jsonMemberGroup.get(1)).getSymbol().getName(); - } - if (memberTypes != null) { - Type memberType = memberTypes.get(keyName); - Type newMemberType = getExpTypeIfUpdatable(memberType, exp); - if (newMemberType != null && keyName != null) { - // Propagate an update of a member's type to its container's (json's) type. - Map newMemberTypes = new HashMap<>(memberTypes); - newMemberTypes.put(keyName, newMemberType); - newJsonType = jsonTypes.get(newMemberTypes); - if (newJsonType == null) { - // Create new json type. - newJsonType = createNewJsonType(newMemberTypes, jsonType); - } - } - } - } - if (newJsonType != null) { - // Update the type of the json term and record the updated expression. - Map updateExps = getUpdateSet(updateFromJson, jsonMemberGroup); - Expression jsonExp = jsonMemberGroup.get(0); - if (jsonExp instanceof Variable) { - ((Variable) jsonExp).setType(newJsonType); - updateExps.put(System.identityHashCode(jsonExp), jsonExp); - } else if (jsonExp instanceof Term) { - ((Term) jsonExp).setType(newJsonType); - updateExps.put(System.identityHashCode(jsonExp), jsonExp); - } - json.put(System.identityHashCode(jsonMemberGroup), newJsonType); - } - } - } - } - - private static Type createNewListType(Type compType, Type parentType) { - String compTypeName = getInterfaceTypeName(compType); - List childrenTypes = getChildrenTypes(parentType, listComponentTypes.keySet()); - Type newListType = new Type("List", "ArrayList<>", "List<" + compTypeName + ">", parentType); - listTypes.put(compType, newListType); - listComponentTypes.put(newListType, compType); - for (Type childType : childrenTypes) { - if (compareTypes(childType, newListType)) { - if (newListType.getParentTypes().contains(parentType)) { - newListType.replaceParentType(parentType, childType); - } else { - newListType.addParentType(childType); - } - } else if (compareTypes(newListType, childType)) { - childType.replaceParentType(parentType, newListType); - } - } - return newListType; - } - - private static Type createNewTupleType(List componentTypes, Type parentTupleType) { - String implTypeName = "AbstractMap.SimpleEntry<>"; - String interfaceTypeName = "Map.Entry<$x>"; - if (componentTypes.size() >= 2) { - implTypeName = implTypeName.replace("$x", getImplementationTypeName(componentTypes.get(0)) + "$x"); - interfaceTypeName = interfaceTypeName.replace("$x", getInterfaceTypeName(componentTypes.get(0)) + "$x"); - for (Type argType : componentTypes.subList(1, componentTypes.size() - 1)) { - implTypeName = implTypeName.replace("$x", - ", AbstractMap.SimpleEntry<" + getImplementationTypeName(argType) + "$x>"); - interfaceTypeName = interfaceTypeName.replace("$x", - ", Map.Entry<" + getInterfaceTypeName(argType) + "$x>"); - } - implTypeName = implTypeName.replace("$x", - ", " + getImplementationTypeName(componentTypes.get(componentTypes.size() - 1))); - interfaceTypeName = interfaceTypeName.replace("$x", - ", " + getInterfaceTypeName(componentTypes.get(componentTypes.size() - 1))); - } - List childrenTypes = getChildrenTypes(parentTupleType, tupleComponentTypes.keySet()); - Type newTupleType = new Type("Tuple", implTypeName, interfaceTypeName, parentTupleType); - tupleTypes.put(componentTypes, newTupleType); - tupleComponentTypes.put(newTupleType, componentTypes); - for (Type childType : childrenTypes) { - if (compareTypes(childType, newTupleType)) { - if (newTupleType.getParentTypes().contains(parentTupleType)) { - newTupleType.replaceParentType(parentTupleType, childType); - } else { - newTupleType.addParentType(childType); - } - } else if (compareTypes(newTupleType, childType)) { - childType.replaceParentType(parentTupleType, newTupleType); - } - } - return newTupleType; - } - - private static Type createNewMapType(List componentTypes, Type parentMapType) { - String implTypeName = "HashMap<>"; - String interfaceTypeName = "Map<$x, $y>"; - if (componentTypes.size() == 2) { - implTypeName = implTypeName.replace("$x", getImplementationTypeName(componentTypes.get(0))); - interfaceTypeName = interfaceTypeName.replace("$x", getInterfaceTypeName(componentTypes.get(0))); - implTypeName = implTypeName.replace("$y", getImplementationTypeName(componentTypes.get(1))); - interfaceTypeName = interfaceTypeName.replace("$y", getInterfaceTypeName(componentTypes.get(1))); - } - List childrenTypes = getChildrenTypes(parentMapType, mapComponentTypes.keySet()); - Type newMapType = new Type("Map", implTypeName, interfaceTypeName, parentMapType); - mapTypes.put(componentTypes, newMapType); - mapComponentTypes.put(newMapType, componentTypes); - for (Type childType : childrenTypes) { - if (compareTypes(childType, newMapType)) { - if (newMapType.getParentTypes().contains(parentMapType)) { - newMapType.replaceParentType(parentMapType, childType); - } else { - newMapType.addParentType(childType); - } - } else if (compareTypes(newMapType, childType)) { - childType.replaceParentType(parentMapType, newMapType); - } - } - return newMapType; - } - - private static JsonType createNewJsonType(Map memberTypes, Type parentJsonType) { - String implTypeName = "HashMap<>"; - String interfaceTypeName = "Map"; - List childrenTypes = getChildrenTypes(parentJsonType, jsonMemberTypes.keySet()); - JsonType newJsonType = new JsonType("Json", implTypeName, interfaceTypeName, parentJsonType); - for (String key: memberTypes.keySet()) { - newJsonType.addMemberType(key, memberTypes.get(key)); - } - jsonTypes.put(memberTypes, newJsonType); - jsonMemberTypes.put(newJsonType, memberTypes); - for (Type childType : childrenTypes) { - if (compareTypes(childType, newJsonType)) { - if (newJsonType.getParentTypes().contains(parentJsonType)) { - newJsonType.replaceParentType(parentJsonType, childType); - } else { - newJsonType.addParentType(childType); - } - } else if (compareTypes(newJsonType, childType)) { - childType.replaceParentType(parentJsonType, newJsonType); - } - } - return newJsonType; - } - - /** - * Get children types of a given type from given set of types. - * @param parentType a type - * @param allTypes set of types - * @return list of the children types - */ - private static List getChildrenTypes(Type parentType, Set allTypes) { - List childrenTypes = new ArrayList<>(); - for (Type childType : allTypes) { - if (childType.getParentTypes().contains(parentType)) { - childrenTypes.add(childType); - } - } - return childrenTypes; - } - - private static String getImplementationTypeName(Type type) { - if (type == null) - return "Object"; - String wrapperType = DataConstraintModel.getWrapperType(type); - if (wrapperType != null) - return wrapperType; - return type.getImplementationTypeName(); - } - - private static String getInterfaceTypeName(Type type) { - if (type == null) - return "Object"; - String wrapperType = DataConstraintModel.getWrapperType(type); - if (wrapperType != null) - return wrapperType; - return type.getInterfaceTypeName(); - } - - private static > Map getUpdateSet(Map> updateSets, U keySet) { - Map updatedExps = updateSets.get(System.identityHashCode(keySet)); - if (updatedExps == null) { - updatedExps = new HashMap<>(); - updateSets.put(System.identityHashCode(keySet), updatedExps); - } - return updatedExps; - } - - private static Type getExpTypeIfUpdatable(Type originalType, Expression newExp) { - Type expType = null; - if (newExp instanceof Term) { - expType = ((Term) newExp).getType(); - } else if (newExp instanceof Variable) { - expType = ((Variable) newExp).getType(); - } - if (compareTypes(originalType, expType)) { - return expType; - } - return null; - } - - /** - * Is an given original type an ancestor of a given new type? - * - * @param originalType original type - * @param newType new type (may not have been registered) - * @return true: if the original type equals to the new type or is an ancestor - * of the new type, false: otherwise - */ - private static boolean compareTypes(Type originalType, Type newType) { - if (originalType == null) return true; - if (originalType != newType && newType != null) { - 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; - 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; - } - return true; - } - if (DataConstraintModel.typeTuple.isAncestorOf(originalType) - && DataConstraintModel.typeTuple.isAncestorOf(newType)) { - List originalCompTypes = tupleComponentTypes.get(originalType); - List newCompTypes = tupleComponentTypes.get(newType); - 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) { - if (DataConstraintModel.typeTuple.isAncestorOf(originalCompTypes.get(i))) { - // Unfold the nested tuple's types. - 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))) { - // Unfold the nested tuple's types. - 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; - } - if (DataConstraintModel.typeList.isAncestorOf(originalType) - && DataConstraintModel.typeList.isAncestorOf(newType)) { - Type originalCompType = listComponentTypes.get(originalType); - Type newCompType = listComponentTypes.get(newType); - if (originalCompType != null && (newCompType == null || !originalCompType.isAncestorOf(newCompType))) return false; - return true; - } - if (DataConstraintModel.typeJson.isAncestorOf(originalType) && DataConstraintModel.typeJson.isAncestorOf(newType)) { - Map originalMemberTypes = jsonMemberTypes.get(originalType); - Map newMemberTypes = jsonMemberTypes.get(newType); - if (originalMemberTypes == null) return true; - if (originalMemberTypes.keySet().size() < newMemberTypes.keySet().size() - && newMemberTypes.keySet().containsAll(originalMemberTypes.keySet())) return true; - if (originalMemberTypes.keySet().size() > newMemberTypes.keySet().size()) return false; - if (!newMemberTypes.keySet().containsAll(originalMemberTypes.keySet())) return false; - for (String key: originalMemberTypes.keySet()) { - if (!originalMemberTypes.get(key).isAncestorOf(newMemberTypes.get(key))) return false; - } - return true; - } - } - return false; - } - - private static interface IGroupExpressionsByResource { - public void groupForChannel(Channel ch); - } - - private static interface IGroupExpressionsByVariable { - public void groupForChannel(Channel ch); - } - - private static interface IGroupExpressionsByMessage { - public void groupForChannel(Channel rootCh, Channel ch); - } - - private static interface IExtractConstraintsOnExpressionsInTerm { - public void extractForChannel(Channel ch); - } - - private static interface IExtractConstraintsOnPathParametersAndResources { - public void extractForChannel(Channel ch); - } -} diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java index 846c273..62320f9 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java @@ -15,12 +15,11 @@ import code.ast.*; import generators.CodeGeneratorFromDataFlowGraph; import generators.DataTransferMethodAnalyzer; -import generators.JavaCodeGenerator; -import generators.JavaMethodBodyGenerator; +import generators.ILanguageSpecific; import generators.JavaSpecific; import generators.StandaloneSpecific; +import generators.TypeInference; import models.dataConstraintModel.ResourceHierarchy; -import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.ModelExtension; import models.dataFlowModel.DataFlowGraph; @@ -41,9 +40,11 @@ public void actionPerformed(ActionEvent e) { DataFlowGraph graph = editor.getDataFlowGraph(); if (graph != null) { + ILanguageSpecific langSpec = new JavaSpecific(); DataTransferModel model = editor.getModel(); ModelExtension.extendModel(model); - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(langSpec); + typeInference.infer(model); DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); String fileName = editor.getCurFileName(); if (fileName == null) fileName = "Main"; @@ -55,13 +56,13 @@ exist = true; } } + CodeGeneratorFromDataFlowGraph codeGenerator = new CodeGeneratorFromDataFlowGraph(new StandaloneSpecific(), langSpec); if (!exist) { - JavaCodeGenerator.setMainTypeName(mainTypeName); // use model's file name as the main type's name. + codeGenerator.setMainTypeName(mainTypeName); // use model's file name as the main type's name. } else { - JavaCodeGenerator.resetMainTypeName(); // use the default main type's name. + codeGenerator.resetMainTypeName(); // use the default main type's name. } -// editor.setCodes(JavaMethodBodyGenerator.doGenerate(graph, model, JavaCodeGenerator.doGenerate(graph, model))); - editor.setCodes(new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new StandaloneSpecific(), new JavaSpecific())); + editor.setCodes(codeGenerator.generateCode(model, graph)); ModelExtension.recoverModel(model); for (CompilationUnit file : editor.getCodes()) { System.out.println(file); diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java index da1a3df..151028d 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java @@ -13,10 +13,10 @@ import code.ast.*; import generators.CodeGeneratorFromDataFlowGraph; import generators.DataTransferMethodAnalyzer; +import generators.ILanguageSpecific; import generators.JavaSpecific; -import generators.JerseyCodeGenerator; -import generators.JerseyMethodBodyGenerator; import generators.JerseySpecific; +import generators.TypeInference; import models.dataConstraintModel.ResourceHierarchy; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.ModelExtension; @@ -38,9 +38,11 @@ public void actionPerformed(ActionEvent e) { DataFlowGraph graph = editor.getDataFlowGraph(); if (graph != null) { + ILanguageSpecific langSpec = new JavaSpecific(); DataTransferModel model = editor.getModel(); ModelExtension.extendModel(model); - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(langSpec); + typeInference.infer(model); DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); String fileName = editor.getCurFileName(); if (fileName == null) fileName = "Main"; @@ -52,13 +54,14 @@ exist = true; } } + CodeGeneratorFromDataFlowGraph codeGenerator = new CodeGeneratorFromDataFlowGraph(new JerseySpecific(), langSpec); if (!exist) { - JerseyCodeGenerator.setMainTypeName(mainTypeName); // use model's file name as the main type's name. + codeGenerator.setMainTypeName(mainTypeName); // use model's file name as the main type's name. } else { - JerseyCodeGenerator.resetMainTypeName(); // use the default main type's name. + codeGenerator.resetMainTypeName(); // use the default main type's name. } // editor.setCodes(JerseyMethodBodyGenerator.doGenerate(graph, model, JerseyCodeGenerator.doGenerate(graph, model))); - editor.setCodes(new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new JerseySpecific(), new JavaSpecific())); + editor.setCodes(codeGenerator.generateCode(model, graph)); ModelExtension.recoverModel(model); for (CompilationUnit file : editor.getCodes()) { System.out.println(file); diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java index b1e32e7..632e16a 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/PushPullSelectionStage.java @@ -10,7 +10,11 @@ import com.mxgraph.swing.mxGraphComponent; import com.mxgraph.util.mxEventSource.mxIEventListener; import com.mxgraph.util.mxPoint; -import generators.JavaCodeGenerator; + +import generators.CodeGenerator; +import generators.CodeGeneratorFromDataFlowGraph; +import generators.JavaSpecific; +import generators.StandaloneSpecific; import models.Edge; import models.algebra.*; import models.dataConstraintModel.Channel; @@ -332,7 +336,7 @@ Set> resourceDependency = new HashSet<>(); if (!ch.getOutputChannelMembers().isEmpty()) { try { - Map>> dependency = ch.fillOutsideResourcePaths(ch.getOutputChannelMembers().iterator().next(), JavaCodeGenerator.pullAccessor); + Map>> dependency = ch.fillOutsideResourcePaths(ch.getOutputChannelMembers().iterator().next(), new CodeGeneratorFromDataFlowGraph(new StandaloneSpecific(), new JavaSpecific()).getPullAccessor(new StandaloneSpecific())); for (ChannelMember srcMem : dependency.keySet()) { ResourceNode srcNode = dataFlowGraph.getResourceNode(srcMem.getResource()); if (srcNode != null) { diff --git a/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java b/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java index 5470a65..3ba4fe5 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java +++ b/AlgebraicDataflowArchitectureModel/src/application/simulator/SimulatorWindow.java @@ -1,7 +1,9 @@ package application.simulator; -import algorithms.TypeInference; import application.editor.Editor; +import generators.JavaSpecific; +import generators.TypeInference; + import com.mxgraph.model.mxCell; import com.mxgraph.model.mxGeometry; import com.mxgraph.model.mxGraphModel; @@ -89,7 +91,8 @@ setVisible(true); DataTransferModel model = this.editor.getModel(); - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(new JavaSpecific()); + typeInference.infer(model); simulator = new Simulator(model); SimulationLayout layout = new SimulationLayout(simulator.getCurState()); layout.constructSimulateGraph(graph, simulator); diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java index 97ac135..a7a07d9 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java @@ -44,20 +44,20 @@ return strings; } - public void addFirstStatement(String code) { - if (code != null) { + public void addFirstStatement(String statement) { + if (statement != null) { this.addFirstStatement(new Statement() { @Override public String toString() { - return code; + return statement; } }); } } - public void addStatement(String code) { - if (code != null) { - this.addStatement(new PlainStatement(code)); + public void addStatement(String statement) { + if (statement != null) { + this.addStatement(new PlainStatement(statement)); } } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java b/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java index b541ce6..333388e 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java @@ -82,6 +82,9 @@ } public Block getBody() { + if (body == null) { + body = new Block(); + } return body; } @@ -89,6 +92,13 @@ this.body = body; } + public void addStatement(Statement statement) { + if (body == null) { + body = new Block(); + } + body.addStatement(statement); + } + public void addStatement(String statement) { if (body == null) { body = new Block(); @@ -96,6 +106,13 @@ body.addStatement(statement); } + public void addFirstStatement(Statement statement) { + if (body == null) { + body = new Block(); + } + body.addFirstStatement(statement); + } + public void addFirstStatement(String statement) { if (body == null) { body = new Block(); diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ParameterizedType.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ParameterizedType.java index dbb16e2..ca7d269 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/ParameterizedType.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ParameterizedType.java @@ -70,6 +70,23 @@ this.typeArguments = typeArguments; } + + /** + * Replace all type arguments and their descendant types that match the replacedType with the replacingType. + * @param replacedType the type to be replaced + * @param replacingType the type to replace with + */ + public void replaceSubTypes(Type replacedType, Type replacingType) { + for (int i = 0; i < typeArguments.size(); i++) { + Type typeArgment = typeArguments.get(i); + if (typeArgment.equals(replacedType)) { + typeArguments.set(i, replacingType); + } else if (typeArgment instanceof ParameterizedType) { + ((ParameterizedType) typeArgment).replaceSubTypes(replacedType, replacingType); + } + } + } + @Override public String toString() { if (typeArguments.isEmpty()) { diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java b/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java index b8d252e..3381022 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java @@ -10,24 +10,16 @@ * @author s-yamagiwa */ public class PrimitiveType extends AnnotatableType { - private models.algebra.Type type; + private String typeName; - public PrimitiveType(models.algebra.Type type) { - this.type = type; - } - - public models.algebra.Type getType() { - return type; - } - - public void setType(models.algebra.Type type) { - this.type = type; + public PrimitiveType(String typeName) { + this.typeName = typeName; } @Override public String toString() { if (getAnnotations().isEmpty()) { - return type.getTypeName(); + return typeName; } StringBuilder builder = new StringBuilder(); @@ -35,7 +27,7 @@ builder.append(annotation.toString()); builder.append(" "); } - builder.append(type.getTypeName()); + builder.append(typeName); return builder.toString(); } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java index 7861acc..d5291e9 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java @@ -7,7 +7,7 @@ * * @author s-yamagiwa */ -public abstract class Type extends ASTNode { +public abstract class Type extends ASTNode implements models.algebra.Type.ITypeImpl { /** * Returns whether this type is a primitive type or not. * diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclarationStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclarationStatement.java index c384ffa..bdc0ad4 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclarationStatement.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclarationStatement.java @@ -28,6 +28,10 @@ public List getFragments() { return fragments; } + + public void addFragment(VariableDeclaration fragment) { + this.fragments.add(fragment); + } public void setFragments(List fragments) { this.fragments = fragments; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerationContext.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerationContext.java new file mode 100644 index 0000000..157806d --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerationContext.java @@ -0,0 +1,144 @@ +package generators; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import code.ast.TypeDeclaration; +import models.algebra.Type; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ListType; +import models.dataConstraintModel.MapType; +import models.dataConstraintModel.ResourceHierarchy; +import models.dataFlowModel.DataTransferChannel; + +public class CodeGenerationContext { + protected HashMap> componentNames = new HashMap<>(); + protected Map resourceHierarchyToComponent; + protected Map componentNameToType; + protected Map>> updateMethods; + protected ILanguageSpecific langSpec = null; + protected IPlatformSpecific platformSpec = null; + + public CodeGenerationContext(ILanguageSpecific langSpec, IPlatformSpecific platformSpec) { + this.resourceHierarchyToComponent = new HashMap<>(); + this.componentNameToType = new HashMap<>(); + this.updateMethods = new HashMap<>(); + this.langSpec = langSpec; + this.platformSpec = platformSpec; + } + + public String getComponentName(ResourceHierarchy res, ILanguageSpecific langSpec) { + String name = res.getResourceName(); + if (res.getNumParameters() > 0) { + if (name.length() > 3 && name.endsWith("ies")) { + name = name.substring(0, name.length() - 3) + "y"; + } else if (name.length() > 1 && name.endsWith("s")) { + name = name.substring(0, name.length() - 1); + } else { + name += "Element"; + } + } + String componentName = langSpec.toComponentName(name); + if (!generatesComponent(res)) return componentName; + // To avoid generating multiple components with the same name. + HashMap resToName = componentNames.get(componentName); + if (resToName == null) { + resToName = new HashMap<>(); + resToName.put(res, componentName); + componentNames.put(componentName, resToName); + return componentName; + } + if (resToName.get(res) == null) { + componentName += resToName.size(); + resToName.put(res, componentName); + return componentName; + } + return resToName.get(res); + } + + public Type getOrCreateComponentType(ResourceHierarchy res) { + return getOrCreateComponentType(getComponentName(res, langSpec)); + } + + public Type getOrCreateComponentType(String componentName) { + Type componentType = componentNameToType.get(componentName); + if (componentType != null) return componentType; + componentType = new Type(componentName, new code.ast.SimpleType(componentName)); + componentNameToType.put(componentName, componentType); + return componentType; + } + + public Type getImplStateType(ResourceHierarchy res, ILanguageSpecific langSpec) { + Set children = res.getChildren(); + if (children == null || children.size() == 0) { + // leaf resource. + return res.getResourceStateType(); + } else { + ResourceHierarchy child = children.iterator().next(); + if (children.size() == 1 && child.getNumParameters() > 0) { + // map or list. + if (DataConstraintModel.typeList.isAncestorOf(res.getResourceStateType()) || res.getResourceStateType() instanceof ListType) { + // list. + if (generatesComponent(child)) { + return langSpec.newListType(getOrCreateComponentType(child)); + } else { + return langSpec.newListType(getImplStateType(child, langSpec)); + } + } else if (DataConstraintModel.typeMap.isAncestorOf(res.getResourceStateType()) || res.getResourceStateType() instanceof MapType) { + // map. + if (generatesComponent(child)) { + return langSpec.newMapType(DataConstraintModel.typeString, getOrCreateComponentType(child).getInterfaceTypeName()); + } else { + return langSpec.newMapType(DataConstraintModel.typeString, getImplStateType(child, langSpec).getInterfaceTypeName()); + } + } + return null; + } else { + // class + return res.getResourceStateType(); + } + } + } + + public boolean generatesComponent(ResourceHierarchy res) { + 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; + if (res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0 + && (res.getChildren().iterator().next().getChildren() == null || res.getChildren().iterator().next().getChildren().size() == 0)) return false; + return true; +// return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); + } + + public void putComponent(ResourceHierarchy res, TypeDeclaration component) { + resourceHierarchyToComponent.put(res, component); + } + + public TypeDeclaration getComponent(ResourceHierarchy res) { + return resourceHierarchyToComponent.get(res); + } + + + public String getOrPutUpdateMethodName(ResourceHierarchy srcRes, DataTransferChannel ch, ResourceHierarchy dstRes) { + Map> dstResUpdatesMethods = updateMethods.getOrDefault(dstRes, new HashMap<>()); + updateMethods.put(dstRes, dstResUpdatesMethods); + Map dstResFromSrcResUpdatesMethods = dstResUpdatesMethods.getOrDefault(srcRes, new HashMap<>()); + dstResUpdatesMethods.put(srcRes, dstResFromSrcResUpdatesMethods); + String updateMethodName = dstResFromSrcResUpdatesMethods.get(ch); + if (updateMethodName == null) { + String srcResComponentName = getComponentName(srcRes, langSpec); + String dstResComponentName = getComponentName(dstRes, langSpec); + if (generatesComponent(dstRes)) { + updateMethodName = CodeGenerator.updateMethodPrefix + CodeGenerator.from + srcResComponentName; + } else if (dstRes.getParent() != null) { + updateMethodName = CodeGenerator.updateMethodPrefix + dstResComponentName + CodeGenerator.from + srcResComponentName; + } + if (dstResFromSrcResUpdatesMethods.size() > 0) { + updateMethodName += dstResFromSrcResUpdatesMethods.size() + 1; // To avoid declaring the method multiply. + } + dstResFromSrcResUpdatesMethods.put(ch, updateMethodName); + } + return updateMethodName; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 37bf0f2..e38225a 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -10,13 +10,7 @@ import java.util.Set; import java.util.Stack; -import algorithms.TypeInference; -import code.ast.Block; -import code.ast.CompilationUnit; -import code.ast.FieldDeclaration; -import code.ast.MethodDeclaration; -import code.ast.TypeDeclaration; -import code.ast.VariableDeclaration; +import code.ast.*; import models.Edge; import models.Node; import models.algebra.Constant; @@ -30,9 +24,13 @@ import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ListType; +import models.dataConstraintModel.MapType; +import models.dataConstraintModel.PairType; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; +import models.dataConstraintModel.TupleType; import models.dataFlowModel.ChannelNode; import models.dataFlowModel.DataFlowEdge; import models.dataFlowModel.DataFlowGraph; @@ -58,98 +56,40 @@ public static final String from = "From"; public static final String _for = "For"; public static final String presenter = "presenter"; - public static final Type presenterType = new Type("SwingPresenter", "SwingPresenter"); + public static final Type presenterType = new Type("SwingPresenter", new code.ast.SimpleType("SwingPresenter")); private static String mainTypeName = null; - private static HashMap> componentNames = new HashMap<>(); - protected Map>> updateMethods; + protected CodeGenerationContext generationContext = null; protected ILanguageSpecific langSpec = null; protected IPlatformSpecific platformSpec = null; - public CodeGenerator() { - componentNames.clear(); + public CodeGenerator(IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + this.langSpec = langSpec; + this.platformSpec = platformSpec; + this.generationContext = new CodeGenerationContext(langSpec, platformSpec); } - - public static String getMainTypeName() { + + public String getMainTypeName() { return mainTypeName; } - public static void setMainTypeName(String mainTypeName) { + public void setMainTypeName(String mainTypeName) { CodeGenerator.mainTypeName = mainTypeName; } - public static void resetMainTypeName() { + public void resetMainTypeName() { CodeGenerator.mainTypeName = null; } - public static String getComponentName(ResourceHierarchy res, ILanguageSpecific langSpec) { - String name = res.getResourceName(); - if (res.getNumParameters() > 0) { - if (name.length() > 3 && name.endsWith("ies")) { - name = name.substring(0, name.length() - 3) + "y"; - } else if (name.length() > 1 && name.endsWith("s")) { - name = name.substring(0, name.length() - 1); - } else { - name += "Element"; - } - } - String componentName = langSpec.toComponentName(name); - if (!generatesComponent(res)) return componentName; - // To avoid generating multiple components with the same name. - HashMap resToName = componentNames.get(componentName); - if (resToName == null) { - resToName = new HashMap<>(); - resToName.put(res, componentName); - componentNames.put(componentName, resToName); - return componentName; - } - if (resToName.get(res) == null) { - componentName += resToName.size(); - resToName.put(res, componentName); - return componentName; - } - return resToName.get(res); + public String getComponentName(ResourceHierarchy res, ILanguageSpecific langSpec) { + return generationContext.getComponentName(res, langSpec); } - public static Type getImplStateType(ResourceHierarchy res, ILanguageSpecific langSpec) { - Set children = res.getChildren(); - if (children == null || children.size() == 0) { - // leaf resource. - return res.getResourceStateType(); - } else { - ResourceHierarchy child = children.iterator().next(); - if (children.size() == 1 && child.getNumParameters() > 0) { - // map or list. - if (DataConstraintModel.typeList.isAncestorOf(res.getResourceStateType())) { - // list. - if (generatesComponent(child)) { - return langSpec.newListType(getComponentName(child, langSpec)); - } else { - 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).getInterfaceTypeName()); - } - } - return null; - } else { - // class - return res.getResourceStateType(); - } - } + public Type getImplStateType(ResourceHierarchy res, ILanguageSpecific langSpec) { + return generationContext.getImplStateType(res, langSpec); } - public static boolean generatesComponent(ResourceHierarchy res) { - 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; - if (res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0 - && (res.getChildren().iterator().next().getChildren() == null || res.getChildren().iterator().next().getChildren().size() == 0)) return false; - return true; -// return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); + public boolean generatesComponent(ResourceHierarchy res) { + return generationContext.generatesComponent(res); } /** @@ -160,10 +100,7 @@ * @param langSpec specified language * @return source codes */ - public ArrayList generateCode(DataTransferModel model, DataFlowGraph flowGraph, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { - this.langSpec = langSpec; - this.platformSpec = platformSpec; - this.updateMethods = new HashMap<>(); + public ArrayList generateCode(DataTransferModel model, DataFlowGraph flowGraph) { ArrayList codes = new ArrayList<>(); Map> dependedRootComponentGraph = null; @@ -312,7 +249,7 @@ String componentName = langSpec.toComponentName(nodeName); // Declare a field to refer each object. if (langSpec.declareField()) { - FieldDeclaration refField = langSpec.newFieldDeclaration(new Type(componentName, componentName), nodeName); + FieldDeclaration refField = langSpec.newFieldDeclaration(generationContext.getOrCreateComponentType(componentName), nodeName); mainType.addField(refField); } // Add a statement to instantiate each object to the main constructor. @@ -345,10 +282,10 @@ String dstNodeName = langSpec.toVariableName(dstComponentName); if (langSpec.declareField()) { // Declare a field to refer to another component. - component.addField(langSpec.newFieldDeclaration(new Type(dstComponentName, dstComponentName), dstNodeName)); + component.addField(langSpec.newFieldDeclaration(generationContext.getOrCreateComponentType(dstComponentName), dstNodeName)); } // Initialize the field to refer to another component. - constructor.addParameter(langSpec.newVariableDeclaration(new Type(dstComponentName, dstComponentName), dstNodeName)); + constructor.addParameter(langSpec.newVariableDeclaration(generationContext.getOrCreateComponentType(dstComponentName), dstNodeName)); constructor.getBody().addStatement(langSpec.getFieldAccessor(dstNodeName) + langSpec.getAssignment() + dstNodeName + langSpec.getStatementDelimiter()); } return dstRes; @@ -357,19 +294,19 @@ protected void fillStateGetterMethod(MethodDeclaration stateGetter, ResourceHierarchy resourceHierarchy, Type resStateType) { // returns the state field when all incoming data-flow edges are PUSH-style. if (langSpec.isValueType(resStateType)) { - stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState)) + langSpec.getStatementDelimiter()); // return value; + stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState))); // return value; } else { if (resourceHierarchy.getChildren() != null && resourceHierarchy.getChildren().size() == 1 && resourceHierarchy.getChildren().iterator().next().getNumParameters() > 0) { // list or map // if (!platformSpec.isMonolithic()) { // // For REST API -// stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState)) + langSpec.getStatementDelimiter()); // return value; +// stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState))); // return value; // } else { String implTypeName = resStateType.getImplementationTypeName(); // copy the current state to be returned as a 'value' List parameters = new ArrayList<>(); parameters.add(langSpec.getFieldAccessor(fieldOfResourceState)); - stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters)) + langSpec.getStatementDelimiter()); // return new Resource(value); + stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters))); // return new Resource(value); // } } else { if (resourceHierarchy.getChildren() == null || resourceHierarchy.getChildren().size() == 0) { @@ -382,7 +319,7 @@ // copy the current state to be returned as a 'value' List parameters = new ArrayList<>(); parameters.add(langSpec.getFieldAccessor(fieldOfResourceState)); - stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters)) + langSpec.getStatementDelimiter()); // return new Resource(value); + stateGetter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters))); // return new Resource(value); // } } else { Term composer = null; @@ -412,9 +349,9 @@ String[] sideEffects = new String[] {null}; String returnValue = composer.toImplementation(sideEffects); if (sideEffects[0] != null) { - stateGetter.addStatement(sideEffects[0] + langSpec.getReturnStatement(returnValue) + langSpec.getStatementDelimiter()); + stateGetter.addStatement(sideEffects[0] + langSpec.getReturnStatement(returnValue)); } else { - stateGetter.addStatement(langSpec.getReturnStatement(returnValue) + langSpec.getStatementDelimiter()); + stateGetter.addStatement(langSpec.getReturnStatement(returnValue)); } } } @@ -452,7 +389,7 @@ 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()); + descendantGetter.addStatement(langSpec.getReturnStatement(returnValue)); } } @@ -482,15 +419,15 @@ } Block block = new Block(); Expression getState = getPullAccessor(platformSpec).getDirectStateAccessorFor(accessResPath, null); - block.addStatement(langSpec.getReturnStatement(getState.toImplementation(new String[] {null})) + langSpec.getStatementDelimiter()); + block.addStatement(langSpec.getReturnStatement(getState.toImplementation(new String[] {null}))); // if (stateGetter.getParameters() == null || stateGetter.getParameters().size() == 0) { -// block.addStatement(langSpec.getReturnStatement(langSpec.getMethodInvocation(accessRes.getResourceName(), stateGetter.getName())) + langSpec.getStatementDelimiter()); +// block.addStatement(langSpec.getReturnStatement(langSpec.getMethodInvocation(accessRes.getResourceName(), stateGetter.getName()))); // } else { // List resParams = new ArrayList<>(); // for (VariableDeclaration var: stateGetter.getParameters()) { // resParams.add(var.getName()); // } -// block.addStatement(langSpec.getReturnStatement(langSpec.getMethodInvocation(accessRes.getResourceName(), stateGetter.getName(), resParams)) + langSpec.getStatementDelimiter()); +// block.addStatement(langSpec.getReturnStatement(langSpec.getMethodInvocation(accessRes.getResourceName(), stateGetter.getName(), resParams))); // } accessor.setBody(block); mainComponent.addMethod(accessor); @@ -505,8 +442,8 @@ if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) { refs.add(res); String refResName = langSpec.toComponentName(res.getLeafResourceName()); - component.addField(langSpec.newFieldDeclaration(new Type(refResName, refResName), res.getLeafResourceName())); - constructor.addParameter(langSpec.newVariableDeclaration(new Type(refResName, refResName), res.getLeafResourceName())); + component.addField(langSpec.newFieldDeclaration(generationContext.getOrCreateComponentType(refResName), res.getLeafResourceName())); + constructor.addParameter(langSpec.newVariableDeclaration(generationContext.getOrCreateComponentType(refResName), res.getLeafResourceName())); constructor.getBody().addStatement(langSpec.getFieldAccessor(res.getLeafResourceName()) + langSpec.getAssignment() + res.getLeafResourceName() + langSpec.getStatementDelimiter()); } } @@ -515,25 +452,7 @@ } protected String getUpdateMethodName(ResourceHierarchy srcRes, ResourceHierarchy dstRes, DataTransferChannel ch) { - Map> dstResUpdatesMethods = updateMethods.getOrDefault(dstRes, new HashMap<>()); - updateMethods.put(dstRes, dstResUpdatesMethods); - Map dstResFromSrcResUpdatesMethods = dstResUpdatesMethods.getOrDefault(srcRes, new HashMap<>()); - dstResUpdatesMethods.put(srcRes, dstResFromSrcResUpdatesMethods); - String updateMethodName = dstResFromSrcResUpdatesMethods.get(ch); - if (updateMethodName == null) { - String srcResComponentName = getComponentName(srcRes, langSpec); - String dstResComponentName = getComponentName(dstRes, langSpec); - if (generatesComponent(dstRes)) { - updateMethodName = updateMethodPrefix + from + srcResComponentName; - } else if (dstRes.getParent() != null) { - updateMethodName = updateMethodPrefix + dstResComponentName + from + srcResComponentName; - } - if (dstResFromSrcResUpdatesMethods.size() > 0) { - updateMethodName += dstResFromSrcResUpdatesMethods.size() + 1; // To avoid declaring the method multiply. - } - dstResFromSrcResUpdatesMethods.put(ch, updateMethodName); - } - return updateMethodName; + return generationContext.getOrPutUpdateMethodName(srcRes, ch, dstRes); } protected MethodDeclaration getConstructor(TypeDeclaration component) { @@ -743,109 +662,126 @@ return resPath.getResourceHierarchy().toResourcePath(params); } - protected void generatePullDataTransfer(MethodDeclaration methodBody, String fromResourceName, String fromResourcePath, Type fromResourceType, boolean doesAddFirst, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + protected void generatePullDataTransfer(MethodDeclaration method, Block block, String fromResourceName, String fromResourcePath, Type fromResourceType, + boolean doesAddFirst, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + if (block == null) { + block = method.getBody(); + } RestApiSpecific restApiSpec = (RestApiSpecific) platformSpec; String varName = new String(fromResourceName); - String respTypeName = fromResourceType.getInterfaceTypeName(); + Type respType = fromResourceType; String respImplTypeName = fromResourceType.getImplementationTypeName(); - String respConverter = ""; + String responseConverter = ""; if (DataConstraintModel.typeList.isAncestorOf(fromResourceType) && fromResourceType != DataConstraintModel.typeList) { - Type compType = TypeInference.getListComponentType(fromResourceType); - if (DataConstraintModel.typeTuple.isAncestorOf(compType)) { - varName += "_json"; - String mapTypeName = convertFromEntryToMapType(compType, langSpec); - respTypeName = langSpec.newListType(mapTypeName).getInterfaceTypeName(); - respConverter += langSpec.getVariableDeclaration(fromResourceType.getInterfaceTypeName(), fromResourceName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(fromResourceType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; - respConverter += langSpec.getForStatementForCollection("i", mapTypeName, varName) + "\n"; - respConverter += "\t" + langSpec.getMethodInvocation(fromResourceName, DataConstraintModel.append.getImplName(), List.of(getCodeForConversionFromMapToTuple(compType, "i", langSpec))) + langSpec.getStatementDelimiter() + "\n"; - respConverter += langSpec.getEndForStatement("i") ; - restApiSpec.addJsonException(methodBody); - } else if (DataConstraintModel.typeMap.isAncestorOf(compType)) { - // To do. + if (fromResourceType instanceof ListType) { + Type compType = ((ListType) fromResourceType).getElementType(); + if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { + varName += "_list"; + Type mapType = convertFromEntryToMapType(compType, langSpec); + respType = langSpec.newListType(mapType); + responseConverter += langSpec.newVariableDeclaration(fromResourceType, fromResourceName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(fromResourceType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + EnhancedForStatement forStatement = langSpec.getForStatementForCollection(langSpec.newVariableDeclaration(mapType, "i"), varName); + Block forBlock = new Block(); + forBlock.addStatement(langSpec.getMethodInvocation(fromResourceName, DataConstraintModel.append.getImplName(), List.of(getCodeForConversionFromMapToTuple(compType, "i", langSpec))) + langSpec.getStatementDelimiter()); + forStatement.setBody(forBlock); + responseConverter += forStatement; + restApiSpec.addJsonException(method); + } else if (compType != null && DataConstraintModel.typeMap.isAncestorOf(compType)) { + // To do. + } } } else if (DataConstraintModel.typeTuple.isAncestorOf(fromResourceType)) { varName += "_json"; - respTypeName = convertFromEntryToMapType(fromResourceType, langSpec); - respConverter += langSpec.getVariableDeclaration(fromResourceType.getInterfaceTypeName(), fromResourceName) + langSpec.getAssignment() + getCodeForConversionFromMapToTuple(fromResourceType, varName, langSpec) + langSpec.getStatementDelimiter(); + respType = convertFromEntryToMapType(fromResourceType, langSpec); + responseConverter += langSpec.newVariableDeclaration(fromResourceType, fromResourceName) + langSpec.getAssignment() + getCodeForConversionFromMapToTuple(fromResourceType, varName, langSpec) + langSpec.getStatementDelimiter(); respImplTypeName = "HashMap"; } else if (DataConstraintModel.typePair.isAncestorOf(fromResourceType)) { varName += "_json"; - respTypeName = convertFromEntryToMapType(fromResourceType, langSpec); - respConverter += langSpec.getVariableDeclaration(fromResourceType.getInterfaceTypeName(), fromResourceName) + langSpec.getAssignment() + getCodeForConversionFromMapToPair(fromResourceType, varName, langSpec) + langSpec.getStatementDelimiter(); + respType = convertFromEntryToMapType(fromResourceType, langSpec); + responseConverter += langSpec.newVariableDeclaration(fromResourceType, fromResourceName) + langSpec.getAssignment() + getCodeForConversionFromMapToPair(fromResourceType, varName, langSpec) + langSpec.getStatementDelimiter(); respImplTypeName = "HashMap"; } else if (DataConstraintModel.typeMap.isAncestorOf(fromResourceType)) { varName += "_json"; - respTypeName = convertFromEntryToMapType(fromResourceType, langSpec); - respConverter += langSpec.getVariableDeclaration(fromResourceType.getInterfaceTypeName(), fromResourceName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(fromResourceType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; - respConverter += getCodeForConversionFromMapToMap(fromResourceType, varName, fromResourceName, langSpec); + respType = convertFromEntryToMapType(fromResourceType, langSpec); + responseConverter += langSpec.newVariableDeclaration(fromResourceType, fromResourceName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(fromResourceType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + responseConverter += getCodeForConversionFromMapToMap(fromResourceType, varName, fromResourceName, langSpec); respImplTypeName = "HashMap"; } if (doesAddFirst) { - if (respConverter.length() > 0) { - methodBody.addFirstStatement(respConverter); + if (responseConverter.length() > 0) { + block.addFirstStatement(responseConverter); } - methodBody.addFirstStatement(langSpec.getVariableDeclaration(respTypeName, varName) + langSpec.getAssignment() + restApiSpec.getHttpMethodCallWithResponseStatement(restApiSpec.getBaseURL(), fromResourcePath, getterPrefix, respImplTypeName)); + block.addFirstStatement(langSpec.newVariableDeclaration(respType, varName) + langSpec.getAssignment() + restApiSpec.getHttpMethodCallWithResponseStatement(restApiSpec.getBaseURL(), fromResourcePath, getterPrefix, respImplTypeName)); } else { - methodBody.addStatement(langSpec.getVariableDeclaration(respTypeName, varName) + langSpec.getAssignment() + restApiSpec.getHttpMethodCallWithResponseStatement(restApiSpec.getBaseURL(), fromResourcePath, getterPrefix, respImplTypeName)); - if (respConverter.length() > 0) { - methodBody.addStatement(respConverter); + block.addStatement(langSpec.newVariableDeclaration(respType, varName) + langSpec.getAssignment() + restApiSpec.getHttpMethodCallWithResponseStatement(restApiSpec.getBaseURL(), fromResourcePath, getterPrefix, respImplTypeName)); + if (responseConverter.length() > 0) { + block.addStatement(responseConverter); } } } - protected String convertFromEntryToMapType(Type type, ILanguageSpecific langSpec) { - String mapTypeName = null; + protected Type convertFromEntryToMapType(Type type, ILanguageSpecific langSpec) { + Type mapType = null; if (DataConstraintModel.typePair.isAncestorOf(type)) { - Type compType = TypeInference.getPairComponentType(type); - String wrapperType = DataConstraintModel.getWrapperType(compType); - if (wrapperType != null) { - mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, wrapperType).getInterfaceTypeName(); - } else { - mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, compType.getInterfaceTypeName()).getInterfaceTypeName(); + if (type instanceof PairType) { + Type compType = ((PairType) type).getComponentType(); + String wrapperType = DataConstraintModel.getWrapperType(compType); + if (wrapperType != null) { + mapType = langSpec.newMapType(DataConstraintModel.typeString, wrapperType); + } else { + mapType = langSpec.newMapType(DataConstraintModel.typeString, compType); + } } } else if (DataConstraintModel.typeMap.isAncestorOf(type)) { - List compTypes = TypeInference.getMapComponentTypes(type); - String wrapperType = DataConstraintModel.getWrapperType(compTypes.get(1)); - if (wrapperType != null) { - mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, wrapperType).getInterfaceTypeName(); - } else { - mapTypeName = langSpec.newMapType(DataConstraintModel.typeString, compTypes.get(1).getInterfaceTypeName()).getInterfaceTypeName(); + if (type instanceof MapType) { + Type keyType = ((MapType) type).getKeyType(); + Type valType = ((MapType) type).getValueType(); + String wrapperType = DataConstraintModel.getWrapperType(valType); + if (wrapperType != null) { + mapType = langSpec.newMapType(DataConstraintModel.typeString, wrapperType); + } else { + mapType = langSpec.newMapType(DataConstraintModel.typeString, valType.getInterfaceTypeName()); + } } } else { - mapTypeName = type.getInterfaceTypeName(); - mapTypeName = mapTypeName.replace(DataConstraintModel.typeTuple.getInterfaceTypeName(), DataConstraintModel.typeMap.getInterfaceTypeName()); - for (int idx = mapTypeName.indexOf("<", 0); idx >= 0; idx = mapTypeName.indexOf("<", idx + 1)) { // Java specific - int to = mapTypeName.indexOf(",", idx); // Java specific - if (to > idx) { - mapTypeName = mapTypeName.substring(0, idx + 1) + DataConstraintModel.typeString.getInterfaceTypeName() + mapTypeName.substring(to); // All elements except for the last one have the string type. + if (type instanceof TupleType) { + // Tuple (Map.Entry>> ==> Map>>) + List compTypes = ((TupleType) type).getComponentTypes(); + mapType = compTypes.get(compTypes.size() - 1); + for (int i = compTypes.size() - 2; i >= 0; i--) { + Type compType = compTypes.get(i); + mapType = langSpec.newMapType(DataConstraintModel.typeString, mapType); } } } - return mapTypeName; + return mapType; } protected String getCodeForConversionFromMapToTuple(Type tupleType, String mapVar, ILanguageSpecific langSpec) { String decoded = "$x"; - List elementsTypes = TypeInference.getTupleComponentTypes(tupleType); String elementBase = mapVar; - for (Type elmType: elementsTypes.subList(0, elementsTypes.size() - 1)) { - elementBase = langSpec.getFirstEntryFromMapExp(elementBase); // elementBase.entrySet().iterator().next() - if (elmType == DataConstraintModel.typeBoolean - || elmType == DataConstraintModel.typeInt - || elmType == DataConstraintModel.typeLong - || elmType == DataConstraintModel.typeFloat - || elmType == DataConstraintModel.typeDouble) { - String getKey = langSpec.getMethodInvocation(elementBase, DataConstraintModel.fst.getImplName()); // elementBase.getKey() - String elmVal = langSpec.getStringToValueExp(elmType.getImplementationTypeName(), getKey); // Integer.parseInt(elementBase.getKey()) - decoded = decoded.replace("$x", langSpec.getPairExp(elmVal, "$x")); // new AbstractMap.SimpleEntry<>(Integer.parseInt(elementBase.getKey()), $x) - } else if (elmType == DataConstraintModel.typeString) { - String getKey = langSpec.getMethodInvocation(elementBase, DataConstraintModel.fst.getImplName()); // elementBase.getKey() - decoded = decoded.replace("$x", langSpec.getPairExp(getKey, "$x")); // new AbstractMap.SimpleEntry<>(elementBase.getKey(), $x) - } else { - // To do. + if (tupleType instanceof TupleType) { + List componentsTypes = ((TupleType) tupleType).getComponentTypes(); + if (componentsTypes != null) { + for (Type elmType: componentsTypes.subList(0, componentsTypes.size() - 1)) { + elementBase = langSpec.getFirstEntryFromMapExp(elementBase); // elementBase.entrySet().iterator().next() + if (elmType == DataConstraintModel.typeBoolean + || elmType == DataConstraintModel.typeInt + || elmType == DataConstraintModel.typeLong + || elmType == DataConstraintModel.typeFloat + || elmType == DataConstraintModel.typeDouble) { + String getKey = langSpec.getMethodInvocation(elementBase, DataConstraintModel.fst.getImplName()); // elementBase.getKey() + String elmVal = langSpec.getStringToValueExp(elmType.getImplementationTypeName(), getKey); // Integer.parseInt(elementBase.getKey()) + decoded = decoded.replace("$x", langSpec.getPairExp(elmVal, "$x")); // new AbstractMap.SimpleEntry<>(Integer.parseInt(elementBase.getKey()), $x) + } else if (elmType == DataConstraintModel.typeString) { + String getKey = langSpec.getMethodInvocation(elementBase, DataConstraintModel.fst.getImplName()); // elementBase.getKey() + decoded = decoded.replace("$x", langSpec.getPairExp(getKey, "$x")); // new AbstractMap.SimpleEntry<>(elementBase.getKey(), $x) + } else { + // To do. + } + elementBase = langSpec.getMethodInvocation(elementBase, DataConstraintModel.snd.getImplName()); // elementBase.getValue() + } } - elementBase = langSpec.getMethodInvocation(elementBase, DataConstraintModel.snd.getImplName()); // elementBase.getValue() } decoded = decoded.replace("$x", elementBase); return decoded; @@ -859,22 +795,24 @@ } protected String getCodeForConversionFromMapToMap(Type mapType, String mapVal, String mapVar, ILanguageSpecific langSpec) { - List elementsTypes = TypeInference.getMapComponentTypes(mapType); - Type keyType = elementsTypes.get(0); -// Type valType = elementsTypes.get(1); String decoded = ""; - if (keyType == DataConstraintModel.typeBoolean - || keyType == DataConstraintModel.typeInt - || keyType == DataConstraintModel.typeLong - || keyType == DataConstraintModel.typeFloat - || keyType == DataConstraintModel.typeDouble) { - String keyVal = langSpec.getStringToValueExp(keyType.getImplementationTypeName(), "k"); - String getInvocation = langSpec.getMethodInvocation(mapVal, DataConstraintModel.lookup.getImplName(), List.of(keyVal)); - decoded += langSpec.getForStatementForMap("k", DataConstraintModel.typeString.getInterfaceTypeName(), mapVal) + "\n"; - decoded += "\t" + langSpec.getMethodInvocation(mapVar, DataConstraintModel.insert.getImplName(), List.of(keyVal, getInvocation)) + langSpec.getStatementDelimiter() + "\n"; - decoded += langSpec.getEndForStatement("k"); - } else if (keyType == DataConstraintModel.typeString) { - decoded += mapVar + langSpec.getAssignment() + mapVal + langSpec.getStatementDelimiter(); + if (mapType instanceof MapType) { + Type keyType = ((MapType) mapType).getKeyType(); + if (keyType == DataConstraintModel.typeBoolean + || keyType == DataConstraintModel.typeInt + || keyType == DataConstraintModel.typeLong + || keyType == DataConstraintModel.typeFloat + || keyType == DataConstraintModel.typeDouble) { + String keyVal = langSpec.getStringToValueExp(keyType.getImplementationTypeName(), "k"); + String getInvocation = langSpec.getMethodInvocation(mapVal, DataConstraintModel.lookup.getImplName(), List.of(keyVal)); + EnhancedForStatement forStatement = langSpec.getForStatementForMap("k", mapVal); + Block forBlock = new Block(); + forBlock.addStatement(langSpec.getMethodInvocation(mapVar, DataConstraintModel.insert.getImplName(), List.of(keyVal, getInvocation)) + langSpec.getStatementDelimiter()); + forStatement.setBody(forBlock); + decoded += forStatement; + } else if (keyType == DataConstraintModel.typeString) { + decoded += mapVar + langSpec.getAssignment() + mapVal + langSpec.getStatementDelimiter(); + } } return decoded; } @@ -895,7 +833,7 @@ } } - protected IResourceStateAccessor getPushAccessor(IPlatformSpecific platformSpec) { + public IResourceStateAccessor getPushAccessor(IPlatformSpecific platformSpec) { if (platformSpec.isMonolithic()) { return new IResourceStateAccessor() { @Override @@ -972,7 +910,7 @@ } } - protected IResourceStateAccessor getPullAccessor(IPlatformSpecific platformSpec) { + public IResourceStateAccessor getPullAccessor(IPlatformSpecific platformSpec) { if (platformSpec.isMonolithic()) { return new IResourceStateAccessor() { @Override @@ -1075,7 +1013,7 @@ if (getter == null && generatesComponent(curPath.getResourceHierarchy())) { // root resource String fieldName = langSpec.toVariableName(typeName); - getter = new Field(fieldName, new Type(typeName, typeName)); + getter = new Field(fieldName, generationContext.getOrCreateComponentType(typeName)); } else { if (generatesComponent(curPath.getResourceHierarchy())) { if (arity == 2) { @@ -1194,7 +1132,7 @@ if (getter == null && fromRes == null) { // root resource String fieldName = langSpec.toVariableName(typeName); - getter = new Field(fieldName, new Type(typeName, typeName)); + getter = new Field(fieldName, generationContext.getOrCreateComponentType(typeName)); } else { if (generatesComponent(curPath.getResourceHierarchy())) { if (arity == 2) { @@ -1255,7 +1193,7 @@ } } - protected IResourceStateAccessor getRefAccessor(IPlatformSpecific platformSpec) { + public IResourceStateAccessor getRefAccessor(IPlatformSpecific platformSpec) { if (platformSpec.isMonolithic()) { return new IResourceStateAccessor() { @Override diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index 4237555..0224022 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -9,20 +9,10 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; - -import algorithms.TypeInference; - import java.util.Set; import java.util.Stack; -import code.ast.Annotation; -import code.ast.Block; -import code.ast.CodeUtil; -import code.ast.CompilationUnit; -import code.ast.FieldDeclaration; -import code.ast.MethodDeclaration; -import code.ast.TypeDeclaration; -import code.ast.VariableDeclaration; +import code.ast.*; import models.Edge; import models.Node; import models.algebra.Constant; @@ -43,6 +33,7 @@ import models.dataConstraintModel.DataConstraintModel; import models.dataConstraintModel.JsonAccessor; import models.dataConstraintModel.JsonTerm; +import models.dataConstraintModel.ListType; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; @@ -60,11 +51,13 @@ import simulator.ResourceIdentifier; public class CodeGeneratorFromDataFlowGraph extends CodeGenerator { - protected Map resourceHierarchyToComponent; protected Map> constructorParams; + public CodeGeneratorFromDataFlowGraph(IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + super(platformSpec, langSpec); + } + public void generateCodeFromFlowGraph(DataTransferModel model, DataFlowGraph flowGraph, Collection components, ArrayList codes, Map> dependedRootComponentGraph) { - resourceHierarchyToComponent = new HashMap<>(); constructorParams = new HashMap<>(); Map resourceConstructors = new HashMap<>(); List> constructorStatements = new ArrayList<>(); @@ -93,7 +86,7 @@ // A component will be generated for this resource. String resourceName = getComponentName(resourceHierarchy, langSpec); Type resStateType = getImplStateType(resourceHierarchy, langSpec); - component = resourceHierarchyToComponent.get(resourceHierarchy); + component = generationContext.getComponent(resourceHierarchy); List depends = new ArrayList<>(); if (component == null) { // Add compilation unit for this component. @@ -102,7 +95,7 @@ // For each root node, add component annotations. ((RestApiSpecific) platformSpec).addComponentAnnotations(component, resourceNode.getResourceName()); } - resourceHierarchyToComponent.put(resourceHierarchy, component); + generationContext.putComponent(resourceHierarchy, component); CompilationUnit cu = langSpec.newCompilationUnit(component); if (!platformSpec.isMonolithic() && resourceHierarchy.getParent() == null) { // For each root node, add platform specific imports. @@ -146,8 +139,8 @@ } } if (component != null) { - if (resourceHierarchyToComponent.get(resourceHierarchy) == null) { - resourceHierarchyToComponent.put(resourceHierarchy, component); + if (generationContext.getComponent(resourceHierarchy) == null) { + generationContext.putComponent(resourceHierarchy, component); } // (#1) Declare the getter methods in this resource to obtain the descendant resources. (complementary to #2) declareDescendantGetterMethods(resourceNode, component, descendantGetters); @@ -168,12 +161,12 @@ TypeDeclaration parentComponent = null; TypeDeclaration rootComponent = null; if (generatesComponent(resourceHierarchy)) { - component = resourceHierarchyToComponent.get(resourceHierarchy); + component = generationContext.getComponent(resourceHierarchy); } if (resourceHierarchy.getParent() != null) { - parentComponent = resourceHierarchyToComponent.get(resourceHierarchy.getParent()); + parentComponent = generationContext.getComponent(resourceHierarchy.getParent()); } - rootComponent = resourceHierarchyToComponent.get(resourceHierarchy.getRoot()); + rootComponent = generationContext.getComponent(resourceHierarchy.getRoot()); // Declare cache fields and update methods in this resource, and an update accessor method in the type of root resource. Map.Entry, Map>>> initStatementsAndUpdateUpdates @@ -243,7 +236,7 @@ Expression updateExp = updateStatements.get(method).getKey(); ResourceHierarchy resource = updateStatements.get(method).getValue().getKey(); ResourceHierarchy descendantRes = updateStatements.get(method).getValue().getValue(); - TypeDeclaration descendantComponent = resourceHierarchyToComponent.get(descendantRes); + TypeDeclaration descendantComponent = generationContext.getComponent(descendantRes); addUpdateStatementWithConstructorInvocationToMethod(method, updateExp, resource, descendantRes, descendantComponent); } } @@ -294,12 +287,12 @@ if (params.size() > 0) { MethodDeclaration constructor = resourceConstructors.get(resource); if (constructor == null) { - if (resourceHierarchyToComponent.get(resource) != null) { + if (generationContext.getComponent(resource) != null) { String resourceName = getComponentName(resource, langSpec); constructor = langSpec.newMethodDeclaration(resourceName, true, null, null); Block body = new Block(); constructor.setBody(body); - resourceHierarchyToComponent.get(resource).addMethod(constructor); + generationContext.getComponent(resource).addMethod(constructor); resourceConstructors.put(resource, constructor); } } @@ -318,13 +311,13 @@ constructor.addParameter(param); constructor.getBody().addStatement(langSpec.getFieldAccessor(langSpec.toVariableName(param.getName())) + langSpec.getAssignment() + langSpec.toVariableName(param.getName()) + langSpec.getStatementDelimiter()); boolean existsField = false; - for (FieldDeclaration field: resourceHierarchyToComponent.get(resource).getFields()) { + for (FieldDeclaration field: generationContext.getComponent(resource).getFields()) { if (field.getName().equals(param.getName())) { existsField = true; } } if (!existsField) { - resourceHierarchyToComponent.get(resource).addField(langSpec.newFieldDeclaration(param.getType(), param.getName())); + generationContext.getComponent(resource).addField(langSpec.newFieldDeclaration(param.getType(), param.getName())); } } } @@ -338,14 +331,16 @@ // Replace each json term in exp with the corresponding constructor invocation. Type replacedJsonType = descendantRes.getResourceStateType(); String replacingClassName = getComponentName(descendantRes, langSpec); - Type descendantType = new Type(replacingClassName, replacingClassName); + Type descendantType = generationContext.getOrCreateComponentType(replacingClassName); Map subTerms = ((Term) exp).getSubTerms(Term.class); Iterator> termEntItr = subTerms.entrySet().iterator(); while (termEntItr.hasNext()) { + // For each sub-term of exp Entry termEnt = termEntItr.next(); Term jsonTerm = termEnt.getValue(); if (jsonTerm.getType() != null) { if (jsonTerm.getType().equals(replacedJsonType)) { + // a json sub-term to replace if (jsonTerm instanceof JsonTerm || jsonTerm.getSymbol().equals(DataConstraintModel.addMember)) { MethodDeclaration childConstructor = getConstructor(descendantComponent); List params = new ArrayList<>(); @@ -372,17 +367,24 @@ } } } - ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(langSpec.getConstructorInvocation(replacingClassName, params))); + ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(langSpec.getConstructorInvocation(replacingClassName, params))); // dummy algebraic expression subTerms = ((Term) exp).getSubTerms(Term.class); termEntItr = subTerms.entrySet().iterator(); } else { jsonTerm.setType(descendantType); } } else { + // not any sub-term to replace, but its type should be rewritten Type oldType = jsonTerm.getType(); - Type newType = new Type(oldType.getTypeName(), - oldType.getImplementationTypeName().replace(replacedJsonType.getInterfaceTypeName(), replacingClassName), - oldType.getInterfaceTypeName().replace(replacedJsonType.getInterfaceTypeName(), replacingClassName)); + Type.ITypeImpl newImplementationType = oldType.getImplementationType(); + Type.ITypeImpl newInterfaceType = oldType.getInterfaceType(); + if (newImplementationType instanceof ParameterizedType) { + ((code.ast.ParameterizedType) newImplementationType).replaceSubTypes((code.ast.Type) replacedJsonType.getImplementationType(), (code.ast.Type) descendantType.getImplementationType()); + } + if (newInterfaceType instanceof ParameterizedType) { + ((code.ast.ParameterizedType) newInterfaceType).replaceSubTypes((code.ast.Type) replacedJsonType.getInterfaceType(), (code.ast.Type) descendantType.getInterfaceType()); + } + Type newType = new Type(oldType.getTypeName(), newImplementationType, newInterfaceType); for (Type parent: oldType.getParentTypes()) { newType.addParentType(parent); } @@ -544,7 +546,7 @@ Type childType = null; if (generatesComponent(c)) { // The child has a component. - childType = new Type(childTypeName, childTypeName); + childType = generationContext.getOrCreateComponentType(childTypeName); String fieldName = c.getResourceName(); FieldDeclaration stateField = langSpec.newFieldDeclaration(childType, fieldName, langSpec.getConstructorInvocation(childTypeName, new ArrayList<>())); component.addField(stateField); @@ -611,8 +613,8 @@ dstRes = dstRes.getParent(); } String dstResName = getComponentName(dstRes, langSpec); - FieldDeclaration refFieldForPush = langSpec.newFieldDeclaration(new Type(dstResName, dstResName), langSpec.toVariableName(dstResName)); - VariableDeclaration refVarForPush = langSpec.newVariableDeclaration(new Type(dstResName, dstResName), langSpec.toVariableName(dstResName)); + FieldDeclaration refFieldForPush = langSpec.newFieldDeclaration(generationContext.getOrCreateComponentType(dstResName), langSpec.toVariableName(dstResName)); + VariableDeclaration refVarForPush = langSpec.newVariableDeclaration(generationContext.getOrCreateComponentType(dstResName), langSpec.toVariableName(dstResName)); if (!platformSpec.isMonolithic() && (outsideOutputResource || (resourceNode.getOutSideResource(ch).getCommonPrefix(dstResPath) == null && platformSpec.isDifferentTreesAsDifferentServices()))) { // Inter-service (for REST API) @@ -659,7 +661,7 @@ if (dstRes.getParent() != null) { // Reference to its root resource. String dstRootResName = getComponentName(dstRes.getRoot(), langSpec); - Type dstRootResType = new Type(dstRootResName, dstRootResName); + Type dstRootResType = generationContext.getOrCreateComponentType(dstRootResName); dstRootResName = langSpec.toVariableName(dstRootResName); FieldDeclaration refRootFieldForPush = langSpec.newFieldDeclaration(dstRootResType, dstRootResName); VariableDeclaration refRootVarForPush = langSpec.newVariableDeclaration(dstRootResType, dstRootResName); @@ -761,8 +763,8 @@ srcRes = srcRes.getParent(); } String srcResName = getComponentName(srcRes.getResourceHierarchy(), langSpec); - FieldDeclaration refFieldForPull = langSpec.newFieldDeclaration(new Type(srcResName, srcResName), langSpec.toVariableName(srcResName)); - VariableDeclaration refVarForPull = langSpec.newVariableDeclaration(new Type(srcResName, srcResName), langSpec.toVariableName(srcResName)); + FieldDeclaration refFieldForPull = langSpec.newFieldDeclaration(generationContext.getOrCreateComponentType(srcResName), langSpec.toVariableName(srcResName)); + VariableDeclaration refVarForPull = langSpec.newVariableDeclaration(generationContext.getOrCreateComponentType(srcResName), langSpec.toVariableName(srcResName)); if (!platformSpec.isMonolithic() && (outsideInputResource || (resourceNode.getInSideResource(ch).getCommonPrefix(srcRes) == null && platformSpec.isDifferentTreesAsDifferentServices()))) { // Inter-service (for REST API) @@ -810,7 +812,7 @@ if (srcRes.getParent() != null) { // Reference to its root resource. String srcRootResName = getComponentName(srcRes.getRoot().getResourceHierarchy(), langSpec); - Type srcRootResType = new Type(srcRootResName, srcRootResName); + Type srcRootResType = generationContext.getOrCreateComponentType(srcRootResName); srcRootResName = langSpec.toVariableName(srcRootResName); FieldDeclaration refRootFieldForPull = langSpec.newFieldDeclaration(srcRootResType, srcRootResName); VariableDeclaration refRootVarForPull = langSpec.newVariableDeclaration(srcRootResType, srcRootResName); @@ -925,7 +927,7 @@ childNode = ancestorNode; ancestorNode = ancestorNode.getParent(); } while (!generatesComponent(ancestorNode.getResourceHierarchy())); - TypeDeclaration ancestorComponent = resourceHierarchyToComponent.get(ancestorNode.getResourceHierarchy()); + TypeDeclaration ancestorComponent = generationContext.getComponent(ancestorNode.getResourceHierarchy()); List getterParams = new ArrayList<>(); int v = 1; while (ancestors.size() > 0) { @@ -1028,9 +1030,9 @@ String[] sideEffects = new String[] {""}; pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); } - generatePullDataTransfer(stateGetter, srcResourceName, - srcResPath.getResourceHierarchy().toResourcePath(pathParams), srcResourceType, - true, platformSpec, langSpec); + generatePullDataTransfer(stateGetter, null, + srcResourceName, srcResPath.getResourceHierarchy().toResourcePath(pathParams), + srcResourceType, true, platformSpec, langSpec); bDeclareClientField = true; } } @@ -1063,9 +1065,9 @@ String[] sideEffects = new String[] {""}; pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); } - generatePullDataTransfer(stateGetter, refResourceName, - refResPath.getResourceHierarchy().toResourcePath(pathParams), refResourceType, - true, platformSpec, langSpec); + generatePullDataTransfer(stateGetter, null, + refResourceName, refResPath.getResourceHierarchy().toResourcePath(pathParams), + refResourceType, true, platformSpec, langSpec); bDeclareClientField = true; } } @@ -1101,7 +1103,7 @@ Type srcResourceType = srcResPath.getResourceStateType(); String srcResName2 = langSpec.toVariableName(getComponentName(srcResPath.getResourceHierarchy(), langSpec)); String srcPath2 = srcResPath.toResourcePath().replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - generatePullDataTransfer(stateGetter, srcResName2, srcPath2, srcResourceType, false, platformSpec, langSpec); + generatePullDataTransfer(stateGetter, null, srcResName2, srcPath2, srcResourceType, false, platformSpec, langSpec); bDeclareClientField = true; } } @@ -1128,11 +1130,11 @@ String srcResName2 = langSpec.toVariableName(getComponentName(src2.getResourceHierarchy(), langSpec)); if (platformSpec.isMonolithic()) { String srcGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(src2, resourceNode.getInSideResource(curChannel)).toImplementation(new String[] {""}); - stateGetter.addStatement(langSpec.getVariableDeclaration(srcResType2.getInterfaceTypeName(), srcResName2) + stateGetter.addStatement(langSpec.newVariableDeclaration(srcResType2, srcResName2) + langSpec.getAssignment() + srcGetter + langSpec.getStatementDelimiter()); } else { String srcPath2 = src2.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - generatePullDataTransfer(stateGetter, srcResName2, srcPath2, srcResType2, false, platformSpec, langSpec); + generatePullDataTransfer(stateGetter, null, srcResName2, srcPath2, srcResType2, false, platformSpec, langSpec); bDeclareClientField = true; } } else { @@ -1145,11 +1147,11 @@ String srcResName2 = langSpec.toVariableName(getComponentName(src2.getResourceHierarchy(), langSpec)); if (platformSpec.isMonolithic()) { String dependingGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(src2, resourceNode.getInSideResource(curChannel)).toImplementation(new String[] {""}); - stateGetter.addStatement(langSpec.getVariableDeclaration(srcResType2.getInterfaceTypeName(), srcResName2) + stateGetter.addStatement(langSpec.newVariableDeclaration(srcResType2, srcResName2) + langSpec.getAssignment() + dependingGetter + langSpec.getStatementDelimiter()); } else { String srcPath2 = src2.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - generatePullDataTransfer(stateGetter, srcResName2, srcPath2, srcResType2, false, platformSpec, langSpec); + generatePullDataTransfer(stateGetter, null, srcResName2, srcPath2, srcResType2, false, platformSpec, langSpec); bDeclareClientField = true; } } @@ -1198,10 +1200,10 @@ // enclosed by a for loop (for data collecting pull transfer) Expression selExp = curChannel.getSelectors().get(0).getExpression(); Type selType = null; - String forVarName = null; + Block forLoopBlock = stateGetter.getBody(); if (selExp instanceof Variable) { selType = ((Variable) selExp).getType(); - forVarName = ((Variable) selExp).getName(); + String forVarName = ((Variable) selExp).getName(); ChannelMember insideChMem = null; for (ChannelMember cm2 :curChannel.getInputChannelMembers()) { if (!cm2.isOutside()) { @@ -1241,10 +1243,16 @@ } if (selType.equals(DataConstraintModel.typeInt)) { // make a for loop (for a list) for data collecting. - stateGetter.addFirstStatement(langSpec.getForStatementForList(forVarName, parent)); + ForStatement forLoopToCollectData = langSpec.getForStatementForList(forVarName, parent); + forLoopBlock = new Block(); + forLoopToCollectData.setBody(forLoopBlock); + stateGetter.addStatement(forLoopToCollectData); } else if (selType.equals(DataConstraintModel.typeString)) { // make a for loop (for a map) for data collecting. - stateGetter.addFirstStatement(langSpec.getForStatementForMap(forVarName, DataConstraintModel.typeString.getInterfaceTypeName(), parent)); + EnhancedForStatement forLoopToCollectData = langSpec.getForStatementForMap(forVarName, parent); + forLoopBlock = new Block(); + forLoopToCollectData.setBody(forLoopBlock); + stateGetter.addStatement(forLoopToCollectData); } if (!platformSpec.isMonolithic() && insideResPath.getCommonPrefix(dstResPath) == null @@ -1253,18 +1261,16 @@ Type parentResType = insideResPath.getResourceStateType(); String parentResName = langSpec.toVariableName(getComponentName(insideResPath.getResourceHierarchy(), langSpec)); String parentResPath = insideResPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - generatePullDataTransfer(stateGetter, parentResName, parentResPath, parentResType, true, platformSpec, langSpec); + generatePullDataTransfer(stateGetter, forLoopBlock, parentResName, parentResPath, parentResType, true, platformSpec, langSpec); bDeclareClientField = true; } } } // initialize the variables to hold side effects within the loop for (Variable var: varsForSideEffects) { - stateGetter.addFirstStatement(langSpec.getVariableDeclaration(var.getType().getInterfaceTypeName(), var.getName()) + stateGetter.addFirstStatement(langSpec.newVariableDeclaration(var.getType(), var.getName()) + langSpec.getAssignment() + langSpec.getConstructorInvocation(var.getType().getImplementationTypeName(), null) + langSpec.getStatementDelimiter()); } - // end of the loop - stateGetter.addStatement("}"); if (curChannel.getChildren() != null && curChannel.getChildren().size() > 0) { channelItrStack.push(chItr); chItr = curChannel.getChildren().iterator(); @@ -1276,7 +1282,7 @@ // generate a return statement. String[] sideEffects = new String[] {""}; String curState = ch.deriveUpdateExpressionOf(out, messageTerm, getPullAccessor(platformSpec)).toImplementation(sideEffects); - stateGetter.addStatement(sideEffects[0] + langSpec.getReturnStatement(curState) + langSpec.getStatementDelimiter()); + stateGetter.addStatement(sideEffects[0] + langSpec.getReturnStatement(curState)); } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed | ValueUndefined e) { e.printStackTrace(); @@ -1314,7 +1320,7 @@ if (!descendants.contains(descendant.getResourceHierarchy())) { descendants.add(descendant.getResourceHierarchy()); String descendantCompName = getComponentName(descendant.getResourceHierarchy(), langSpec); - Type descendantType = new Type(descendantCompName, descendantCompName); + Type descendantType = generationContext.getOrCreateComponentType(descendantCompName); MethodDeclaration descendantGetter = null; if (params.size() == 0) { descendantGetter = langSpec.newMethodDeclaration(getterPrefix + descendantCompName, descendantType); @@ -1608,7 +1614,9 @@ } i++; } - update.addFirstStatement(langSpec.getIfStatement(conditions, updateStatement)); + Block ifBlock = new Block(); + ifBlock.addStatement(updateStatement); + update.addFirstStatement(langSpec.getIfStatement(conditions, ifBlock)); } } } @@ -1631,61 +1639,66 @@ Type paramType = jsonParam.getType(); String paramName = jsonParam.getName(); String paramTypeName = paramType.getInterfaceTypeName(); - String strTypeName = DataConstraintModel.typeString.getInterfaceTypeName(); String paramConverter = ""; if (DataConstraintModel.typeList.isAncestorOf(paramType) && paramType != DataConstraintModel.typeList) { - Type compType = TypeInference.getListComponentType(paramType); - if (DataConstraintModel.typeTuple.isAncestorOf(compType)) { - jsonParam.setType(DataConstraintModel.typeListStr); - jsonParam.setName(paramName + "_json"); - paramConverter += langSpec.getVariableDeclaration(paramTypeName, paramName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(paramType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; - paramConverter += langSpec.getForStatementForCollection("str", strTypeName, jsonParam.getName()) + "\n"; - String mapTypeName = convertFromEntryToMapType(compType, langSpec); - paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString("str", "i", mapTypeName) + langSpec.getStatementDelimiter() + "\n"; - paramConverter += "\t" + langSpec.getMethodInvocation(paramName, DataConstraintModel.append.getImplName(), List.of(getCodeForConversionFromMapToTuple(compType, "i", langSpec))) + langSpec.getStatementDelimiter() + "\n"; - paramConverter += langSpec.getEndForStatement("str"); - ((RestApiSpecific) platformSpec).addJsonException(update); - } else if (DataConstraintModel.typePair.isAncestorOf(compType)) { - jsonParam.setType(DataConstraintModel.typeListStr); - jsonParam.setName(paramName + "_json"); - paramConverter += langSpec.getVariableDeclaration(paramTypeName, paramName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(paramType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; - paramConverter += langSpec.getForStatementForCollection("str", strTypeName, jsonParam.getName()) + "\n"; - String mapTypeName = convertFromEntryToMapType(compType, langSpec); - paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString("str", "i", mapTypeName) + langSpec.getStatementDelimiter() + "\n"; - paramConverter += "\t" + langSpec.getMethodInvocation(paramName, DataConstraintModel.append.getImplName(), List.of(getCodeForConversionFromMapToPair(compType, "i", langSpec))) + langSpec.getStatementDelimiter() + "\n"; - paramConverter += langSpec.getEndForStatement("str"); - ((RestApiSpecific) platformSpec).addJsonException(update); - } else if (DataConstraintModel.typeMap.isAncestorOf(compType)) { - jsonParam.setType(DataConstraintModel.typeListStr); - // To do. + if (paramType instanceof ListType) { + Type compType = ((ListType) paramType).getElementType(); + if (compType != null && DataConstraintModel.typeTuple.isAncestorOf(compType)) { + jsonParam.setType(DataConstraintModel.typeListStr); + jsonParam.setName(paramName + "_json"); + paramConverter += langSpec.newVariableDeclaration(paramType, paramName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(paramType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + EnhancedForStatement forStatement = langSpec.getForStatementForCollection(langSpec.newVariableDeclaration(DataConstraintModel.typeString, "str"), jsonParam.getName()); + Block forBlock = new Block(); + Type mapType = convertFromEntryToMapType(compType, langSpec); + forBlock.addStatement(((RestApiSpecific) platformSpec).getConversionFromJsonString("str", "i", mapType.getInterfaceTypeName()) + langSpec.getStatementDelimiter()); + forBlock.addStatement(langSpec.getMethodInvocation(paramName, DataConstraintModel.append.getImplName(), List.of(getCodeForConversionFromMapToTuple(compType, "i", langSpec))) + langSpec.getStatementDelimiter()); + forStatement.setBody(forBlock); + paramConverter += forStatement; + ((RestApiSpecific) platformSpec).addJsonException(update); + } else if (compType != null && DataConstraintModel.typePair.isAncestorOf(compType)) { + jsonParam.setType(DataConstraintModel.typeListStr); + jsonParam.setName(paramName + "_json"); + paramConverter += langSpec.newVariableDeclaration(paramType, paramName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(paramType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + EnhancedForStatement forStatement = langSpec.getForStatementForCollection(langSpec.newVariableDeclaration(DataConstraintModel.typeString, "str"), jsonParam.getName()); + Block forBlock = new Block(); + Type mapType = convertFromEntryToMapType(compType, langSpec); + forBlock.addStatement(((RestApiSpecific) platformSpec).getConversionFromJsonString("str", "i", mapType.getInterfaceTypeName()) + langSpec.getStatementDelimiter()); + forBlock.addStatement(langSpec.getMethodInvocation(paramName, DataConstraintModel.append.getImplName(), List.of(getCodeForConversionFromMapToPair(compType, "i", langSpec))) + langSpec.getStatementDelimiter()); + forStatement.setBody(forBlock); + paramConverter += forStatement; + ((RestApiSpecific) platformSpec).addJsonException(update); + } else if (compType != null && DataConstraintModel.typeMap.isAncestorOf(compType)) { + jsonParam.setType(DataConstraintModel.typeListStr); + // To do. + } } } else if (DataConstraintModel.typeTuple.isAncestorOf(paramType)) { jsonParam.setType(DataConstraintModel.typeString); jsonParam.setName(paramName + "_json"); - paramConverter += langSpec.getVariableDeclaration(paramTypeName, paramName) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.newVariableDeclaration(paramType, paramName) + langSpec.getStatementDelimiter() + "\n"; paramConverter += langSpec.getOpeningScoreDelimiter() + "\n"; - String mapTypeName = convertFromEntryToMapType(paramType, langSpec); - paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapTypeName) + langSpec.getStatementDelimiter() + "\n"; + Type mapType = convertFromEntryToMapType(paramType, langSpec); + paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapType.getInterfaceTypeName()) + langSpec.getStatementDelimiter() + "\n"; paramConverter += "\t" + paramName + langSpec.getAssignment() + getCodeForConversionFromMapToTuple(paramType, "i", langSpec) + langSpec.getStatementDelimiter() + "\n"; paramConverter += langSpec.getClosingScoreDelimiter(); ((RestApiSpecific) platformSpec).addJsonException(update); } else if (DataConstraintModel.typePair.isAncestorOf(paramType)) { jsonParam.setType(DataConstraintModel.typeString); jsonParam.setName(paramName + "_json"); - paramConverter += langSpec.getVariableDeclaration(paramTypeName, paramName) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.newVariableDeclaration(paramType, paramName) + langSpec.getStatementDelimiter() + "\n"; paramConverter += langSpec.getOpeningScoreDelimiter() + "\n"; - String mapTypeName = convertFromEntryToMapType(paramType, langSpec); - paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapTypeName) + langSpec.getStatementDelimiter() + "\n"; + Type mapType = convertFromEntryToMapType(paramType, langSpec); + paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapType.getInterfaceTypeName()) + langSpec.getStatementDelimiter() + "\n"; paramConverter += "\t" + paramName + langSpec.getAssignment() + getCodeForConversionFromMapToPair(paramType, "i", langSpec) + langSpec.getStatementDelimiter() + "\n"; paramConverter += langSpec.getClosingScoreDelimiter(); ((RestApiSpecific) platformSpec).addJsonException(update); } else if (DataConstraintModel.typeMap.isAncestorOf(paramType)) { jsonParam.setType(DataConstraintModel.typeString); jsonParam.setName(paramName + "_json"); - paramConverter += langSpec.getVariableDeclaration(paramTypeName, paramName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(paramType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.newVariableDeclaration(paramType, paramName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(paramType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; paramConverter += langSpec.getOpeningScoreDelimiter() + "\n"; - String mapTypeName = convertFromEntryToMapType(paramType, langSpec); - paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapTypeName) + langSpec.getStatementDelimiter() + "\n"; + Type mapType = convertFromEntryToMapType(paramType, langSpec); + paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapType.getInterfaceTypeName()) + langSpec.getStatementDelimiter() + "\n"; paramConverter += "\t" + getCodeForConversionFromMapToMap(paramType, "i", paramName, langSpec) + "\n"; paramConverter += langSpec.getClosingScoreDelimiter(); ((RestApiSpecific) platformSpec).addJsonException(update); @@ -1836,8 +1849,7 @@ } if ((((PushPullAttribute) dOut.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource2) || outsideOutputResource2) { // PUSH transfer - boolean addForStatement = false; - String forVarName = null; + Block forLoopBlock = update.getBody(); if (descendantDstChannels.contains(chNode2)) { // For hierarchical channels (broadcasting push transfer). if (ch2.getSelectors() != null && ch2.getSelectors().size() > 0) { @@ -1845,7 +1857,7 @@ Type selType = null; if (selExp instanceof Variable) { selType = ((Variable) selExp).getType(); - forVarName = ((Variable) selExp).getName(); + String forVarName = ((Variable) selExp).getName(); ChannelMember insideChMem = null; for (ChannelMember cm :ch2.getInputChannelMembers()) { if (!cm.isOutside()) { @@ -1893,12 +1905,16 @@ } if (selType.equals(DataConstraintModel.typeInt)) { // make a for loop (for a list) for broadcasting. - update.addStatement(langSpec.getForStatementForList(forVarName, parent)); - addForStatement = true; + ForStatement forLoopToCollectData = langSpec.getForStatementForList(forVarName, parent); + forLoopBlock = new Block(); + forLoopToCollectData.setBody(forLoopBlock); + update.addStatement(forLoopToCollectData); } else if (selType.equals(DataConstraintModel.typeString)) { // make a for loop (for a map) for broadcasting. - update.addStatement(langSpec.getForStatementForMap(forVarName, DataConstraintModel.typeString.getInterfaceTypeName(), parent)); - addForStatement = true; + EnhancedForStatement forLoopToCollectData = langSpec.getForStatementForMap(forVarName, parent); + forLoopBlock = new Block(); + forLoopToCollectData.setBody(forLoopBlock); + update.addStatement(forLoopToCollectData); } if (!platformSpec.isMonolithic() && insideResPath.getCommonPrefix(resourceNode.getOutSideResource(directDstCh)) == null @@ -1907,7 +1923,7 @@ Type parentResType = insideResPath.getResourceStateType(); String parentResName = langSpec.toVariableName(getComponentName(insideResPath.getResourceHierarchy(), langSpec)); String parentResPath = insideResPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - generatePullDataTransfer(update, parentResName, parentResPath, parentResType, true, platformSpec, langSpec); + generatePullDataTransfer(update, forLoopBlock, parentResName, parentResPath, parentResType, true, platformSpec, langSpec); if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { // Declare a client field to connect to the destination resource of push transfer. ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); @@ -1948,7 +1964,7 @@ for (Expression pathExp: ref.getPathParams()) { pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); } - generatePullDataTransfer(update, refVarName, ref.getResourceHierarchy().toResourcePath(pathParams), refResourceType, false, platformSpec, langSpec); + generatePullDataTransfer(update, forLoopBlock, refVarName, ref.getResourceHierarchy().toResourcePath(pathParams), refResourceType, false, platformSpec, langSpec); if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { // Declare a client field to connect to the destination resource of push transfer. ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); @@ -1960,7 +1976,7 @@ Expression refGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(ref, srcRes); String refExp = refGetter.toImplementation(sideEffects); String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); - update.addStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refVarName) + forLoopBlock.addStatement(sideEffects[0] + langSpec.newVariableDeclaration(ref.getResourceStateType(), refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); } } @@ -1970,9 +1986,8 @@ } } // Add an update method invocation. - hasUpdateMethodinvoked = addUpdateMethodInvocation(resourceNode, dstNode, update, refParams, - ch2, in, out1, inDegree, outsideOutputResource2, - forVarName, addForStatement, hasUpdateMethodinvoked); + hasUpdateMethodinvoked = addUpdateMethodInvocation(resourceNode, dstNode, update, forLoopBlock, refParams, + ch2, in, out1, inDegree, outsideOutputResource2, hasUpdateMethodinvoked); } } @@ -2343,7 +2358,7 @@ String[] sideEffects = new String[] {""}; String refExp = refGetter.toImplementation(sideEffects); String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); - mainInputAccessor.addFirstStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refVarName) + mainInputAccessor.addFirstStatement(sideEffects[0] + langSpec.newVariableDeclaration(ref.getResourceStateType(), refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); } } @@ -2483,7 +2498,7 @@ for (Expression pathExp: ref.getPathParams()) { pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); } - generatePullDataTransfer(input, refResourceName, ref.getResourceHierarchy().toResourcePath(pathParams), refResourceType, true, platformSpec, langSpec); + generatePullDataTransfer(input, null, refResourceName, ref.getResourceHierarchy().toResourcePath(pathParams), refResourceType, true, platformSpec, langSpec); if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { // Declare a client field to connect to the destination resource of push transfer. ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); @@ -2495,7 +2510,7 @@ Expression refGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(ref, dstRes); String refExp = refGetter.toImplementation(sideEffects); String refTypeName = refResourceType.getInterfaceTypeName(); - input.addFirstStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refResourceName) + input.addFirstStatement(sideEffects[0] + langSpec.newVariableDeclaration(refResourceType, refResourceName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); } } @@ -2621,8 +2636,7 @@ } if ((((PushPullAttribute) dOut.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource2) || outsideOutputResource2) { // PUSH transfer - boolean addForStatement = false; - String forVarName = null; + Block forLoopBlock = input.getBody(); if (descendantDstChannels.contains(chNode2)) { // For hierarchical channels (broadcasting push transfer). if (ch2.getSelectors() != null && ch2.getSelectors().size() > 0) { @@ -2630,7 +2644,7 @@ Type selType = null; if (selExp instanceof Variable) { selType = ((Variable) selExp).getType(); - forVarName = ((Variable) selExp).getName(); + String forVarName = ((Variable) selExp).getName(); ChannelMember insideChMem = null; for (ChannelMember cm :ch2.getInputChannelMembers()) { if (!cm.isOutside()) { @@ -2678,12 +2692,16 @@ } if (selType.equals(DataConstraintModel.typeInt)) { // make a for loop (for a list) for broadcasting. - input.addStatement(langSpec.getForStatementForList(forVarName, parent)); - addForStatement = true; + ForStatement forLoopToCollectData = langSpec.getForStatementForList(forVarName, parent); + forLoopBlock = new Block(); + forLoopToCollectData.setBody(forLoopBlock); + input.addStatement(forLoopToCollectData); } else if (selType.equals(DataConstraintModel.typeString)) { // make a for loop (for a map) for broadcasting. - input.addStatement(langSpec.getForStatementForMap(forVarName, DataConstraintModel.typeString.getInterfaceTypeName(), parent)); - addForStatement = true; + EnhancedForStatement forLoopToCollectData = langSpec.getForStatementForMap(forVarName, parent); + forLoopBlock = new Block(); + forLoopToCollectData.setBody(forLoopBlock); + input.addStatement(forLoopToCollectData); } if (!platformSpec.isMonolithic() && insideResPath.getCommonPrefix(resourceNode.getOutSideResource(directDstCh)) == null @@ -2692,7 +2710,7 @@ Type parentResType = insideResPath.getResourceStateType(); String parentResName = langSpec.toVariableName(getComponentName(insideResPath.getResourceHierarchy(), langSpec)); String parentResPath = insideResPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - generatePullDataTransfer(input, parentResName, parentResPath, parentResType, true, platformSpec, langSpec); + generatePullDataTransfer(input, forLoopBlock, parentResName, parentResPath, parentResType, true, platformSpec, langSpec); if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { // Declare a client field to connect to the destination resource of push transfer. ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); @@ -2729,7 +2747,7 @@ String[] sideEffects = new String[] {""}; String refExp = refGetter.toImplementation(sideEffects); String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); - input.addStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); + forLoopBlock.addStatement(sideEffects[0] + langSpec.newVariableDeclaration(ref.getResourceStateType(), refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); } refParams.add(new AbstractMap.SimpleEntry<>(ref.getResourceStateType(), new AbstractMap.SimpleEntry<>(refVarName, @@ -2737,9 +2755,8 @@ } } // Add an update method invocation. - hasUpdateMethodinvoked = addUpdateMethodInvocation(resourceNode, dstNode, input, refParams, - ch2, in, out2, inDegree, outsideOutputResource2, - forVarName, addForStatement, hasUpdateMethodinvoked); + hasUpdateMethodinvoked = addUpdateMethodInvocation(resourceNode, dstNode, input, forLoopBlock, refParams, + ch2, in, out2, inDegree, outsideOutputResource2, hasUpdateMethodinvoked); } } @@ -2817,10 +2834,12 @@ } private boolean addUpdateMethodInvocation(ResourceNode srcNode, ResourceNode dstNode, - MethodDeclaration callerMethod, List>> refParams, - DataTransferChannel ch, ChannelMember in, ChannelMember out, int inDegree, boolean outsideOutputResource, - String forVarName, boolean addForStatement, boolean hasUpdateMethodinvoked) { - List>> pathParams = new ArrayList<>(); + MethodDeclaration callerMethod, Block callerBlock, List>> refParams, + DataTransferChannel ch, ChannelMember in, ChannelMember out, int inDegree, boolean outsideOutputResource, boolean hasUpdateMethodinvoked) { + if (callerBlock == null) { + callerBlock = callerMethod.getBody(); + } + List>> pathParams = new ArrayList<>(); if (platformSpec.isMonolithic()) { // Update fields to refer to outside resources. ResourcePath filledOutsideResourcePath = null; @@ -2852,7 +2871,7 @@ } String[] sideEffects = new String[] {""}; String outsideAccessor = outsideExp.toImplementation(sideEffects); - callerMethod.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. + callerBlock.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. } } } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork @@ -2976,21 +2995,23 @@ TypeDeclaration srcComponent = null; TypeDeclaration srcParentComponent = null; if (generatesComponent(srcRes)) { - srcComponent = resourceHierarchyToComponent.get(srcRes); + srcComponent = generationContext.getComponent(srcRes); } else if (srcRes.getParent() != null) { - srcParentComponent = resourceHierarchyToComponent.get(srcRes.getParent()); + srcParentComponent = generationContext.getComponent(srcRes.getParent()); } if (!hasUpdateMethodinvoked) { // The first call to an update method in this method - callerMethod.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, true)); - String httpMethodCall = langSpec.getVariableDeclaration(DataConstraintModel.typeString.getInterfaceTypeName(), "result") + callerBlock.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, true)); + String httpMethodCall = langSpec.newVariableDeclaration(DataConstraintModel.typeString, "result") + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, srcResName, httpMethod); if (guardCondition == null) { // Non-conditional http method call. - callerMethod.addStatement(httpMethodCall); + callerBlock.addStatement(httpMethodCall); } else { // Conditional http method call by a guarded state transition. - callerMethod.addStatement(langSpec.getIfStatement(guardCondition, httpMethodCall)); + Block ifBlock = new Block(); + ifBlock.addStatement(httpMethodCall); + callerBlock.addStatement(langSpec.getIfStatement(guardCondition, ifBlock)); } if (srcComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcComponent)) { // Declare a client field to connect to the destination resource of push transfer. @@ -3005,14 +3026,16 @@ hasUpdateMethodinvoked = true; } else { // After the second time of call to update methods in this method - callerMethod.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, false)); + callerBlock.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, false)); String httpMethodCall = "result" + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, srcResName, httpMethod); if (guardCondition == null) { // Non-conditional http method call. - callerMethod.addStatement(httpMethodCall); + callerBlock.addStatement(httpMethodCall); } else { // Conditional http method call by a guarded state transition. - callerMethod.addStatement(langSpec.getIfStatement(guardCondition, httpMethodCall)); + Block ifBlock = new Block(); + ifBlock.addStatement(httpMethodCall); + callerBlock.addStatement(langSpec.getIfStatement(guardCondition, ifBlock)); } if (srcComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcComponent)) { // Declare a client field to connect to the destination resource of push transfer. @@ -3039,10 +3062,12 @@ + langSpec.getStatementDelimiter(); // this.dst.updateDstFromSrc(value, refParams); if (guardCondition == null) { // Non-conditional invocation. - callerMethod.addStatement(methodInvocation); + callerBlock.addStatement(methodInvocation); } else { // Conditional invocation by a guarded state transition. - callerMethod.addStatement(langSpec.getIfStatement(guardCondition, methodInvocation)); + Block ifBlock = new Block(); + ifBlock.addStatement(methodInvocation); + callerBlock.addStatement(langSpec.getIfStatement(guardCondition, ifBlock)); } } } else { @@ -3065,16 +3090,14 @@ } if (guardCondition == null) { // Non-conditional invocation. - callerMethod.addStatement(methodInvocation); + callerBlock.addStatement(methodInvocation); } else { // Conditional invocation by a guarded state transition. - callerMethod.addStatement(langSpec.getIfStatement(guardCondition, methodInvocation)); + Block ifBlock = new Block(); + ifBlock.addStatement(methodInvocation); + callerBlock.addStatement(langSpec.getIfStatement(guardCondition, ifBlock)); } } - if (addForStatement) { - // Close the for loop - callerMethod.addStatement(langSpec.getEndForStatement(forVarName)); - } return hasUpdateMethodinvoked; } @@ -3136,7 +3159,7 @@ String updateMethodName = getUpdateMethodName(srcRes, dstRes, ch); if (generatesComponent(dstRes)) { // A component is created for this resource. - TypeDeclaration dstComponent = resourceHierarchyToComponent.get(dstRes); + TypeDeclaration dstComponent = generationContext.getComponent(dstRes); for (MethodDeclaration method: dstComponent.getMethods()) { if (method.getName().equals(updateMethodName)) { update = method; @@ -3149,7 +3172,7 @@ } } else if (dstRes.getParent() != null) { // No component is created for this resource. - TypeDeclaration dstParentComponent = resourceHierarchyToComponent.get(dstRes.getParent()); + TypeDeclaration dstParentComponent = generationContext.getComponent(dstRes.getParent()); for (MethodDeclaration method: dstParentComponent.getMethods()) { if (method.getName().equals(updateMethodName)) { update = method; @@ -3192,7 +3215,7 @@ resPath.replacePathParam(i, pathParam, null); } Expression getState = getPullAccessor(platformSpec).getDirectStateAccessorFor(resPath, resPath.getRoot()); - getterAccessor.getBody().addStatement(langSpec.getReturnStatement(getState.toImplementation(new String[] {null})) + langSpec.getStatementDelimiter()); + getterAccessor.getBody().addStatement(langSpec.getReturnStatement(getState.toImplementation(new String[] {null}))); if (!platformSpec.isMonolithic()) { ((RestApiSpecific) platformSpec).addGetAnnotations(getterAccessor); if (resourcePath.length() > 0) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java index 2c89884..2dfe533 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java @@ -1,14 +1,14 @@ package generators; -import java.util.ArrayList; import java.util.List; import code.ast.*; -import models.algebra.Expression; import models.algebra.Term; import models.algebra.Type; -import models.algebra.Variable; -import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; +import models.dataConstraintModel.JsonType; +import models.dataConstraintModel.ListType; +import models.dataConstraintModel.MapType; +import models.dataConstraintModel.TupleType; public interface ILanguageSpecific { CompilationUnit newCompilationUnit(TypeDeclaration component); @@ -18,10 +18,16 @@ MethodDeclaration newMethodDeclaration(String methodName, boolean isConstructor, Type returnType, List parameters); FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName); FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName, String fieldInitializer); - Type newListType(String compTypeName); - Type newMapType(Type keyType, String compTypeName); - Type newTupleType(List compTypes); - VariableDeclaration getVariableDeclaration(Type typeName, String varName); + ListType newListType(Type compType); + ListType newListType(Type compType, Type parentListType); + MapType newMapType(Type keyType, String compTypeName); + MapType newMapType(Type keyType, String compTypeName, Type parentMapType); + MapType newMapType(Type keyType, Type valueType); + MapType newMapType(Type keyType, Type valueType, Type parentMapType); + TupleType newTupleType(List compTypes); + TupleType newTupleType(List componentTypes, Type parentTupleType); + JsonType newJsonType(); + JsonType newJsonType(Type parentJsonType); boolean declareField(); String getSelfExp(); String getFieldAccessor(String fieldName); @@ -32,11 +38,9 @@ String getConstructorInvocation(String componentName, List parameters); ReturnStatement getReturnStatement(String returnValue); IfStatement getIfStatement(Term condition, Statement block); - ForStatement getForStatementForList(Variable varName, Expression list); - EnhancedForStatement getForStatementForCollection(String varName, String varType, String collection); - EnhancedForStatement getForStatementForMap(String varName, String varType, String map); - String getEndForStatement(); - String getEndForStatement(String varName); + ForStatement getForStatementForList(String varName, String list); + EnhancedForStatement getForStatementForCollection(VariableDeclaration varDeclaration, String collection); + EnhancedForStatement getForStatementForMap(String varName, String map); String toComponentName(String name); String toVariableName(String name); String getMainComponentName(); @@ -53,4 +57,5 @@ String getDecomposedTuple(String tupleExp, VariableDeclaration tupleVar, List vars); boolean isValueType(Type type); boolean isVoidType(Type type); + Type getWrapperType(Type type); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java deleted file mode 100644 index b362030..0000000 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ /dev/null @@ -1,1470 +0,0 @@ -package generators; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.Stack; - -import code.ast.Annotation; -import code.ast.Block; -import code.ast.CompilationUnit; -import code.ast.FieldDeclaration; -import code.ast.ImportDeclaration; -import code.ast.MethodDeclaration; -import code.ast.TypeDeclaration; -import code.ast.VariableDeclaration; -import models.Edge; -import models.Node; -import models.algebra.Expression; -import models.algebra.Field; -import models.algebra.Parameter; -import models.algebra.Position; -import models.algebra.Symbol; -import models.algebra.Term; -import models.algebra.Type; -import models.algebra.Variable; -import models.dataConstraintModel.Channel; -import models.dataConstraintModel.ChannelMember; -import models.dataConstraintModel.DataConstraintModel; -import models.dataConstraintModel.ResourceHierarchy; -import models.dataConstraintModel.ResourcePath; -import models.dataConstraintModel.Selector; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.DataTransferChannel; -import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; -import models.dataFlowModel.PushPullAttribute; -import models.dataFlowModel.PushPullValue; -import models.dataFlowModel.ChannelNode; -import models.dataFlowModel.DataFlowEdge; -import models.dataFlowModel.DataFlowGraph; -import models.dataFlowModel.ResourceNode; -import models.dataFlowModel.StoreAttribute; - -/** - * Generator for plain Java prototypes - * - * @author Nitta - * - */ -public class JavaCodeGenerator { - public static final Type typeVoid = new Type("Void", "void"); - private static String defaultMainTypeName = "Main"; - static String mainTypeName = defaultMainTypeName; - - public static String getMainTypeName() { - return mainTypeName; - } - - public static void setMainTypeName(String mainTypeName) { - JavaCodeGenerator.mainTypeName = mainTypeName; - } - - public static void resetMainTypeName() { - JavaCodeGenerator.mainTypeName = defaultMainTypeName; - } - - public static String getComponentName(ResourceHierarchy res) { - String name = res.getResourceName(); - if (res.getNumParameters() > 0) { - if (name.length() > 3 && name.endsWith("ies")) { - name = name.substring(0, name.length() - 3) + "y"; - } else if (name.length() > 1 && name.endsWith("s")) { - name = name.substring(0, name.length() - 1); - } else { - name += "Element"; - } - } - return name.substring(0, 1).toUpperCase() + name.substring(1); - } - - public static String toVariableName(String name) { - return name.substring(0, 1).toLowerCase() + name.substring(1); - } - - public static Type getImplStateType(ResourceHierarchy res) { - Set children = res.getChildren(); - if (children == null || children.size() == 0) { - // leaf resource. - return res.getResourceStateType(); - } else { - ResourceHierarchy child = children.iterator().next(); - if (children.size() == 1 && child.getNumParameters() > 0) { - // map or list. - if (DataConstraintModel.typeList.isAncestorOf(res.getResourceStateType())) { - // list. - if (generatesComponent(child)) { - return new Type("List", "ArrayList<>", "List<" + getComponentName(child) + ">", DataConstraintModel.typeList); - } else { - 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 null; - } else { - // class - return res.getResourceStateType(); - } - } - } - - public static boolean generatesComponent(ResourceHierarchy res) { - 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; - if (res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0 - && (res.getChildren().iterator().next().getChildren() == null || res.getChildren().iterator().next().getChildren().size() == 0)) return false; - return true; -// return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); - } - - static public ArrayList doGenerate(DataFlowGraph graph, DataTransferModel model) { - ArrayList codes = new ArrayList<>(); - Map resourceComponents = new HashMap<>(); - Map resourceConstructors = new HashMap<>(); - List> getters = new ArrayList<>(); - Map> updates = new HashMap<>(); - Map> inputs = new HashMap<>(); - List> fields = new ArrayList<>(); - Map> descendantGetters = new HashMap<>(); - List> constructorParams = new ArrayList<>(); - - Map> dependedRootComponentGraph = getDependedRootComponentGraph(model); - ArrayList resources = determineResourceOrder(graph, dependedRootComponentGraph); - TypeDeclaration mainComponent = new TypeDeclaration(mainTypeName); - CompilationUnit mainCU = new CompilationUnit(mainComponent); - mainCU.addImport(new ImportDeclaration("java.util.*")); - codes.add(mainCU); - - // Declare the constructor of the main type. - MethodDeclaration mainConstructor = new MethodDeclaration(mainTypeName, true); - mainComponent.addMethod(mainConstructor); - - // For each resource node. - for (ResourceNode resourceNode: resources) { - TypeDeclaration component = null; - Set depends = new HashSet<>(); - Set refs = new HashSet<>(); - if (generatesComponent(resourceNode.getResourceHierarchy())) { - boolean f = false; - String resourceName = getComponentName(resourceNode.getResourceHierarchy()); - - component = resourceComponents.get(resourceNode.getResourceHierarchy()); - if (component == null) { - // Add compilation unit for each resource. - component = new TypeDeclaration(resourceName); - resourceComponents.put(resourceNode.getResourceHierarchy(), component); - CompilationUnit cu = new CompilationUnit(component); - cu.addImport(new ImportDeclaration("java.util.*")); - codes.add(cu); - - // Declare the field to refer to each resource in the main type. - if (resourceNode.getResourceHierarchy().getParent() == null) { - // For a root resource - String fieldInitializer = "new " + resourceName + "("; - for (Edge resToCh: resourceNode.getOutEdges()) { - DataFlowEdge re = (DataFlowEdge) resToCh; - if (((PushPullAttribute) re.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { - for (Edge chToRes: re.getDestination().getOutEdges()) { - ResourceHierarchy dstRes = ((ResourceNode) chToRes.getDestination()).getResourceHierarchy(); - String resName = getComponentName(dstRes); - depends.add(dstRes); - fieldInitializer += toVariableName(resName) + ","; - f = true; - } - } - } - for (Edge chToRes : resourceNode.getInEdges()) { - for (Edge resToCh: chToRes.getSource().getInEdges()) { - DataFlowEdge re = (DataFlowEdge) resToCh; - ResourceHierarchy srcRes = ((ResourceNode) re.getSource()).getResourceHierarchy(); - String resName = getComponentName(srcRes); - if (((PushPullAttribute) re.getAttribute()).getSelectedOption() != PushPullValue.PUSH) { - depends.add(srcRes); - fieldInitializer += toVariableName(resName) + ","; - f = true; - } else { - ChannelNode cn = (ChannelNode) re.getDestination(); - if (cn.getIndegree() > 1 - || (cn.getIndegree() == 1 && cn.getChannel().getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { - // Declare a field to cache the state of the source resource in the type of the destination resource. - ResourceHierarchy cacheRes = ((ResourceNode) re.getSource()).getResourceHierarchy(); - component.addField(new FieldDeclaration( - cacheRes.getResourceStateType(), cacheRes.getResourceName(), getInitializer(cacheRes))); - } - } - } - } - for (ResourceHierarchy dependedRes: dependedRootComponentGraph.keySet()) { - for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(dependedRes)) { - if (resourceNode.getResourceHierarchy().equals(dependingRes)) { - // Declare a field to refer to outside resources. - depends.add(dependedRes); - String resName = getComponentName(dependedRes); - fieldInitializer += toVariableName(resName) + ","; - f = true; - } - } - } - for (Channel ch : model.getChannels()) { - DataTransferChannel c = (DataTransferChannel) ch; - if (resourceNode.getOutSideResource(c) != null) { - for (ResourcePath res: c.getReferenceResources()) { - if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) { - refs.add(res); - String refResName = res.getLeafResourceName(); - fieldInitializer += toVariableName(refResName) + ","; - f = true; - } - } - } - } - if (f) fieldInitializer = fieldInitializer.substring(0, fieldInitializer.length() - 1); - fieldInitializer += ")"; - FieldDeclaration field = new FieldDeclaration(new Type(resourceName, resourceName), resourceNode.getResourceName()); - mainComponent.addField(field); - Block mainConstructorBody = mainConstructor.getBody(); - if (mainConstructorBody == null) { - mainConstructorBody = new Block(); - mainConstructor.setBody(mainConstructorBody); - } - mainConstructorBody.addStatement(resourceNode.getResourceName() + " = " + fieldInitializer + ";"); - } - - // Declare the field to store the state in the type of each resource. - if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { - ResourceHierarchy res = resourceNode.getResourceHierarchy(); - Set children = res.getChildren(); - if (children == null || children.size() == 0) { - // leaf resource. - Type fieldType = getImplStateType(res); - component.addField(new FieldDeclaration(fieldType, "value", getInitializer(res))); - } else { - ResourceHierarchy child = children.iterator().next(); - if (children.size() == 1 && child.getNumParameters() > 0) { - // map or list. - component.addField(new FieldDeclaration(getImplStateType(res), "value", getInitializer(res))); - } else { - // class - for (ResourceHierarchy c: children) { - String childTypeName = getComponentName(c); - Type childType = null; - if (generatesComponent(c)) { - // The child has a component. - childType = new Type(childTypeName, childTypeName); - String fieldName = toVariableName(childTypeName); - component.addField(new FieldDeclaration(childType, fieldName, "new " + childTypeName + "()")); - } - } - } - } - } - - // Declare the getter method to obtain the resource state in this component. - MethodDeclaration stateGetter = new MethodDeclaration("getValue", getImplStateType(resourceNode.getResourceHierarchy())); - component.addMethod(stateGetter); - - // Declare the accessor method in the main type to call the getter method. - declareAccessorMethodInMainComponent(resourceNode, mainComponent); - } - if (component != null) { - // (#1) Declare the getter methods in this resource to obtain descendant resources. (complementary to #2) - Set descendants = descendantGetters.get(resourceNode.getResourceHierarchy()); - if (descendants == null) { - descendants = new HashSet<>(); - descendantGetters.put(resourceNode.getResourceHierarchy(), descendants); - } - for (ResourceNode child: resourceNode.getChildren()) { - // 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)); - } - 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); - } - } - } - - // Declare the state field and reference fields in the parent component. - if (component == null) { - // Declare reference fields for push/pull data transfer. - boolean noPullTransfer = true; - for (Edge chToRes : resourceNode.getInEdges()) { - for (Edge resToCh: chToRes.getSource().getInEdges()) { - DataFlowEdge re = (DataFlowEdge) resToCh; - DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); - ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(ch); - // Check if the input resource is outside of the channel scope. - boolean outsideInputResource = false; - for (ChannelMember cm: ch.getInputChannelMembers()) { - if (cm.getResource().equals(srcRes) && cm.isOutside()) { - outsideInputResource = true; // Regarded as pull transfer. - break; - } - } - // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = false; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (resourceNode.getInSideResources().contains(cm.getResource()) && cm.isOutside()) { - outsideOutputResource = true; // Regarded as push transfer. - break; - } - } - if ((((PushPullAttribute) re.getAttribute()).getSelectedOption() != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { - noPullTransfer = false; - } - } - } - // Declare the state field in the parent component. - ResourceHierarchy res = resourceNode.getResourceHierarchy(); - if (((StoreAttribute) resourceNode.getAttribute()).isStored() && noPullTransfer && res.getNumParameters() == 0) { - String resName = getComponentName(res); - FieldDeclaration stateField = new FieldDeclaration(res.getResourceStateType(), toVariableName(resName)); - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), stateField)); - constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), new VariableDeclaration(res.getResourceStateType(), toVariableName(resName)))); - } - } - - // (#2) Declare the getter method to obtain the resource state in an ancestor component. (complementary to #1) - 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) { - ResourceHierarchy r = entry.getKey(); - MethodDeclaration m = entry.getValue(); - if (r == ancestorNode.getResourceHierarchy() && m.getName().equals(getterName) - && (m.getParameters() == null ? 0 : m.getParameters().size()) == getterParams.size()) { - bExists = true; - break; - } - } - if (!bExists) { - Type resType = getImplStateType(resourceNode.getResourceHierarchy()); - MethodDeclaration stateGetter = null; - if (getterParams.size() == 0) { - stateGetter = new MethodDeclaration(getterName, resType); - } else { - stateGetter = new MethodDeclaration(getterName, false, resType, getterParams); - } - getters.add(new AbstractMap.SimpleEntry<>(ancestorNode.getResourceHierarchy(), stateGetter)); - - // Declare the accessor method in the main type to call the getter method. - declareAccessorMethodInMainComponent(resourceNode, mainComponent); - } - } - - // Declare reference fields for push data transfer. - for (Edge resToCh : resourceNode.getOutEdges()) { - DataFlowEdge re = (DataFlowEdge) resToCh; - ChannelNode directDstChNode = (ChannelNode) re.getDestination(); - DataTransferChannel directDstCh = directDstChNode.getChannel(); - // Check if the input resource is outside of the channel scope. - boolean outsideInputResource = false; - for (ChannelMember cm: directDstCh.getInputChannelMembers()) { - if (cm.getResource().equals(resourceNode.getOutSideResource(directDstCh)) && cm.isOutside()) { - outsideInputResource = true; // Regarded as pull transfer. - break; - } - } - // Should take into account the channel hierarchy. - Set ancestorDstChannels = directDstChNode.getAncestors(); - Set descendantDstChannels = directDstChNode.getDescendants(); - Set outEdges = new HashSet<>(); - outEdges.addAll(directDstChNode.getOutEdges()); - for (ChannelNode ancestorDst: ancestorDstChannels) { - outEdges.addAll(ancestorDst.getOutEdges()); - } - for (ChannelNode descendantDst: descendantDstChannels) { - outEdges.addAll(descendantDst.getOutEdges()); - } - for (Edge chToRes: outEdges) { - ResourceHierarchy dstRes = ((ResourceNode) chToRes.getDestination()).getResourceHierarchy(); - ChannelNode chNode = (ChannelNode) chToRes.getSource(); - DataTransferChannel ch = chNode.getChannel(); - // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = false; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (((ResourceNode) chToRes.getDestination()).getInSideResources().contains(cm.getResource()) && cm.isOutside()) { - outsideOutputResource = true; // Regarded as push transfer. - break; - } - } - // Also take into account the channel hierarchy to determine push/pull transfer. - if (descendantDstChannels.contains(chNode)) { - outsideOutputResource = true; // Regarded as (broadcasting) push transfer. - } - if (ancestorDstChannels.contains(chNode)) { - outsideInputResource = true; // Regarded as (collecting) pull transfer. - } - if ((((PushPullAttribute) re.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { - // Declare a field to refer to the destination resource of push transfer. - if (!generatesComponent(dstRes)) { - dstRes = dstRes.getParent(); - } - String dstResName = getComponentName(dstRes); - depends.add(dstRes); - FieldDeclaration dstRefField = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); - VariableDeclaration dstRefVar = new VariableDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); - if (component != null) { - // A component is created for this resource. - if (resourceNode.getResourceHierarchy() != dstRes) { - component.addField(dstRefField); - if (!outsideOutputResource) { - constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), dstRefVar)); - } - } - } else { - // No component is created for this resource. - if (resourceNode.getParent().getResourceHierarchy() != dstRes) { - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRefField)); - if (!outsideOutputResource) { - constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRefVar)); - } - } - } - if (outsideOutputResource) { - // When the reference to the destination resource can vary. - if (dstRes.getParent() != null) { - // Reference to root resource. - ResourceHierarchy dstRootRes = dstRes.getRoot(); - String dstRootResName = getComponentName(dstRootRes); - FieldDeclaration dstRootRefField = new FieldDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName)); - VariableDeclaration dstRootRefVar = new VariableDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName)); - if (component != null) { - // A component is created for this resource. - component.addField(dstRootRefField); - constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), dstRootRefVar)); - } else { - // No component is created for this resource. - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRootRefField)); - constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRootRefVar)); - } - } - } - } - } - } - // Declare update methods called by other resources for push data transfer - // and reference fields for pull data transfer. - for (Edge chToRes : resourceNode.getInEdges()) { - ChannelNode directSrcChannel = (ChannelNode) chToRes.getSource(); - DataTransferChannel ch = directSrcChannel.getChannel(); - // Should take into account the channel hierarchy. - Set ancestorSrcChannels = directSrcChannel.getAncestors(); - Set descendantSrcChannels = directSrcChannel.getDescendants(); - Set inEdges = new HashSet<>(); - inEdges.addAll(directSrcChannel.getInEdges()); - for (ChannelNode ancestorSrc: ancestorSrcChannels) { - inEdges.addAll(ancestorSrc.getInEdges()); - } - for (ChannelNode descendantSrc: descendantSrcChannels) { - inEdges.addAll(descendantSrc.getInEdges()); - } - for (Edge resToCh: inEdges) { - // For each data transfer from srcResPath:ResourcePath to resourceNode:ResourceNode. - DataFlowEdge re = (DataFlowEdge) resToCh; - ChannelNode indirectSrcChNode = (ChannelNode) re.getDestination(); - DataTransferChannel indirectSrcCh = indirectSrcChNode.getChannel(); - ResourcePath srcResPath = ((ResourceNode) re.getSource()).getOutSideResource(indirectSrcCh); - // Check if the input resource is outside of the channel scope. - boolean outsideInputResource = false; - for (ChannelMember cm: indirectSrcCh.getInputChannelMembers()) { - if (cm.getResource().equals(srcResPath) && cm.isOutside()) { - outsideInputResource = true; // Regarded as pull transfer. - break; - } - } - // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = false; - ChannelMember out = null; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (resourceNode.getInSideResources().contains(cm.getResource())) { - out = cm; - if (cm.isOutside()) { - outsideOutputResource = true; // Regarded as push transfer. - break; - } - } - } - // Also take into account the channel hierarchy to determine push/pull transfer. - if (ancestorSrcChannels.contains(indirectSrcChNode)) { - outsideOutputResource = true; // Regarded as (broadcasting) push transfer. - } - if (descendantSrcChannels.contains(indirectSrcChNode)) { - outsideInputResource = true; // Regarded as (collecting) pull transfer. - } - String srcResName = getComponentName(srcResPath.getResourceHierarchy()); - ResourcePath srcRes2 = srcResPath; - String srcResName2 = srcResName; - if (!generatesComponent(srcResPath.getResourceHierarchy())) { - srcRes2 = srcResPath.getParent(); - srcResName2 = getComponentName(srcRes2.getResourceHierarchy()); - } - if ((((PushPullAttribute) re.getAttribute()).getSelectedOption() != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { - // Declare a field to refer to the source resource of pull transfer. - depends.add(srcRes2.getResourceHierarchy()); - FieldDeclaration srcRefField = new FieldDeclaration(new Type(srcResName2, srcResName2), toVariableName(srcResName2)); - VariableDeclaration srcRefVar = new VariableDeclaration(new Type(srcResName2, srcResName2), toVariableName(srcResName2)); - if (component != null) { - // A component is created for this resource. - if (resourceNode.getResourceHierarchy() != srcRes2.getResourceHierarchy()) { - component.addField(srcRefField); - if (!outsideInputResource) { - constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), srcRefVar)); - } - } - } else { - // No component is created for this resource. - if (resourceNode.getParent().getResourceHierarchy() != srcRes2.getResourceHierarchy()) { - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRefField)); - if (!outsideInputResource) { - constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRefVar)); - } - } - } - if (outsideInputResource) { - // When the reference to the source resource can vary. - if (srcRes2.getParent() != null) { - // Reference to its root resource. - ResourcePath srcRootRes = srcRes2.getRoot(); - String srcRootResName = getComponentName(srcRootRes.getResourceHierarchy()); - FieldDeclaration srcRootRefField = new FieldDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName)); - VariableDeclaration srcRootRefVar = new VariableDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName)); - if (component != null) { - // A component is created for this resource. - component.addField(srcRootRefField); - constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), srcRootRefVar)); - } else { - // No component is created for this resource. - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRootRefField)); - constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRootRefVar)); - } - } - } - } else { - // Declare an update method in the type of the destination resource. - ArrayList params = new ArrayList<>(); - int v = 1; - for (Expression exp: out.getResource().getPathParams()) { - if (exp instanceof Variable) { - Variable pathVar = (Variable) exp; - String varName = "self" + (v > 1 ? v : ""); - VariableDeclaration pathParam = new VariableDeclaration(pathVar.getType(), varName); - params.add(pathParam); // A path parameter to identify the self resource. - } else if (exp instanceof Term) { - Term pathVar = (Term) exp; - String varName = "self" + (v > 1 ? v : ""); - VariableDeclaration pathParam = new VariableDeclaration(pathVar.getType(), varName); - params.add(pathParam); // A path parameter to identify the self resource. - } - v++; - } - for (Selector selector: ch.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - VariableDeclaration chParam = new VariableDeclaration(selVar.getType(), selVar.getName()); - params.add(chParam); // A channel parameter to specify the context of the collaboration. - } - } - params.add(new VariableDeclaration(srcResPath.getResourceStateType(), toVariableName(getComponentName(srcResPath.getResourceHierarchy())))); // The state of the source resource to carry the data-flow. - for (ResourcePath ref: ch.getReferenceResources()) { - if (!ref.equals(resourceNode.getInSideResource(ch))) { - params.add(new VariableDeclaration(ref.getResourceStateType(), toVariableName(getComponentName(ref.getResourceHierarchy())))); - } - } - MethodDeclaration update = null; - if (component != null) { - // A component is created for this resource. - update = new MethodDeclaration("updateFrom" + srcResName, false, typeVoid, params); - component.addMethod(update); - } else { - // No component is created for this resource. - String resourceName = getComponentName(resourceNode.getResourceHierarchy()); - String updateMethodName = "update" + resourceName + "From" + srcResName; - Map nameToMethod = updates.get(resourceNode.getParent().getResourceHierarchy()); - if (nameToMethod == null) { - nameToMethod = new HashMap<>(); - updates.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod); - } - if (nameToMethod.get(updateMethodName) == null) { - update = new MethodDeclaration(updateMethodName, false, typeVoid, params); - nameToMethod.put(updateMethodName, update); - } - } - } - } - } - // Declare a field to refer to outside resources. - if (resourceNode.getParent() == null) { - for (ResourceHierarchy dependedRes: dependedRootComponentGraph.keySet()) { - for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(dependedRes)) { - if (resourceNode.getResourceHierarchy().equals(dependingRes)) { - // Declare a field to refer to outside resources. - depends.add(dependedRes); - String resName = getComponentName(dependedRes); - FieldDeclaration refField = new FieldDeclaration(new Type(resName, resName), toVariableName(resName)); - VariableDeclaration refVar = new VariableDeclaration(new Type(resName, resName), toVariableName(resName)); - if (component != null) { - // A component is created for this resource. - boolean existsField = false; - for (FieldDeclaration field: component.getFields()) { - if (field.getName().equals(refVar.getName())) { - existsField = true; - break; - } - } - if (!existsField) { - component.addField(refField); - } - constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), refVar)); - } else { - // No component is created for this resource. - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refField)); - constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refVar)); - } - } - } - } - } - // Declare a field to refer to the reference resource. - for (Channel ch : model.getChannels()) { - DataTransferChannel c = (DataTransferChannel) ch; - if (resourceNode.getOutSideResource(c) != null) { - for (ResourcePath res: c.getReferenceResources()) { - if (!refs.contains(res) && !depends.contains(res.getResourceHierarchy())) { - refs.add(res); - String refResName = getComponentName(res.getResourceHierarchy()); - FieldDeclaration refResField = new FieldDeclaration(new Type(refResName, refResName), res.getLeafResourceName()); - VariableDeclaration refResVar = new VariableDeclaration(new Type(refResName, refResName), res.getLeafResourceName()); - if (component != null) { - // A component is created for this resource. - component.addField(refResField); - constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy(), refResVar)); - } else { - // No component is created for this resource. - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refResField)); - constructorParams.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refResVar)); - } - } - } - } - } - - // Declare the input method in this component and the main component. - for (Channel ch : model.getInputChannels()) { - for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) { - if (resourceNode.getInSideResources().contains(cm.getResource())) { - Expression message = cm.getStateTransition().getMessageExpression(); - if (message instanceof Term) { - // In each resource. - ArrayList resInputParams = new ArrayList<>(); - ArrayList mainInputParams = new ArrayList<>(); - // The path parameters are not to be passed to the input method of each resource (resInputParams) - // because they are always equal to either channel selectors or message parameters. - - // Channel parameters to specify the context of the collaboration. - int v = 1; - for (Selector selector: ch.getSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - resInputParams.add(new VariableDeclaration(selVar.getType(), selVar.getName())); - mainInputParams.add(new VariableDeclaration(selVar.getType(), selVar.getName())); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); - resInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); - mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; - } - if (ch.getParent() != null) { - for (Selector selector: ch.getParent().getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - mainInputParams.add(new VariableDeclaration(selVar.getType(), selVar.getName())); - } else if (selector.getExpression() instanceof Term) { - Term var = (Term) selector.getExpression(); - mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; - } - } - // Message parameters to carry the data-flows. - for (Map.Entry varEnt: message.getVariables().entrySet()) { - Variable var = varEnt.getValue(); - String refVarName = null; - for (ChannelMember refCm: ((DataTransferChannel) ch).getReferenceChannelMembers()) { - Expression varExp = refCm.getStateTransition().getMessageExpression().getSubTerm(varEnt.getKey()); - if (varExp != null && varExp instanceof Variable) { - if (refCm.getStateTransition().getCurStateExpression().contains(varExp)) { - refVarName = refCm.getResource().getLeafResourceName(); - break; - } - } - } - if (refVarName != null) { - // var has come from a reference resource. - resInputParams.add(new VariableDeclaration(var.getType(), refVarName)); - } else { - // var has not come from a reference resource. - resInputParams.add(new VariableDeclaration(var.getType(), var.getName())); - boolean bExists = false; - for (VariableDeclaration mainParam: mainInputParams) { - if (mainParam.getName().equals(var.getName()) ) { - bExists = true; - break; - } - } - if (!bExists) { - mainInputParams.add(new VariableDeclaration(var.getType(), var.getName())); - } - } - } - String inputMethodName = ((Term) message).getSymbol().getImplName(); - if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) { - inputMethodName += "For" + getComponentName(cm.getResource().getResourceHierarchy()); - } - MethodDeclaration input = new MethodDeclaration(inputMethodName, false, typeVoid, resInputParams); - if (component != null) { - // A component is created for this resource. - component.addMethod(input); - } else { - // No component is created for this resource. - Map nameToMethod = inputs.get(resourceNode.getParent().getResourceHierarchy()); - if (nameToMethod == null) { - nameToMethod = new HashMap<>(); - inputs.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod); - } - if (nameToMethod.get(inputMethodName) == null) { - nameToMethod.put(inputMethodName, input); - } - } - - // In the main type. - String messageSymbol = ((Term) message).getSymbol().getImplName(); - input = getMethod(mainComponent, messageSymbol, mainInputParams); - if (input == null) { - input = new MethodDeclaration(messageSymbol, false, typeVoid, mainInputParams); - mainComponent.addMethod(input); - } else { - // Add type to a parameter without type. - for (VariableDeclaration param: input.getParameters()) { - if (param.getType() == null) { - for (VariableDeclaration p: mainInputParams) { - if (param.getName().equals(p.getName()) && p.getType() != null) { - param.setType(p.getType()); - } - } - } - } - } - } else if (message instanceof Variable) { - // In each resource. - ArrayList resInputParams = new ArrayList<>(); - ArrayList mainInputParams = new ArrayList<>(); - int v = 1; - if (cm.getResource().getLastParam() != null) { - Expression param = cm.getResource().getLastParam(); - if (param instanceof Variable) { - Variable var = (Variable) param; - resInputParams.add(new VariableDeclaration(var.getType(), var.getName())); - mainInputParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (param instanceof Term) { - Term var = (Term) param; - resInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); - mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; - } - if (cm.getResource().getParent() != null) { - for (Expression param: cm.getResource().getParent().getPathParams()) { - if (param instanceof Variable) { - Variable var = (Variable) param; - mainInputParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (param instanceof Term) { - Term var = (Term) param; - mainInputParams.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; - } - } - String inputMethodName = ((Variable) message).getName(); - if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) { - inputMethodName += "For" + getComponentName(cm.getResource().getResourceHierarchy()); - } - MethodDeclaration input = null; - if (resInputParams.size() > 0) { - input = new MethodDeclaration(inputMethodName, false, typeVoid, resInputParams); - } else { - input = new MethodDeclaration(inputMethodName, false, typeVoid, null); - } - if (component != null) { - // A component is created for this resource. - component.addMethod(input); - } else { - // No component is created for this resource. - Map nameToMethod = inputs.get(resourceNode.getParent().getResourceHierarchy()); - if (nameToMethod == null) { - nameToMethod = new HashMap<>(); - inputs.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod); - } - if (nameToMethod.get(inputMethodName) == null) { - nameToMethod.put(inputMethodName, input); - } - } - - // In the main type. - String messageSymbol = ((Variable) message).getName(); - input = getMethod(mainComponent, messageSymbol, mainInputParams); - if (input == null) { - if (mainInputParams.size() > 0) { - input = new MethodDeclaration(messageSymbol, false, typeVoid, mainInputParams); - } else { - input = new MethodDeclaration(messageSymbol, false, typeVoid, null); - } - mainComponent.addMethod(input); - } - } - } - } - } - } - - // Add leaf getter methods to the parent components. - for (Map.Entry entry: getters) { - resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); - } - - // Add leaf update methods to the parent components. - for (Map.Entry> entry: updates.entrySet()) { - for (MethodDeclaration update: entry.getValue().values()) { - resourceComponents.get(entry.getKey()).addMethod(update); - } - } - - // Add leaf input methods to the parent components. - for (Map.Entry> entry: inputs.entrySet()) { - for (MethodDeclaration input: entry.getValue().values()) { - resourceComponents.get(entry.getKey()).addMethod(input); - } - } - - // Add leaf reference fields to the parent components. - for (Map.Entry entry: fields) { - boolean existsField = false; - for (FieldDeclaration field: resourceComponents.get(entry.getKey()).getFields()) { - if (field.getName().equals(entry.getValue().getName())) { - existsField = true; - break; - } - } - if (!existsField) { - resourceComponents.get(entry.getKey()).addField(entry.getValue()); - } - } - - // Add constructor parameters to the ancestor components. - for (ResourceNode root: graph.getRootResourceNodes()) { - addConstructorParameters(root.getResourceHierarchy(), resourceComponents, resourceConstructors, constructorParams); - } - - // Declare the Pair class. - boolean isCreatedPair = false; - for (ResourceNode rn : resources) { - if (isCreatedPair) continue; - if (rn.getResourceStateType() != null && model.getType("Pair").isAncestorOf(rn.getResourceStateType())) { - TypeDeclaration type = new TypeDeclaration("Pair"); - type.addField(new FieldDeclaration(new Type("Double", "T"), "left")); - type.addField(new FieldDeclaration(new Type("Double", "T"), "right")); - - MethodDeclaration constructor = new MethodDeclaration("Pair", true); - constructor.addParameter(new VariableDeclaration(new Type("Double", "T"), "left")); - constructor.addParameter(new VariableDeclaration(new Type("Double", "T"), "right")); - Block block = new Block(); - block.addStatement("this.left = left;"); - block.addStatement("this.right = right;"); - constructor.setBody(block); - type.addMethod(constructor); - - for(FieldDeclaration field : type.getFields()) { - MethodDeclaration getter = new MethodDeclaration( - "get" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1), - new Type("Double","T")); - getter.setBody(new Block()); - getter.getBody().addStatement("return " + field.getName() + ";"); - type.addMethod(getter); - } - - CompilationUnit cu = new CompilationUnit(type); - cu.addImport(new ImportDeclaration("java.util.*")); - codes.add(cu); - - isCreatedPair = true; - } - } - -// HashSet tmps = new HashSet<>(); -// HashSet cont = new HashSet<>(); -// for (MethodDeclaration method : mainType.getMethods()) { -// if (!tmps.contains(method.getName())) -// tmps.add(method.getName()); -// else -// cont.add(method.getName()); -// } -// for (MethodDeclaration method : mainType.getMethods()) { -// if (cont.contains(method.getName())) { -// method.setName(method.getName() + method.getParameters().get(0).getName().substring(0, 1).toUpperCase() -// + method.getParameters().get(0).getName().substring(1)); -// } -// } - return codes; - } - - private static Map> getDependedRootComponentGraph(DataTransferModel model) { - Map> dependedComponentGraph = new HashMap<>(); - for (Channel ch: model.getChannels()) { - Set inRes = new HashSet<>(); - Set outRes = new HashSet<>(); - getDependedRootComponentGraphSub(ch, inRes, outRes, true); - if (outRes.size() > 0 && inRes.size() > 0) { - for (ResourceHierarchy out: outRes) { - for (ResourceHierarchy in: inRes) { - Set dependings = dependedComponentGraph.get(out.getRoot()); - if (dependings == null) { - dependings = new HashSet<>(); - dependedComponentGraph.put(out.getRoot(), dependings); - } - if (!out.getRoot().equals(in.getRoot())) { - dependings.add(in.getRoot()); - } - } - } - } - } - return dependedComponentGraph; - } - - private static void getDependedRootComponentGraphSub(Channel ch, Set inRes, Set outRes, boolean isRoot) { - DataTransferChannel dtCh = (DataTransferChannel) ch; - for (ChannelMember cm: dtCh.getChannelMembers()) { - if (!isRoot && !cm.isOutside()) { - outRes.add(cm.getResource().getResourceHierarchy()); // dependency to a descendant channel resource. - } - if (cm.isOutside()) { - outRes.add(cm.getResource().getResourceHierarchy()); // dependency to an outside resource. - } else { - inRes.add(cm.getResource().getResourceHierarchy()); // dependency from an inside resource. - } - } - for (Channel childCh: ch.getChildren()) { - getDependedRootComponentGraphSub(childCh, inRes, outRes, false); - } - } - - private static ArrayList determineResourceOrder(DataFlowGraph graph, Map> dependedRootComponentGraph) { - ArrayList resources = new ArrayList<>(); - Set visited = new HashSet<>(); - for (Node n : graph.getResourceNodes()) { - ResourceNode resNode = (ResourceNode) n; - topologicalSort(resNode, graph, dependedRootComponentGraph, visited, resources); - } - return resources; - } - - static private void topologicalSort(ResourceNode curResNode, DataFlowGraph graph, Map> dependedRootComponentGraph, Set visited, List orderedList) { - if (visited.contains(curResNode)) return; - visited.add(curResNode); - // For each incoming PUSH transfer. - for (Edge chToRes: curResNode.getInEdges()) { - for (Edge resToCh: chToRes.getSource().getInEdges()) { - DataFlowEdge re = (DataFlowEdge) resToCh; - if (((PushPullAttribute) re.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { - topologicalSort((ResourceNode) re.getSource(), graph, dependedRootComponentGraph, visited, orderedList); - } - } - } - // For each outgoing PULL transfer. - for (Edge resToCh: curResNode.getOutEdges()) { - DataFlowEdge de = (DataFlowEdge) resToCh; - if (((PushPullAttribute) de.getAttribute()).getSelectedOption() != PushPullValue.PUSH) { - for (Edge chToRes : resToCh.getDestination().getOutEdges()) { - topologicalSort((ResourceNode) chToRes.getDestination(), graph, dependedRootComponentGraph, visited, orderedList); - } - } - } - // For each depending root node. - if (dependedRootComponentGraph.get(curResNode.getResourceHierarchy()) != null) { - for (ResourceHierarchy dependingRes: dependedRootComponentGraph.get(curResNode.getResourceHierarchy())) { - for (ResourceNode root: graph.getRootResourceNodes()) { - if (root.getResourceHierarchy().equals(dependingRes)) { - topologicalSort(root, graph, dependedRootComponentGraph, visited, orderedList); - } - } - } - } - // For each reference resource. - for (Node n: graph.getResourceNodes()) { - ResourceNode resNode = (ResourceNode) n; - for (Edge resToCh : resNode.getOutEdges()) { - ChannelNode chNode = (ChannelNode) resToCh.getDestination(); - for (ChannelMember m: chNode.getChannel().getReferenceChannelMembers()) { - if (curResNode.getOutSideResources().contains(m.getResource())) { - topologicalSort(resNode, graph, dependedRootComponentGraph, visited, orderedList); - } - } - } - } - orderedList.add(0, curResNode); - } - - private static void declareAccessorMethodInMainComponent(ResourceNode resourceNode, TypeDeclaration mainComponent) { - MethodDeclaration getterAccessor = null; - List mainGetterParams = new ArrayList<>(); - int v = 1; - for (Expression param: resourceNode.getPrimaryResourcePath().getPathParams()) { - if (param instanceof Variable) { - Variable var = (Variable) param; - mainGetterParams.add(new VariableDeclaration(var.getType(), var.getName())); - } else if (param instanceof Term) { - Term var = (Term) param; - mainGetterParams.add(new VariableDeclaration(var.getType(), "v" + v)); - } - v++; - } - ResourcePath resPath = new ResourcePath(resourceNode.getPrimaryResourcePath()); - for (int i = 0; i < mainGetterParams.size(); i++) { - Parameter pathParam = new Parameter(mainGetterParams.get(i).getName()); - resPath.replacePathParam(i, pathParam, null); - } - if (mainGetterParams.size() > 0) { - getterAccessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()), - false, - getImplStateType(resourceNode.getResourceHierarchy()), - mainGetterParams); - } else { - getterAccessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()), - getImplStateType(resourceNode.getResourceHierarchy())); - } - getterAccessor.setBody(new Block()); - Expression getState = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(resPath, null); - getterAccessor.getBody().addStatement("return " + getState.toImplementation(new String[] {null}) + ";"); - mainComponent.addMethod(getterAccessor); - } - - private static List addConstructorParameters(ResourceHierarchy resource, - Map resourceComponents, - Map resourceConstructors, - List> constructorParams) { - List params = new ArrayList<>(); - for (ResourceHierarchy child: resource.getChildren()) { - params.addAll(addConstructorParameters(child, resourceComponents, resourceConstructors, constructorParams)); - } - for (Entry paramEnt: constructorParams) { - if (paramEnt.getKey().equals(resource)) { - params.add(paramEnt.getValue()); - } - } - if (params.size() > 0) { - MethodDeclaration constructor = resourceConstructors.get(resource); - if (constructor == null) { - if (resourceComponents.get(resource) != null) { - String resourceName = getComponentName(resource); - constructor = new MethodDeclaration(resourceName, true); - Block body = new Block(); - constructor.setBody(body); - resourceComponents.get(resource).addMethod(constructor); - resourceConstructors.put(resource, constructor); - } - } - if (constructor != null) { - for (VariableDeclaration param: params) { - boolean existsParam = false; - if (constructor.getParameters() != null) { - for (VariableDeclaration constParam: constructor.getParameters()) { - if (constParam.getName().equals(param.getName())) { - existsParam = true; - break; - } - } - } - if (!existsParam) { - constructor.addParameter(param); - constructor.getBody().addStatement("this." + toVariableName(param.getName()) + " = " + toVariableName(param.getName()) + ";"); - } - } - } - } - if (resource.getNumParameters() > 0) params.clear(); - return params; - } - - private static String getInitializer(ResourceHierarchy res) { - Type stateType = res.getResourceStateType(); - String initializer = null; - if (res.getInitialValue() != null) { - initializer = res.getInitialValue().toImplementation(new String[] {""}); - } else if (stateType != null) { - initializer = DataConstraintModel.getDefaultValue(stateType); - } - return initializer; - } - - static public ArrayList getCodes(ArrayList codeTree) { - ArrayList codes = new ArrayList<>(); - for (TypeDeclaration type : codeTree) { - codes.add("public class " + type.getTypeName() + "{"); - for (FieldDeclaration field : type.getFields()) { - if (type.getTypeName() != mainTypeName) { - String cons = "\t" + "private " + field.getType().getInterfaceTypeName() + " " - + field.getName(); - if (DataConstraintModel.isListType(field.getType())) - cons += " = new ArrayList<>()"; - cons += ";"; - codes.add(cons); - } else { - String cons = "\t" + "private " + field.getType().getInterfaceTypeName() + " " - + field.getName() + " = new " + field.getType().getTypeName() + "("; - cons += ");"; - codes.add(cons); - } - } - codes.add(""); - for (MethodDeclaration method : type.getMethods()) { - String varstr = "\t" + "public " + method.getReturnType().getInterfaceTypeName() + " " - + method.getName() + "("; - if (method.getParameters() != null) { - for (VariableDeclaration var : method.getParameters()) { - varstr += var.getType().getInterfaceTypeName() + " " + var.getName() + ","; - } - if (!method.getParameters().isEmpty()) - varstr = varstr.substring(0, varstr.length() - 1); - } - if (method.getBody() != null) { - for (String str : method.getBody().getStatements()) { - codes.add("\t\t" + str + ";"); - } - } - codes.add(varstr + ")" + "{"); - codes.add("\t" + "}"); - codes.add(""); - } - codes.add("}"); - codes.add(""); - } - return codes; - } - - private static MethodDeclaration getMethod(TypeDeclaration type, String methodName, List params) { - for (MethodDeclaration m: type.getMethods()) { - if (m.getName().equals(methodName)) { - if (m.getParameters() == null && (params == null || params.size() == 0)) return m; - if (m.getParameters() != null && params != null && m.getParameters().size() == params.size()) { - boolean matchParams = true; - for (int i = 0; i < m.getParameters().size(); i++) { - if (!m.getParameters().get(i).getType().equals(params.get(i).getType())) { - matchParams = false; - break; - } - } - if (matchParams) return m; - } - } - } - return null; - } - - static public IResourceStateAccessor pushAccessor = new IResourceStateAccessor() { - @Override - public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { - ResourcePath targetRes = target.getResource(); - ResourcePath fromRes = from.getResource(); - if (targetRes.equals(fromRes)) { - return new Field("value", - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - // use the cached value as the current state - return new Field(toVariableName(getComponentName(targetRes.getResourceHierarchy())), - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - - @Override - public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { - ResourcePath targetRes = target.getResource(); - return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - - @Override - public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { - if (fromRes != null && targetRes.equals(fromRes)) { - return new Field("value", - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - // for reference channel member - return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - }; - - static public IResourceStateAccessor pullAccessor = new IResourceStateAccessor() { - @Override - public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { - ResourcePath targetRes = target.getResource(); - if (from != null) { - ResourcePath fromRes = from.getResource(); - if (!target.isOutside()) { - return getDirectStateAccessorFor(targetRes, fromRes); - } - Term getter = null; - String targetComponentName = getComponentName(targetRes.getResourceHierarchy()); - if (generatesComponent(targetRes.getResourceHierarchy())) { - getter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); - getter.addChild(new Field(toVariableName(targetComponentName), targetRes.getResourceStateType())); - } else { - String parentName = toVariableName(getComponentName(targetRes.getResourceHierarchy().getParent())); - Type parentType = targetRes.getResourceHierarchy().getParent().getResourceStateType(); - getter = new Term(new Symbol("get" + targetComponentName, 1, Symbol.Type.METHOD)); - getter.addChild(new Field(parentName, parentType)); - } - return getter; - } else { - return getDirectStateAccessorFor(targetRes, null); - } - } - - @Override - public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { - ResourcePath targetRes = target.getResource(); - if (from != null) { - ResourcePath fromRes = from.getResource(); - if (!target.isOutside()) { - return getDirectStateAccessorFor(targetRes, fromRes); - } - // Get the next state by invoking a getter method. - Term getter = null; - String targetComponentName = getComponentName(targetRes.getResourceHierarchy()); - if (generatesComponent(targetRes.getResourceHierarchy())) { - getter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); - getter.addChild(new Field(toVariableName(targetComponentName), targetRes.getResourceStateType())); - } else { - String parentName = toVariableName(getComponentName(targetRes.getResourceHierarchy().getParent())); - Type parentType = targetRes.getResourceHierarchy().getParent().getResourceStateType(); - getter = new Term(new Symbol("get" + targetComponentName, 1, Symbol.Type.METHOD)); - getter.addChild(new Field(parentName, parentType)); - } - return getter; - } else { - return getDirectStateAccessorFor(targetRes, null); - } - } - - @Override - public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { - if (fromRes != null) { - if (targetRes.equals(fromRes)) { - return new Field("value", - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - // for reference channel member - if (fromRes.isAncestorOf(targetRes)) { - Stack pathStack = new Stack<>(); - ResourcePath curPath = targetRes; - do { - pathStack.push(curPath); - curPath = curPath.getParent(); - } while (!curPath.equals(fromRes)); - // iterate from the fromRes resource - return getRelativePath(targetRes, pathStack); - } - if (generatesComponent(targetRes.getResourceHierarchy())) { - Term getter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); - getter.addChild(new Field(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType())); - return getter; - } else { - return new Field(toVariableName(getComponentName(targetRes.getResourceHierarchy())), targetRes.getResourceStateType()); - } - } else { - // (#3) access from the outside of the hierarchy (must be kept consistent with #4) - Stack pathStack = new Stack<>(); - ResourcePath curPath = targetRes; - do { - pathStack.push(curPath); - curPath = curPath.getParent(); - } while (curPath != null); - // iterate from the root resource - return getRelativePath(targetRes, pathStack); - } - } - - private Expression getRelativePath(ResourcePath targetRes, Stack pathStack) { - ResourcePath curPath; - Term getter = null; - int arity = 2; - boolean doesChainInvocations = true; - while (!pathStack.empty()) { - curPath = pathStack.pop(); - String typeName = getComponentName(curPath.getResourceHierarchy()); - if (getter == null && generatesComponent(curPath.getResourceHierarchy())) { - // root resource - String fieldName = toVariableName(typeName); - getter = new Field(fieldName, new Type(typeName, typeName)); - } else { - 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) { - Expression param = curPath.getLastParam(); - if (param != null) { - newGetter.addChild(param); - newGetter.getSymbol().setArity(2); - } - } - getter = newGetter; - } else { - // add the last path parameter. - if (curPath.getResourceHierarchy().getNumParameters() > 0) { - Expression param = curPath.getLastParam(); - if (param != null) { - getter.getSymbol().setArity(arity); - getter.addChild(param); - } - } - } - arity = 2; - doesChainInvocations = true; - } else { - // to get a descendant resource directly. (e.g, .todos.{year}.{month}.{day}.{id} ==> .getTodos().getTodo(year, month, day, id)) - if (doesChainInvocations) { - Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD)); - newGetter.addChild(getter); - getter = newGetter; - doesChainInvocations = false; - } - if (curPath.getResourceHierarchy().getNumParameters() > 0) { - // may change the symbol name - getter.getSymbol().changeName("get" + typeName); - // add a path parameter. - Expression param = curPath.getLastParam(); - if (param != null) { - getter.getSymbol().setArity(arity); - getter.addChild(param); - arity++; - } - } - } - } - } - if (generatesComponent(targetRes.getResourceHierarchy())) { - Term newGetter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); - newGetter.addChild(getter); - getter = newGetter; - } - return getter; - } - }; - - static public IResourceStateAccessor refAccessor = new IResourceStateAccessor() { - @Override - public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { - ResourcePath targetRes = target.getResource(); - ResourcePath fromRes = from.getResource(); - if (targetRes.equals(fromRes)) { - return new Field("value", - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - // for reference channel member - return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - - @Override - public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { - ResourcePath targetRes = target.getResource(); - return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - - @Override - public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { - if (fromRes != null && targetRes.equals(fromRes)) { - return new Field("value", - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - // for reference channel member - return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - }; -} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java deleted file mode 100644 index 8d1fca4..0000000 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ /dev/null @@ -1,1472 +0,0 @@ -package generators; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Stack; -import java.util.Map.Entry; - -import code.ast.CompilationUnit; -import code.ast.MethodDeclaration; -import code.ast.TypeDeclaration; -import code.ast.VariableDeclaration; -import models.Edge; -import models.algebra.Constant; -import models.algebra.Expression; -import models.algebra.Field; -import models.algebra.InvalidMessage; -import models.algebra.Parameter; -import models.algebra.ParameterizedIdentifierIsFutureWork; -import models.algebra.Position; -import models.algebra.Symbol; -import models.algebra.Term; -import models.algebra.Type; -import models.algebra.UnificationFailed; -import models.algebra.ValueUndefined; -import models.algebra.Variable; -import models.dataConstraintModel.Channel; -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; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.DataTransferChannel; -import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; -import models.dataFlowModel.PushPullAttribute; -import models.dataFlowModel.PushPullValue; -import models.dataFlowModel.ChannelNode; -import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; -import models.dataFlowModel.DataFlowEdge; -import models.dataFlowModel.DataFlowGraph; -import models.dataFlowModel.ResourceNode; -import models.dataFlowModel.StoreAttribute; - -public class JavaMethodBodyGenerator { - public static ArrayList doGenerate(DataFlowGraph graph, DataTransferModel model, ArrayList codes) { - // Create a map from type names (lower case) to their types. - Map componentMap = new HashMap<>(); - for (CompilationUnit code: codes) { - for (TypeDeclaration component: code.types()) { - componentMap.put(component.getTypeName(), component); - } - } - - // Generate the body of each update or getter method. - try { - Map> referredResources = new HashMap<>(); - for (Edge e: graph.getEdges()) { - DataFlowEdge resToCh = (DataFlowEdge) e; - if (!resToCh.isChannelToResource()) { - PushPullAttribute pushPull = (PushPullAttribute) resToCh.getAttribute(); - ResourceNode src = (ResourceNode) resToCh.getSource(); - ChannelNode directDstChNode = (ChannelNode) resToCh.getDestination(); - DataTransferChannel directDstCh = directDstChNode.getChannel(); - // Should take into account the channel hierarchy. - Set ancestorDstChannels = directDstChNode.getAncestors(); - Set descendantDstChannels = directDstChNode.getDescendants(); - Set outEdges = new HashSet<>(); - outEdges.addAll(directDstChNode.getOutEdges()); - for (ChannelNode ancestorDst: ancestorDstChannels) { - outEdges.addAll(ancestorDst.getOutEdges()); - } - for (ChannelNode descendantDst: descendantDstChannels) { - outEdges.addAll(descendantDst.getOutEdges()); - } - for (Edge chToRes: outEdges) { - ResourceNode dst = (ResourceNode) chToRes.getDestination(); - String srcResourceName = JavaCodeGenerator.getComponentName(src.getResourceHierarchy()); - String dstResourceName = JavaCodeGenerator.getComponentName(dst.getResourceHierarchy()); - TypeDeclaration srcComponent = componentMap.get(srcResourceName); - TypeDeclaration dstComponent = componentMap.get(dstResourceName); - ChannelNode chNode = (ChannelNode) chToRes.getSource(); - DataTransferChannel ch = chNode.getChannel(); - for (ChannelMember out: ch.getOutputChannelMembers()) { - if (dst.getInSideResources().contains(out.getResource())) { - // Check if the input resource is outside of the channel scope. - boolean outsideInputResource = false; - for (ChannelMember cm: ch.getInputChannelMembers()) { - if (src.getOutSideResources().contains(cm.getResource()) && cm.isOutside()) { - outsideInputResource = true; // Regarded as pull transfer. - break; - } - } - // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = out.isOutside(); - // Take into account the channel hierarchy. - if (descendantDstChannels.contains(chNode)) { - outsideOutputResource = true; // Regarded as (broadcasting) push transfer. - } - if (ancestorDstChannels.contains(chNode)) { - outsideInputResource = true; // Regarded as (collecting) pull transfer. - } - if ((pushPull.getSelectedOption() == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { - // for push data transfer - MethodDeclaration update = null; - if (dstComponent == null) { - String dstParentResourceName = JavaCodeGenerator.getComponentName(dst.getResourceHierarchy().getParent()); - dstComponent = componentMap.get(dstParentResourceName); - update = getUpdateMethod(dstComponent, dstResourceName, srcResourceName); - } else { - update = getUpdateMethod(dstComponent, null, srcResourceName); - } - if (((StoreAttribute) dst.getAttribute()).isStored()) { - // update stored state of dst side resource (when every incoming edge is in push style) - Term unifiedMassage = null; - if (directDstCh != ch) { - unifiedMassage = directDstCh.fillOutsideResourcePaths(out, JavaCodeGenerator.pushAccessor, null).getValue(); - } - Expression updateExp = null; - if (ch.getReferenceChannelMembers().size() == 0) { - Term message = ch.fillOutsideResourcePaths(out, JavaCodeGenerator.pushAccessor, null).getValue(); - if (unifiedMassage == null) { - unifiedMassage = message; - } else { - unifiedMassage = (Term) unifiedMassage.unify(message); - } - updateExp = ch.deriveUpdateExpressionOf(out, unifiedMassage, JavaCodeGenerator.pushAccessor); - } else { - // if there exists one or more reference channel member. - HashMap inputResourceToStateAccessor = new HashMap<>(); - for (ChannelMember in: ch.getInputChannelMembers()) { - inputResourceToStateAccessor.put(in, JavaCodeGenerator.pushAccessor); - } - for (ChannelMember c: ch.getReferenceChannelMembers()) { - inputResourceToStateAccessor.put(c, JavaCodeGenerator.refAccessor); - } - Term message = ch.fillOutsideResourcePaths(out, JavaCodeGenerator.pushAccessor, inputResourceToStateAccessor).getValue(); - if (unifiedMassage == null) { - unifiedMassage = message; - } else { - unifiedMassage = (Term) unifiedMassage.unify(message); - } - updateExp = ch.deriveUpdateExpressionOf(out, unifiedMassage, JavaCodeGenerator.pushAccessor); - } - // 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 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); - int numOfOutResourcesWithTheSameHierarchy = 0; - for (ResourcePath outResPath: ch.getOutputResources()) { - if (outResPath.getResourceHierarchy().equals(outRes)) { - numOfOutResourcesWithTheSameHierarchy++; - } - } - String updateStatement = ""; - if (JavaCodeGenerator.generatesComponent(outRes)) { - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - updateStatement = sideEffects[0]; - if (updateStatement.endsWith("\n")) { - updateStatement = updateStatement.substring(0, updateStatement.length() - 1); - } - } else { - updateStatement = sideEffects[0] + "this.value = " + newState + ";"; - } - } else { - if (sideEffects[0] != null) { - updateStatement = sideEffects[0]; - updateStatement = updateStatement.replace(".value", "." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(outRes))); - if (updateStatement.endsWith("\n")) { - updateStatement = updateStatement.substring(0, updateStatement.length() - 1); - } - } - if (DataConstraintModel.typeList.isAncestorOf(outRes.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.set); - selector.addChild(new Field("value")); - selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newList = selector.toImplementation(sideEffects2); - updateStatement += sideEffects2[0]; - } else if (DataConstraintModel.typeMap.isAncestorOf(outRes.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.insert); - selector.addChild(new Field("value")); - selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newMap = selector.toImplementation(sideEffects2); - updateStatement += sideEffects2[0]; - } else if (!(updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect())) { - updateStatement += "this." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(outRes)) + " = " + newState + ";"; - } - } - // add an update statement of the state of dst side resource. - if (numOfOutResourcesWithTheSameHierarchy == 1) { - update.addFirstStatement(updateStatement); - } else { - Term conditions = null; - int v = 1; - Map>> resourcePaths = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pushAccessor); - for (Expression pathParam: out.getResource().getPathParams()) { - if (pathParam instanceof Variable) { - String selfParamName = ((Variable) pathParam).getName(); - Expression arg = null; - for (Selector selector: ch.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - if (selVar.getName().equals(selfParamName)) { - arg = selVar; - break; - } - } - } - if (arg == null) { - ResourcePath filledPath = resourcePaths.get(out).getKey(); - arg = filledPath.getPathParams().get(v - 1); - } - Term condition = new Term(DataConstraintModel.eq, new Expression[] { - new Parameter("self" + (v > 1 ? v : ""), DataConstraintModel.typeString), - arg}); - if (conditions == null) { - conditions = condition; - } else { - conditions = new Term(DataConstraintModel.and, new Expression[] { - conditions, - condition}); - } - } - v++; - } - String ifStatement = "if (" + conditions.toImplementation(new String[] {""})+ ") {\n"; - update.addFirstStatement(ifStatement + "\t" + updateStatement.replace("\n", "\n\t") + "\n}"); - } - } - // Calculate in-degree (PUSH transfer) of the destination resource. - int inDegree = 0; - Set inEdges = new HashSet<>(); - inEdges.addAll(chNode.getInEdges()); - for (ChannelNode ancestor: chNode.getAncestors()) { - inEdges.addAll(ancestor.getInEdges()); - } - for (ChannelNode descendant: chNode.getDescendants()) { - inEdges.addAll(descendant.getInEdges()); - } - for (Edge resToCh2: inEdges) { - DataFlowEdge df =(DataFlowEdge) resToCh2; - if (((PushPullAttribute) df.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { - inDegree++; - } - } - if (inDegree > 1 - || (inDegree == 1 && directDstCh.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { - // update a cache of src side resource (when incoming edges are multiple) - String cacheStatement = "this." + JavaCodeGenerator.toVariableName(srcResourceName) + " = " + JavaCodeGenerator.toVariableName(srcResourceName) + ";"; - if (update.getBody() == null || !update.getBody().getStatements().contains(cacheStatement)) { - update.addStatement(cacheStatement); - } - } - if (((StoreAttribute) dst.getAttribute()).isStored()) { - // returns the current state stored in a field. - MethodDeclaration getter = null; - if (JavaCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { - getter = getMethod(dstComponent, "getValue"); - } else { - getter = getGetterMethod(dstComponent, dstResourceName); - } - if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - Type resourceType = dst.getResourceStateType(); - if (dst.getResourceHierarchy().getNumParameters() == 0) { - if (JavaCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { - // dst has a component. - if (model.isPrimitiveType(resourceType)) { - getter.addStatement("return value;"); - } else { - // copy the current state to be returned as a 'value' - String implTypeName = resourceType.getImplementationTypeName(); - getter.addStatement("return new " + implTypeName + "(value);"); - } - } else { - // dst has no component. - String dstResName = JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(dst.getResourceHierarchy())); - if (model.isPrimitiveType(resourceType)) { - getter.addStatement("return " + dstResName + ";"); - } else { - // copy the current state to be returned as a 'value' - String implTypeName = resourceType.getImplementationTypeName(); - getter.addStatement("return new " + implTypeName + "(" + dstResName + ");"); - } - } - } else { - String[] sideEffects = new String[] {""}; - if (DataConstraintModel.typeList.isAncestorOf(dst.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.get); - selector.addChild(new Field("value")); - selector.addChild(dst.getSelectors().get(dst.getSelectors().size() - 1).getExpression()); - String curState = selector.toImplementation(sideEffects); - getter.addStatement(sideEffects[0] + "return " + curState + ";"); - } else if (DataConstraintModel.typeMap.isAncestorOf(dst.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.lookup); - selector.addChild(new Field("value")); - selector.addChild(dst.getSelectors().get(dst.getSelectors().size() - 1).getExpression()); - String curState = selector.toImplementation(sideEffects); - getter.addStatement(sideEffects[0] + "return " + curState + ";"); - } - } - } - } - // src side (for a chain of update method invocations) - ChannelMember in = null; - for (ChannelMember cm: directDstCh.getInputChannelMembers()) { - if (src.getOutSideResources().contains(cm.getResource())) { - in = cm; - break; - } - } - String srcResName = null; - if (srcComponent == null) { - String srcParentResourceName = JavaCodeGenerator.getComponentName(src.getResourceHierarchy().getParent()); - srcComponent = componentMap.get(srcParentResourceName); - srcResName = srcResourceName; - } - // For caller update methods - for (MethodDeclaration srcUpdate: getUpdateMethods(srcComponent, srcResName)) { - ResourcePath dstRes = out.getResource(); - // Get the value of reference member to call the update method. - String refParams = ""; - Set referredSet = referredResources.get(srcUpdate); - for (ChannelMember rc: ch.getReferenceChannelMembers()) { - ResourcePath ref = rc.getResource(); - if (referredSet == null) { - referredSet = new HashSet<>(); - referredResources.put(srcUpdate, referredSet); - } - if (!dst.getInSideResources().contains(ref)) { - String refVarName = JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(ref.getResourceHierarchy())); - if (!referredSet.contains(ref)) { - referredSet.add(ref); - ResourcePath srcRes = in.getResource(); - if (!JavaCodeGenerator.generatesComponent(srcRes.getResourceHierarchy())) { - srcRes = srcRes.getParent(); - } - Expression refGetter = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(ref, srcRes); - String[] sideEffects = new String[] {""}; - String refExp = refGetter.toImplementation(sideEffects); - String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); - srcUpdate.addStatement(sideEffects[0] + refTypeName + " " + refVarName + " = " + refExp + ";"); - } - refParams += ", " + refVarName; - } - } - // Update fields to refer to outside resources. - ResourcePath filledOutsideResourcePath = null; - Map>> resourcePaths = ch.fillOutsideResourcePaths(out, JavaCodeGenerator.pullAccessor); - if (resourcePaths != null && resourcePaths.size() > 0) { - for (ChannelMember outsideMember: resourcePaths.keySet()) { - ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); - if (out.equals(outsideMember)) { - filledOutsideResourcePath = outsidePath; - } - if (!JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { - outsidePath = outsidePath.getParent(); - } - String outsideResName = JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(outsidePath.getResourceHierarchy())); - Expression outsideExp = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(outsidePath, null); - if (JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { - outsideExp = ((Term) outsideExp).getChild(0); - } - if (outsideExp instanceof Field) { - outsideExp = new Variable(((Field) outsideExp).getSymbol().getName(), ((Field) outsideExp).getType()); - } else if (outsideExp instanceof Term) { - for (Entry fieldEnt: ((Term) outsideExp).getSubTerms(Field.class).entrySet()) { - Position pos = fieldEnt.getKey(); - Field field = fieldEnt.getValue(); - Variable var = new Variable(field.getSymbol().getName(), field.getType()); - ((Term) outsideExp).replaceSubTerm(pos, var); - } - } - String[] sideEffects = new String[] {""}; - String outsideAccessor = outsideExp.toImplementation(sideEffects); - srcUpdate.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. - } - } - // Values of path parameters to call the update method. - if (filledOutsideResourcePath == null) { - filledOutsideResourcePath = dstRes; - } - String pathParams = ""; - for (Expression pathParam: filledOutsideResourcePath.getPathParams()) { - if (pathParam instanceof Variable) { - Variable pathVar = (Variable) pathParam; - pathParams += pathVar.getName() + ", "; - } else if (pathParam instanceof Constant) { - Constant pathVar = (Constant) pathParam; - pathParams += pathVar.getSymbol().getName() + ", "; - } - } - // Values of channel parameters to call the update method. - String chParams = ""; - for (Selector selector: ch.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - chParams += selVar.getName() + ", "; - } - } - // Value of the source side (input side) resource. - String srcFieldName = "value"; - if (!JavaCodeGenerator.generatesComponent(src.getResourceHierarchy())) { - srcFieldName = JavaCodeGenerator.toVariableName(srcResourceName); - } - // Call the update method. - String updateMethodName = null; - if (JavaCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { - updateMethodName = "updateFrom" + srcResourceName; - } else { - updateMethodName = "update" + dstResourceName + "From" + srcResourceName; - } - if (!outsideOutputResource) { - // The destination resource is not outside. - if (srcComponent != dstComponent) { - srcUpdate.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); - } else { - srcUpdate.addStatement("this." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); - } - } else { - // Use the reference field to refer to outside destination resource. - srcUpdate.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); - } - if (descendantDstChannels.contains(chNode)) { - // For hierarchical channels (broadcasting push transfer). - if (ch.getSelectors() != null && ch.getSelectors().size() > 0) { - Expression selExp = ch.getSelectors().get(0).getExpression(); - Type selType = null; - String forVarName = null; - if (selExp instanceof Variable) { - selType = ((Variable) selExp).getType(); - forVarName = ((Variable) selExp).getName(); - ChannelMember insideChMem = null; - for (ChannelMember cm :ch.getInputChannelMembers()) { - if (!cm.isOutside()) { - insideChMem = cm; - break; - } - } - if (insideChMem == null) { - for (ChannelMember cm :ch.getReferenceChannelMembers()) { - if (!cm.isOutside()) { - insideChMem = cm; - break; - } - } - } - if (insideChMem == null) { - for (ChannelMember cm :ch.getOutputChannelMembers()) { - if (!cm.isOutside()) { - insideChMem = cm; - break; - } - } - } - ResourcePath insideResPath = insideChMem.getResource(); - while (insideResPath.getParent() != null && (insideResPath.getLastParam() == null || !insideResPath.getLastParam().equals(selExp))) { - insideResPath = insideResPath.getParent(); - } - insideResPath = insideResPath.getParent(); - if (insideResPath != null) { - String parent = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(insideResPath, src.getOutSideResource(directDstCh)).toImplementation(new String[] {""}); - if (selType.equals(DataConstraintModel.typeInt)) { - // make a for loop (for a list) for broadcasting. - srcUpdate.addFirstStatement("for (int " + forVarName + " = 0; " + forVarName +" < " + parent + ".size(); " + forVarName + "++) {"); - srcUpdate.addStatement("}"); - } else if (selType.equals(DataConstraintModel.typeString)) { - // make a for loop (for a map) for broadcasting. - srcUpdate.addFirstStatement("for (String " + forVarName + ": " + parent + ".keySet()) {"); - srcUpdate.addStatement("}"); - } - } - } else if (selExp instanceof Term) { - // not supported. - } - } - } - } - // For caller input methods - for (MethodDeclaration srcInput: getInputMethods(srcComponent, src, model)) { - ResourcePath dstRes = out.getResource(); - // Get the value of reference member to call the update method. - String refParams = ""; - Set referredSet = referredResources.get(srcInput); - for (ChannelMember rc: ch.getReferenceChannelMembers()) { - ResourcePath ref = rc.getResource(); - if (referredSet == null) { - referredSet = new HashSet<>(); - referredResources.put(srcInput, referredSet); - } - if (!dst.getInSideResources().contains(ref)) { - String refVarName = JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(ref.getResourceHierarchy())); - if (!referredSet.contains(ref)) { - referredSet.add(ref); - ResourcePath srcRes = in.getResource(); - if (!JavaCodeGenerator.generatesComponent(srcRes.getResourceHierarchy())) { - srcRes = srcRes.getParent(); - } - Expression refGetter = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(ref, srcRes); - String[] sideEffects = new String[] {""}; - String refExp = refGetter.toImplementation(sideEffects); - String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); - srcInput.addStatement(sideEffects[0] + refTypeName + " " + refVarName + " = " + refExp + ";"); - } - refParams += ", " + refVarName; - } - } - // Update fields to refer to outside resources. - ResourcePath filledOutsideResourcePath = null; - Map>> resourcePaths = ch.fillOutsideResourcePaths(out, JavaCodeGenerator.pullAccessor); - if (resourcePaths != null && resourcePaths.size() > 0) { - for (ChannelMember outsideMember: resourcePaths.keySet()) { - ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); - if (out.equals(outsideMember)) { - filledOutsideResourcePath = outsidePath; - } - if (!JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { - outsidePath = outsidePath.getParent(); - } - String outsideResName = JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(outsidePath.getResourceHierarchy())); - Expression outsideExp = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(outsidePath, null); - if (JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { - outsideExp = ((Term) outsideExp).getChild(0); - } - if (outsideExp instanceof Field) { - outsideExp = new Variable(((Field) outsideExp).getSymbol().getName(), ((Field) outsideExp).getType()); - } else if (outsideExp instanceof Term) { - for (Entry fieldEnt: ((Term) outsideExp).getSubTerms(Field.class).entrySet()) { - Position pos = fieldEnt.getKey(); - Field field = fieldEnt.getValue(); - Variable var = new Variable(field.getSymbol().getName(), field.getType()); - ((Term) outsideExp).replaceSubTerm(pos, var); - } - } - String[] sideEffects = new String[] {""}; - String outsideAccessor = outsideExp.toImplementation(sideEffects); - srcInput.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. - } - } - // Values of path parameters to call the update method. - if (filledOutsideResourcePath == null) { - filledOutsideResourcePath = dstRes; - } - String pathParams = ""; - for (Expression pathParam: filledOutsideResourcePath.getPathParams()) { - if (pathParam instanceof Variable) { - Variable pathVar = (Variable) pathParam; - pathParams += pathVar.getName() + ", "; - } else if (pathParam instanceof Constant) { - Constant pathVar = (Constant) pathParam; - pathParams += pathVar.getSymbol().getName() + ", "; - } - } - // Values of channel parameters to call the update method. - String chParams = ""; - for (Selector selector: ch.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - chParams += selVar.getName() + ", "; - } - } - // Call the update method. - String updateMethodName = null; - if (JavaCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { - updateMethodName = "updateFrom" + srcResourceName; - } else { - updateMethodName = "update" + dstResourceName + "From" + srcResourceName; - } - // Value of the source side (input side) resource. - String srcFieldName = "value"; - if (!JavaCodeGenerator.generatesComponent(src.getResourceHierarchy())) { - srcFieldName = JavaCodeGenerator.toVariableName(srcResourceName); - } - if (!outsideOutputResource) { - // The destination resource is not outside. - if (srcComponent != dstComponent) { - srcInput.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); - } else { - srcInput.addStatement("this." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); - } - } else { - // Use the reference field to refer to outside destination resource. - srcInput.addStatement("this." + JavaCodeGenerator.toVariableName(dstComponent.getTypeName()) + "." + updateMethodName + "(" + pathParams + chParams + srcFieldName + refParams + ");"); - } - if (descendantDstChannels.contains(chNode)) { - // For hierarchical channels (broadcasting push transfer). - if (ch.getSelectors() != null && ch.getSelectors().size() > 0) { - Expression selExp = ch.getSelectors().get(0).getExpression(); - Type selType = null; - String varName = null; - if (selExp instanceof Variable) { - selType = ((Variable) selExp).getType(); - varName = ((Variable) selExp).getName(); - ChannelMember insideChMem = null; - for (ChannelMember cm :ch.getInputChannelMembers()) { - if (!cm.isOutside()) { - insideChMem = cm; - break; - } - } - if (insideChMem == null) { - for (ChannelMember cm :ch.getReferenceChannelMembers()) { - if (!cm.isOutside()) { - insideChMem = cm; - break; - } - } - } - if (insideChMem == null) { - for (ChannelMember cm :ch.getOutputChannelMembers()) { - if (!cm.isOutside()) { - insideChMem = cm; - break; - } - } - } - ResourcePath insideResPath = insideChMem.getResource(); - while (insideResPath.getParent() != null && (insideResPath.getLastParam() == null || !insideResPath.getLastParam().equals(selExp))) { - insideResPath = insideResPath.getParent(); - } - insideResPath = insideResPath.getParent(); - if (insideResPath != null) { - String parent = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(insideResPath, src.getOutSideResource(directDstCh)).toImplementation(new String[] {""}); - if (selType.equals(DataConstraintModel.typeInt)) { - // make a for loop (for a list) for broadcasting. - srcInput.addFirstStatement("for (int " + varName + " = 0; " + varName +" < " + parent + ".size(); " + varName + "++) {"); - srcInput.addStatement("}"); - } else if (selType.equals(DataConstraintModel.typeString)) { - // make a for loop (for a map) for broadcasting. - srcInput.addFirstStatement("for (String " + varName + ": " + parent + ".keySet()) {"); - srcInput.addStatement("}"); - } - } - } else if (selExp instanceof Term) { - // not supported. - } - } - } - } - } else if ((pushPull.getSelectedOption() != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { - // for pull (or push/pull) data transfer - if (dstComponent == null) { - String dstParentResourceName = JavaCodeGenerator.getComponentName(dst.getResourceHierarchy().getParent()); - dstComponent = componentMap.get(dstParentResourceName); - } - MethodDeclaration getter = null; - if (JavaCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { - getter = getMethod(dstComponent, "getValue"); - } else { - getter = getGetterMethod(dstComponent, dstResourceName); - } - if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - // The first time to fill the getter method's body. - // Data transfer on the same channel hierarchy. - String[] sideEffects = new String[] {""}; - boolean isContainedPush = false; - Map inputResourceToStateAccessor = new HashMap<>(); - for (Edge chToRes2: dst.getInEdges()) { - DataTransferChannel ch2 = ((ChannelNode) chToRes2.getSource()).getChannel(); - for (Edge resToCh2: chToRes2.getSource().getInEdges()) { - DataFlowEdge dIn = (DataFlowEdge) resToCh2; - ChannelMember in = null; - for (ChannelMember cm: ch2.getInputChannelMembers()) { - if (((ResourceNode) dIn.getSource()).getOutSideResources().contains(cm.getResource())) { - in = cm; - break; - } - } - if (((PushPullAttribute) dIn.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { - isContainedPush = true; - inputResourceToStateAccessor.put(in, JavaCodeGenerator.pushAccessor); - } else { - inputResourceToStateAccessor.put(in, JavaCodeGenerator.pullAccessor); - } - } - } - // for reference channel members - for (ChannelMember c: ch.getReferenceChannelMembers()) { - inputResourceToStateAccessor.put(c, JavaCodeGenerator.pullAccessor); // by pull data transfer - } - Map.Entry>>, Term> resourcePathsAndMessage; - - // Construct the base message. - if (!isContainedPush) { - // All incoming edges are in PULL-style. - resourcePathsAndMessage = ch.fillOutsideResourcePaths(out, JavaCodeGenerator.pullAccessor, null); - } else { - // At least one incoming edge is in PUSH-style. - resourcePathsAndMessage = ch.fillOutsideResourcePaths(out, JavaCodeGenerator.pullAccessor, inputResourceToStateAccessor); - } - Map>> resourcePaths = resourcePathsAndMessage.getKey(); - Term messageTerm = resourcePathsAndMessage.getValue(); - // Data transfer from the descendant channel hierarchies. - Stack> channelItrStack = new Stack<>(); - DataTransferChannel curChannel = ch; - if (curChannel.getChildren() != null && curChannel.getChildren().size() > 0) { - // retrieve descendant channels recursively. - Iterator chItr = curChannel.getChildren().iterator(); - do { - if (!chItr.hasNext()) { - chItr = channelItrStack.pop(); - } else { - curChannel = (DataTransferChannel) chItr.next(); - // generate pull data transfers. - Set chMems = new HashSet<>(curChannel.getInputChannelMembers()); - chMems.addAll(curChannel.getReferenceChannelMembers()); - for (ChannelMember cm2: chMems) { - if (resourcePaths == null || !resourcePaths.keySet().contains(cm2)) { - // not a depending channel member. - ResourcePath src2 = cm2.getResource(); - Type srcResType2 = src2.getResourceStateType(); - String srcResName2 = JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(src2.getResourceHierarchy())); - String srcGetter = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(src2, dst.getInSideResource(curChannel)).toImplementation(new String[] {""}); - getter.addStatement(srcResType2.getInterfaceTypeName() + " " + srcResName2 + " = " + srcGetter + ";"); - } else { - // a depending channel member. - ResourcePath src2 = resourcePaths.get(cm2).getKey(); - // get outside src2 resource state by pull data transfer. - if (cm2.isOutside() || src2.getCommonPrefix(dst.getInSideResource(curChannel)) == null) { - // generate a pull data transfer from a depending in/ref resource. - Type srcResType2 = src2.getResourceStateType(); - String srcResName2 = JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(src2.getResourceHierarchy())); - String dependingGetter = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(src2, dst.getInSideResource(curChannel)).toImplementation(new String[] {""}); - getter.addStatement(srcResType2.getInterfaceTypeName() + " " + srcResName2 + " = " + dependingGetter + ";"); - } - } - } - // collect the message constraints by a descendant channel. - List varsForSideEffects = new ArrayList<>(); - int v = 0; - resourcePathsAndMessage = curChannel.fillOutsideResourcePaths(out, JavaCodeGenerator.pullAccessor, null); - if (resourcePathsAndMessage != null) { - resourcePaths = resourcePathsAndMessage.getKey(); - Term messageTermSub = resourcePathsAndMessage.getValue(); - for (Entry fieldEnt: ((Term) messageTermSub).getSubTerms(Field.class).entrySet()) { - Position pos = fieldEnt.getKey(); - Field field = fieldEnt.getValue(); - Variable var = new Variable(field.getSymbol().getName(), field.getType()); - ((Term) messageTermSub).replaceSubTerm(pos, var); - } - for (Map.Entry subTermEnt: messageTermSub.getSubTerms(Term.class).entrySet()) { - Term subTerm = subTermEnt.getValue(); - if (!(subTerm instanceof Constant) && subTerm.getSymbol().isImplWithSideEffect()) { - Variable var = new Variable("v" + v, subTerm.getType()); - varsForSideEffects.add(var); - v++; - // Add a side effect statement within the loop - Position pos = new Position(); - pos.addHeadOrder(0); - subTerm.replaceSubTerm(pos, var); - sideEffects = new String[] {""}; - String curState = messageTermSub.toImplementation(sideEffects); - getter.addStatement(sideEffects[0].replaceAll("\n", "")); - // Cancel the side effects in the return value. - pos = subTermEnt.getKey(); - messageTermSub.replaceSubTerm(pos, var); - } - } - if (messageTerm == null) { - messageTerm = messageTermSub; - } else { - messageTerm = (Term) messageTerm.unify(messageTermSub); - } - if (messageTerm == null) { - throw new UnificationFailed(); - } - } - // enclosed by a for loop - Expression selExp = curChannel.getSelectors().get(0).getExpression(); - Type selType = null; - String varName = null; - if (selExp instanceof Variable) { - selType = ((Variable) selExp).getType(); - varName = ((Variable) selExp).getName(); - ChannelMember insideChMem = null; - for (ChannelMember cm2 :curChannel.getInputChannelMembers()) { - if (!cm2.isOutside()) { - insideChMem = cm2; - break; - } - } - if (insideChMem == null) { - for (ChannelMember cm2 :curChannel.getReferenceChannelMembers()) { - if (!cm2.isOutside()) { - insideChMem = cm2; - break; - } - } - } - ResourcePath insideResPath = insideChMem.getResource(); - while (insideResPath.getParent() != null && (insideResPath.getLastParam() == null || !insideResPath.getLastParam().equals(selExp))) { - insideResPath = insideResPath.getParent(); - } - insideResPath = insideResPath.getParent(); - if (insideResPath != null) { - String parent = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(insideResPath, dst.getInSideResource(ch)).toImplementation(new String[] {""}); - if (selType.equals(DataConstraintModel.typeInt)) { - // make a for loop (for a list) for data collecting. - getter.addFirstStatement("for (int " + varName + " = 0; " + varName +" < " + parent + ".size(); " + varName + "++) {"); - } else if (selType.equals(DataConstraintModel.typeString)) { - // make a for loop (for a map) for data collecting. - getter.addFirstStatement("for (String " + varName + ": " + parent + ".keySet()) {"); - } - } - } - // initialize the variables to hold side effects within the loop. - for (Variable var: varsForSideEffects) { - getter.addFirstStatement(var.getType().getInterfaceTypeName() + " " + var.getName() + " = new " + var.getType().getImplementationTypeName() + "();"); - } - // end of the loop - getter.addStatement("}"); - if (curChannel.getChildren() != null && curChannel.getChildren().size() > 0) { - channelItrStack.push(chItr); - chItr = curChannel.getChildren().iterator(); - } - } - } while (!channelItrStack.isEmpty()); - } - // generate a return statement. - sideEffects = new String[] {""}; - String curState = ch.deriveUpdateExpressionOf(out, messageTerm, JavaCodeGenerator.pullAccessor).toImplementation(sideEffects); - getter.addStatement(sideEffects[0] + "return " + curState + ";"); - } - if (outsideInputResource) { - // Update fields to refer to outside resources. - Map>> resourcePaths = ch.fillOutsideResourcePaths(out, JavaCodeGenerator.pullAccessor); - if (resourcePaths != null && resourcePaths.size() > 0) { - for (ChannelMember outsideMember: resourcePaths.keySet()) { - ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); - if (!JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { - outsidePath = outsidePath.getParent(); - } - String outsideResName = JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(outsidePath.getResourceHierarchy())); - Set dependedMembers = resourcePaths.get(outsideMember).getValue(); - for (ChannelMember dependedMember: dependedMembers) { - ResourcePath dependedRes = dependedMember.getResource(); - ResourceNode dependedNode = null; - PushPullAttribute pushPull2 = null; - for (Edge resToCh2: resToCh.getDestination().getInEdges()) { - if (((ResourceNode) resToCh2.getSource()).getOutSideResources().contains(dependedRes)) { - dependedNode = (ResourceNode) resToCh2.getSource(); - pushPull2 = (PushPullAttribute) resToCh.getAttribute(); - } - } - TypeDeclaration dependedComponent = null; - if (JavaCodeGenerator.generatesComponent(dependedRes.getResourceHierarchy())) { - String dependedResourceName = JavaCodeGenerator.getComponentName(dependedRes.getResourceHierarchy()); - dependedComponent = componentMap.get(dependedResourceName); - } else { - String dependedParentResourceName = JavaCodeGenerator.getComponentName(dependedRes.getParent().getResourceHierarchy()); - dependedComponent = componentMap.get(dependedParentResourceName); - } - Expression outsideExp = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(outsidePath, null); - if (JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { - outsideExp = ((Term) outsideExp).getChild(0); - } - if (dstComponent == dependedComponent) { - // In the common parent. - if (dependedNode != null) { // Inspect further dependency. - for (Edge chToRes2: dependedNode.getInEdges()) { - DataTransferChannel ch2 = ((ChannelNode) chToRes2.getSource()).getChannel(); - if (ch2.getInputChannelMembers().size() == 0) { - // In an input method of the parent component. - Set outs = ch2.getOutputChannelMembers(); - MethodDeclaration input = getInputMethod(dependedComponent, outs.iterator().next(), outs.size()); - String[] sideEffects = new String[] {""}; - String outsideAccessor = outsideExp.toImplementation(sideEffects); - input.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. - // Update constructor. - MethodDeclaration constructor = getConstructor(dependedComponent); - constructor.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // initialize the reference field. - } else { - boolean isPush = true; - for (Edge resToCh2: chToRes2.getSource().getInEdges()) { - if (((PushPullAttribute) resToCh2.getAttribute()).getSelectedOption() != PushPullValue.PUSH) { - isPush = false; - break; - } - } - if (isPush) { - String[] sideEffects = new String[] {""}; - String outsideAccessor = outsideExp.toImplementation(sideEffects); - for (Edge resToCh2: chToRes2.getSource().getInEdges()) { - // In an update method of the parent component. - ResourceNode dependingResSrc = (ResourceNode) resToCh2.getSource(); - MethodDeclaration update = null; - if (JavaCodeGenerator.generatesComponent(dependedRes.getResourceHierarchy())) { - update = getUpdateMethod(dependedComponent, null, JavaCodeGenerator.getComponentName(dependingResSrc.getResourceHierarchy())); - } else { - String dependingResName = JavaCodeGenerator.getComponentName(dependedRes.getResourceHierarchy()); - update = getUpdateMethod(dependedComponent, dependingResName, JavaCodeGenerator.getComponentName(dependingResSrc.getResourceHierarchy())); - } - update.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. - } - // Update constructor. - MethodDeclaration constructor = getConstructor(dependedComponent); - constructor.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // initialize the reference field. - } - } - } - } - } else { - if (pushPull2.getSelectedOption() == PushPullValue.PUSH) { - // In an update method of the destination component. - MethodDeclaration update = null; - if (JavaCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { - update = getUpdateMethod(dstComponent, null, JavaCodeGenerator.getComponentName(dependedRes.getResourceHierarchy())); - } else { - String dstResName = JavaCodeGenerator.getComponentName(dst.getResourceHierarchy()); - update = getUpdateMethod(dstComponent, dstResName, JavaCodeGenerator.getComponentName(dependedRes.getResourceHierarchy())); - } - String[] sideEffects = new String[] {""}; - String outsideAccessor = outsideExp.toImplementation(sideEffects); - update.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. - // Update constructor. - MethodDeclaration constructor = getConstructor(dstComponent); - constructor.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // initialize the reference field. - } - } - } - } - } - } - } - } - } - } - } - } - - // for source nodes - TypeDeclaration mainComponent = componentMap.get(JavaCodeGenerator.mainTypeName); - for (ResourceHierarchy resource: model.getResourceHierarchies()) { - String resourceName = JavaCodeGenerator.getComponentName(resource); - TypeDeclaration component = componentMap.get(resourceName); - if (JavaCodeGenerator.generatesComponent(resource)) { - if (component != null) { - // state getter method - Type resourceType = JavaCodeGenerator.getImplStateType(resource); - MethodDeclaration stateGetter = getMethod(component, "getValue"); - if (stateGetter != null && (stateGetter.getBody() == null || stateGetter.getBody().getStatements().size() == 0)) { - if (model.isPrimitiveType(resourceType)) { - // primitive type - stateGetter.addStatement("return value;"); - } else { - if (resource.getChildren() != null && resource.getChildren().size() == 1 && resource.getChildren().iterator().next().getNumParameters() > 0) { - // list or map - String implTypeName = resourceType.getImplementationTypeName(); - // copy the current state to be returned as a 'value' - stateGetter.addStatement("return new " + implTypeName + "(value);"); - } else { - if (resource.getChildren() == null || resource.getChildren().size() == 0) { - // a leaf resource - String implTypeName = resourceType.getImplementationTypeName(); - stateGetter.addStatement("return new " + implTypeName + "(value);"); - } else { - Term composer = null; - Term composerSub = new Constant(DataConstraintModel.nil); - composerSub.setType(DataConstraintModel.typeMap); - for (ResourceHierarchy child: resource.getChildren()) { - String childTypeName = JavaCodeGenerator.getComponentName(child); - String fieldName = JavaCodeGenerator.toVariableName(childTypeName); - Term childGetter = null; - if (!JavaCodeGenerator.generatesComponent(child)) { - // the child is not a class - childGetter = new Term(new Symbol("get" + childTypeName, 1, Symbol.Type.METHOD)); - childGetter.addChild(new Constant("this")); - } else { - // the child is a class - childGetter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); - childGetter.addChild(new Field(fieldName, JavaCodeGenerator.getImplStateType(child))); - } - composer = new Term(DataConstraintModel.insert); - composer.addChild(composerSub); - composer.addChild(new Constant(fieldName, DataConstraintModel.typeString)); // key - composer.addChild(childGetter); // value - composer.setType(DataConstraintModel.typeMap); - composerSub = composer; - } - composer.setType(stateGetter.getReturnType()); - String[] sideEffects = new String[] {""}; - String returnValue = composer.toImplementation(sideEffects); - if (sideEffects[0] != null) { - stateGetter.addStatement(sideEffects[0] + "return " + returnValue+ ";"); - } else { - stateGetter.addStatement("return " + returnValue+ ";"); - } - } - } - } - } - - // (#4) descendant getter method (the implementation must be kept consistent with #3) - if (resource.getChildren().size() > 0) { - for (ResourceHierarchy child: resource.getChildren()) { - 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; - break; - } - } - 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; - } 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; - } - 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; - if (DataConstraintModel.typeList.isAncestorOf(parent.getResourceStateType())) { - params++; - } else if (DataConstraintModel.typeMap.isAncestorOf(parent.getResourceStateType())) { - params++; - } - children = descendant.getChildren(); - } while (children != null && children.size() == 1 && (descendant = children.iterator().next()) != null); - } - } - } - } - - // methods for input events - Map> ioChannelsAndMembers = getIOChannelsAndMembers(resource, model); - for (Map.Entry> entry: ioChannelsAndMembers.entrySet()) { - Set outs = entry.getValue(); - DataTransferChannel ch = entry.getKey(); - for (ChannelMember out: outs) { - MethodDeclaration input = null; - if (JavaCodeGenerator.generatesComponent(resource)) { - // A component is generated for this resource. - input = getInputMethod(component, out, ch.getOutputChannelMembers().size()); - } else { - // No component is generated for this resource. - ResourceHierarchy parent = resource.getParent(); - if (parent != null) { - TypeDeclaration parentType = componentMap.get(JavaCodeGenerator.getComponentName(parent)); - input = getInputMethod(parentType, out, ch.getOutputChannelMembers().size()); - } - } - if (input != null) { - // In each resource - Expression updateExp = ch.deriveUpdateExpressionOf(out, JavaCodeGenerator.refAccessor).getKey(); - // 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 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); - if (JavaCodeGenerator.generatesComponent(resource)) { - String updateStatement; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - updateStatement = sideEffects[0]; - if (updateStatement.endsWith("\n")) { - updateStatement = updateStatement.substring(0, updateStatement.length() - 1); - } - } else { - updateStatement = sideEffects[0] + "this.value = " + newState + ";"; - } - if (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement)) { - input.addFirstStatement(updateStatement); - } - } else { - String updateStatement = ""; - if (sideEffects[0] != null) { - updateStatement = sideEffects[0]; - updateStatement = updateStatement.replace(".value", "." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(resource))); - if (updateStatement.endsWith("\n")) { - updateStatement = updateStatement.substring(0, updateStatement.length() - 1); - } - } - if (DataConstraintModel.typeList.isAncestorOf(resource.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.set); - selector.addChild(new Field("value")); - selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newList = selector.toImplementation(sideEffects2); - updateStatement += sideEffects2[0]; - } else if (DataConstraintModel.typeMap.isAncestorOf(resource.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.insert); - selector.addChild(new Field("value")); - selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newMap = selector.toImplementation(sideEffects2); - updateStatement += sideEffects2[0]; - } else if (!(updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect())) { - updateStatement += "this." + JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(resource)) + " = " + newState + ";"; - } - if (updateStatement != null && (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement))) { - input.addFirstStatement(updateStatement); - } - } - - // In the main type - if (mainComponent != null) { - Expression message = out.getStateTransition().getMessageExpression(); - String inputAccessorName = input.getName(); - if (message instanceof Term) { - inputAccessorName = ((Term) message).getSymbol().getImplName(); - } else if (message instanceof Variable) { - inputAccessorName = ((Variable) message).getName(); - } - MethodDeclaration inputAccessor = getMethod(mainComponent, inputAccessorName); - if (inputAccessor != null) { - Set referredSet = referredResources.get(input); - for (ChannelMember rc: ch.getReferenceChannelMembers()) { - // For each reference channel member, get the current state of the reference side resource by pull data transfer. - ResourcePath ref = rc.getResource(); - if (referredSet == null) { - referredSet = new HashSet<>(); - referredResources.put(input, referredSet); - } - if (!out.getResource().equals(ref)) { - String refVarName = ref.getLeafResourceName(); - if (!referredSet.contains(ref)) { - referredSet.add(ref); - Expression refGetter = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(ref, null); - sideEffects = new String[] {""}; - String refExp = refGetter.toImplementation(sideEffects); - String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); - inputAccessor.addFirstStatement(sideEffects[0] + refTypeName + " " + refVarName + " = " + refExp + ";"); - } - } - } - Expression resExp = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(out.getResource(), null); - List args = new ArrayList<>(); - if (resExp instanceof Term) { - // To access the parent resource if the leaf resource is primitive and cannot declare the input method, or to remove getValue(). - if (((Term) resExp).getChildren().size() > 1 && ((Term) resExp).getChild(1) instanceof Variable) { - args.add(((Variable)((Term) resExp).getChild(1)).getName()); - } - resExp = ((Term) resExp).getChild(0); - } - // Values of channel parameters. - for (Selector selector: ch.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - if (!args.contains(selVar.getName())) { - args.add(selVar.getName()); - } - } - } - // Values of message parameters. - if (message instanceof Term) { - for (Map.Entry varEnt: message.getVariables().entrySet()) { - String refVarName = null; - for (ChannelMember rc: ch.getReferenceChannelMembers()) { - Expression varExp = rc.getStateTransition().getMessageExpression().getSubTerm(varEnt.getKey()); - if (varExp != null && rc.getStateTransition().getCurStateExpression().contains(varExp)) { - refVarName = rc.getResource().getLeafResourceName(); - break; - } - } - if (refVarName != null) { - if (!args.contains(refVarName)) { - args.add(refVarName); - } - } else { - if (!args.contains(varEnt.getValue().getName())) { - args.add(varEnt.getValue().getName()); - } - } - } - } - String argsStr = ""; - String delimiter = ""; - for (String arg: args) { - argsStr += delimiter + arg; - delimiter = ", "; - } - if (resExp != null) { - String resourceAccess = resExp.toImplementation(new String[] {null}); - inputAccessor.addStatement(resourceAccess + "." + input.getName() + "(" + argsStr + ");"); - } else { - inputAccessor.addStatement(input.getName() + "(" + argsStr + ");"); - } - } - } - } - } - } - } - } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork - | InvalidMessage | UnificationFailed | ValueUndefined e1) { - e1.printStackTrace(); - } - return codes; - } - - private static void replaceJsonTermWithConstructorInvocation(Expression exp, Type replacedJsonType, String replacingClassName, TypeDeclaration descendantComponent) { - // Replace each json term in exp with the corresponding constructor invocation. - Type descendantType = new Type(replacingClassName, replacingClassName); - Map subTerms = ((Term) exp).getSubTerms(Term.class); - Iterator> termEntItr = subTerms.entrySet().iterator(); - while (termEntItr.hasNext()) { - Entry termEnt = termEntItr.next(); - Term jsonTerm = termEnt.getValue(); - if (jsonTerm.getType() != null) { - if (jsonTerm.getType().equals(replacedJsonType)) { - if (jsonTerm instanceof JsonTerm || jsonTerm.getSymbol().equals(DataConstraintModel.addMember)) { - String constructorInvocation = "new " + replacingClassName + "("; - MethodDeclaration descendantConstructor = getConstructor(descendantComponent); - String delimiter = ""; - if (descendantConstructor != null) { - for (VariableDeclaration var: descendantConstructor.getParameters()) { - // Extract the argument of each constructor parameter from jsonTerm. - JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); - jsonMember.addChild(jsonTerm); - jsonMember.addChild(new Constant(var.getName(), DataConstraintModel.typeString)); - Expression param = jsonMember.reduce(); // Reduce {"name": "foo", age: 25}.name => "foo" - 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()); - } - } - constructorInvocation = constructorInvocation + delimiter + param.toImplementation(null); - } else { - constructorInvocation = constructorInvocation + delimiter + var.getName(); - } - delimiter = ", "; - } - } - constructorInvocation += ")"; - ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation, descendantType)); - subTerms = ((Term) exp).getSubTerms(Term.class); - termEntItr = subTerms.entrySet().iterator(); - } else { - jsonTerm.setType(descendantType); - } - } else { - Type oldType = jsonTerm.getType(); - Type newType = new Type(oldType.getTypeName(), - oldType.getImplementationTypeName().replace(replacedJsonType.getInterfaceTypeName(), replacingClassName), - oldType.getInterfaceTypeName().replace(replacedJsonType.getInterfaceTypeName(), replacingClassName)); - for (Type parent: oldType.getParentTypes()) { - newType.addParentType(parent); - } - jsonTerm.setType(newType); - } - } - } - } - - private static MethodDeclaration getConstructor(TypeDeclaration component) { - for (MethodDeclaration m: component.getMethods()) { - if (m.isConstructor()) return m; - } - return null; - } - - private static MethodDeclaration getUpdateMethod(TypeDeclaration component, String dstResName, String srcResName) { - for (MethodDeclaration m: component.getMethods()) { - if (dstResName == null) { - if (m.getName().equals("updateFrom" + srcResName)) return m; - } else { - if (m.getName().equals("update" + dstResName + "From" + srcResName)) return m; - } - } - return null; - } - - private static List getUpdateMethods(TypeDeclaration component, String resName) { - List updates = new ArrayList<>(); - for (MethodDeclaration m: component.getMethods()) { - if (resName == null) { - if (m.getName().startsWith("updateFrom")) { - updates.add(m); - } - } else { - if (m.getName().startsWith("update" + resName + "From")) { - updates.add(m); - } - } - } - 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().equals("get" + resourceName)) { - getters.add(m); - } - } - return getters; - } - - private static Map> getIOChannelsAndMembers(ResourceHierarchy resource, DataTransferModel model) { - Map> ioChannelsAndMembers = new HashMap<>(); - for (Channel c: model.getInputChannels()) { - DataTransferChannel ch = (DataTransferChannel) c; - // I/O channel - for (ChannelMember out: ch.getOutputChannelMembers()) { - if (resource.equals(out.getResource().getResourceHierarchy())) { - if (out.getStateTransition().getMessageExpression() instanceof Term || out.getStateTransition().getMessageExpression() instanceof Variable) { - Set channelMembers = ioChannelsAndMembers.get(ch); - if (channelMembers == null) { - channelMembers = new HashSet<>(); - ioChannelsAndMembers.put(ch, channelMembers); - } - channelMembers.add(out); - } - } - } - } - return ioChannelsAndMembers; - } - - private static List getInputMethods(TypeDeclaration component, ResourceNode resource, DataTransferModel model) { - List inputs = new ArrayList<>(); - for (Channel c: model.getInputChannels()) { - DataTransferChannel channel = (DataTransferChannel) c; - // I/O channel - for (ChannelMember out: channel.getOutputChannelMembers()) { - if (resource.getInSideResources().contains(out.getResource())) { - MethodDeclaration input = getInputMethod(component, out, channel.getOutputChannelMembers().size()); - inputs.add(input); - } - } - } - return inputs; - } - - private static List getInputMethods(TypeDeclaration component, ResourceHierarchy resource, DataTransferModel model) { - List inputs = new ArrayList<>(); - for (Channel c: model.getInputChannels()) { - DataTransferChannel channel = (DataTransferChannel) c; - // I/O channel - for (ChannelMember out: channel.getOutputChannelMembers()) { - if (resource.equals(out.getResource().getResourceHierarchy())) { - MethodDeclaration input = getInputMethod(component, out, channel.getOutputChannelMembers().size()); - inputs.add(input); - } - } - } - return inputs; - } - - private static MethodDeclaration getInputMethod(TypeDeclaration component, ChannelMember cm, int outNumber) { - String inputMethodName = null; - if (cm.getStateTransition().getMessageExpression() instanceof Term) { - Term message = (Term) cm.getStateTransition().getMessageExpression(); - inputMethodName =message.getSymbol().getImplName(); - } else if (cm.getStateTransition().getMessageExpression() instanceof Variable) { - Variable message = (Variable) cm.getStateTransition().getMessageExpression(); - inputMethodName = message.getName(); - } - if (outNumber > 1) { - inputMethodName += "For" + JavaCodeGenerator.getComponentName(cm.getResource().getResourceHierarchy()); - } - MethodDeclaration input = getMethod(component, inputMethodName); - return input; - } - - private static MethodDeclaration getMethod(TypeDeclaration component, String methodName) { - for (MethodDeclaration m: component.getMethods()) { - if (m.getName().equals(methodName)) return m; - } - return null; - } -} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java index d0c42c7..6548d62 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java @@ -1,17 +1,35 @@ package generators; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import code.ast.*; +import code.ast.Expression; import code.ast.Variable; import models.algebra.*; -import models.algebra.Expression; import models.algebra.Type; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonType; +import models.dataConstraintModel.ListType; +import models.dataConstraintModel.MapType; +import models.dataConstraintModel.TupleType; public class JavaSpecific implements ILanguageSpecific { - public static final Type typeVoid = new Type("Void", "void"); + public static final Type typeVoid = new Type("Void", new code.ast.SimpleType("void")); + public static final code.ast.SimpleType typeObject = new code.ast.SimpleType("Object"); + public static final code.ast.SimpleType typeBoolean = new code.ast.SimpleType("Boolean"); + public static final code.ast.SimpleType typeInteger = new code.ast.SimpleType("Integer"); + public static final code.ast.SimpleType typeLong = new code.ast.SimpleType("Long"); + public static final code.ast.SimpleType typeFloat = new code.ast.SimpleType("Float"); + public static final code.ast.SimpleType typeDouble = new code.ast.SimpleType("Double"); + public static final code.ast.SimpleType typeString = new code.ast.SimpleType("String"); + public static final code.ast.SimpleType typeList = new code.ast.SimpleType("List"); + public static final code.ast.SimpleType typeArrayList = new code.ast.SimpleType("ArrayList"); + public static final code.ast.SimpleType typeMap = new code.ast.SimpleType("Map"); + public static final code.ast.SimpleType typeMapEntry = new code.ast.SimpleType("Map.Entry"); + public static final code.ast.SimpleType typeHashMap = new code.ast.SimpleType("HashMap"); + public static final code.ast.SimpleType typePair = new code.ast.SimpleType("Pair"); public static final String self = "this"; @Override @@ -58,40 +76,93 @@ } @Override - public Type newListType(String compTypeName) { - return new Type("List", "ArrayList<>", "List<" + compTypeName + ">", DataConstraintModel.typeList); - } - - @Override - public Type newMapType(Type keyType, String valueTypeName) { - return new Type("Map", "HashMap<>", "Map<" + keyType.getImplementationTypeName() + ", " + valueTypeName + ">", DataConstraintModel.typeMap); - } - - @Override - public Type newTupleType(List componentTypes) { - String implTypeName = "AbstractMap.SimpleEntry<>"; - String interfaceTypeName = "Map.Entry<$x>"; - if (componentTypes.size() >= 2) { - implTypeName = implTypeName.replace("$x", getImplementationTypeName(componentTypes.get(0)) + "$x"); - interfaceTypeName = interfaceTypeName.replace("$x", getInterfaceTypeName(componentTypes.get(0)) + "$x"); - for (Type argType : componentTypes.subList(1, componentTypes.size() - 1)) { - implTypeName = implTypeName.replace("$x", - ", AbstractMap.SimpleEntry<" + getImplementationTypeName(argType) + "$x>"); - interfaceTypeName = interfaceTypeName.replace("$x", - ", Map.Entry<" + getInterfaceTypeName(argType) + "$x>"); - } - implTypeName = implTypeName.replace("$x", - ", " + getImplementationTypeName(componentTypes.get(componentTypes.size() - 1))); - interfaceTypeName = interfaceTypeName.replace("$x", - ", " + getInterfaceTypeName(componentTypes.get(componentTypes.size() - 1))); - } - Type newTupleType = new Type("Tuple", implTypeName, interfaceTypeName, DataConstraintModel.typeTuple); - return newTupleType; + public ListType newListType(Type compType) { + return newListType(compType, DataConstraintModel.typeList); } @Override - public VariableDeclaration getVariableDeclaration(Type typeName, String varName) { - return new VariableDeclaration(typeName, varName); + public ListType newListType(Type compType, Type parentListType) { + List typeArgs = new ArrayList<>(); + if (isValueType(compType)) { + typeArgs.add((code.ast.Type) getWrapperType(compType).getInterfaceType()); + } else { + typeArgs.add((code.ast.Type) compType.getInterfaceType()); + } + return new ListType("List", new code.ast.ParameterizedType(typeArrayList), new code.ast.ParameterizedType(JavaSpecific.typeList, typeArgs), parentListType, compType); + } + + @Override + public MapType newMapType(Type keyType, String valueTypeName) { + return newMapType(keyType, valueTypeName, DataConstraintModel.typeMap); + } + + @Override + public MapType newMapType(Type keyType, String valueTypeName, Type parentMapType) { + Type valueType = new Type(valueTypeName, new code.ast.SimpleType(valueTypeName)); + List typeArgs = new ArrayList<>(); + typeArgs.add((code.ast.Type) keyType.getInterfaceType()); + typeArgs.add((code.ast.Type) valueType.getInterfaceType()); + return new MapType("Map", new code.ast.ParameterizedType(typeHashMap), new code.ast.ParameterizedType(JavaSpecific.typeMap, typeArgs), parentMapType, keyType, valueType); + } + + @Override + public MapType newMapType(Type keyType, Type valueType) { + return newMapType(keyType, valueType, DataConstraintModel.typeMap); + } + + @Override + public MapType newMapType(Type keyType, Type valueType, Type parentMapType) { + List typeArgs = new ArrayList<>(); + typeArgs.add((code.ast.Type) keyType.getInterfaceType()); + if (isValueType(valueType)) { + typeArgs.add((code.ast.Type) getWrapperType(valueType).getInterfaceType()); + } else { + typeArgs.add((code.ast.Type) valueType.getInterfaceType()); + } + return new MapType("Map", new code.ast.ParameterizedType(typeHashMap), new code.ast.ParameterizedType(JavaSpecific.typeMap, typeArgs), parentMapType, keyType, valueType); + } + + @Override + public TupleType newTupleType(List componentTypes) { + return newTupleType(componentTypes, DataConstraintModel.typeTuple); + } + + @Override + public TupleType newTupleType(List componentTypes, Type parentTupleType) { + code.ast.Type implType = new code.ast.SimpleType("AbstractMap.SimpleEntry"); + code.ast.Type interfaceType = typeMapEntry; + if (componentTypes.size() >= 2) { + Type compType = componentTypes.get(componentTypes.size() - 1); + if (isValueType(compType)) { + interfaceType = (code.ast.Type) getWrapperType(compType).getInterfaceType(); + } else { + interfaceType = (code.ast.Type) compType.getInterfaceType(); + } + for (int i = componentTypes.size() - 2; i >= 0; i--) { + List typeArgs = new ArrayList<>(); + compType = componentTypes.get(i); + if (isValueType(compType)) { + typeArgs.add((code.ast.Type) getWrapperType(compType).getInterfaceType()); + } else { + typeArgs.add((code.ast.Type) compType.getInterfaceType()); + } + typeArgs.add(interfaceType); + interfaceType = new code.ast.ParameterizedType(typeMapEntry, typeArgs); + } + } + return new TupleType("Tuple", implType, interfaceType, parentTupleType, componentTypes); + } + + @Override + public JsonType newJsonType() { + return new JsonType("Json", new code.ast.ParameterizedType(typeHashMap), new code.ast.ParameterizedType(typeMap, List.of(typeString, typeObject))); + } + + @Override + public JsonType newJsonType(Type parentJsonType) { + JsonType jsonType = newJsonType(); + jsonType.addParentType(parentJsonType); + return jsonType; } @Override @@ -187,17 +258,20 @@ } @Override - public ForStatement getForStatementForList(models.algebra.Variable varName, Expression list) { + public ForStatement getForStatementForList(String varName, String list) { + VariableDeclaration varDec = new VariableDeclaration(DataConstraintModel.typeInt, varName, new code.ast.Constant("0")); + VariableDeclarationStatement varDecStmt = new VariableDeclarationStatement(); + varDecStmt.addFragment(varDec); ForStatement forStatement = new ForStatement(); - forStatement.getInitializers().add(new PlainStatement("int " + varName.getName() + " = 0")); + forStatement.getInitializers().add(varDecStmt); InfixExpression condition = new InfixExpression( new Symbol("<", 2, Symbol.Type.INFIX), - new code.ast.Variable(varName.getName()), - new code.ast.Variable(list.toString() + ".size()") + new code.ast.Variable(varName), + new code.ast.Variable(list + ".size()") ); forStatement.setExpression(condition); PostfixExpression increment = new PostfixExpression( - new code.ast.Variable(varName.getName()), + new code.ast.Variable(varName), PostfixExpression.Operator.INCREMENT ); forStatement.setUpdaters(Arrays.asList(new ExpressionStatement(increment))); @@ -205,10 +279,9 @@ } @Override - public EnhancedForStatement getForStatementForCollection(String varName, String varType, String collection) { + public EnhancedForStatement getForStatementForCollection(VariableDeclaration varDeclaration, String collection) { EnhancedForStatement enhancedForStatement = new EnhancedForStatement(); - VariableDeclaration varDeclaration = new VariableDeclaration(new models.algebra.Type(varName,varType), varName); enhancedForStatement.setParameter(varDeclaration); enhancedForStatement.setExpression(new code.ast.Variable(collection)); @@ -216,10 +289,10 @@ } @Override - public EnhancedForStatement getForStatementForMap(String varName, String varType, String map) { + public EnhancedForStatement getForStatementForMap(String varName, String map) { + VariableDeclaration varDeclaration = new VariableDeclaration(DataConstraintModel.typeString, varName); EnhancedForStatement enhancedForStatement = new EnhancedForStatement(); - - VariableDeclaration varDeclaration = new VariableDeclaration(new models.algebra.Type(varName,varType), varName); + enhancedForStatement.setParameter(varDeclaration); enhancedForStatement.setExpression(new code.ast.Variable(map + ".keySet()")); @@ -227,16 +300,6 @@ } @Override - public String getEndForStatement() { - return "}"; - } - - @Override - public String getEndForStatement(String varName) { - return "}"; - } - - @Override public String toComponentName(String name) { return name.substring(0, 1).toUpperCase() + name.substring(1); } @@ -337,11 +400,11 @@ @Override public String getDecomposedTuple(String tupleExp, VariableDeclaration tupleVar, List vars) { String statements = ""; - statements += getVariableDeclaration(tupleVar.getType(), tupleVar.getName()) + statements += newVariableDeclaration(tupleVar.getType(), tupleVar.getName()) + getAssignment() + tupleExp + getStatementDelimiter(); for (int i = 0; i < vars.size(); i++) { VariableDeclaration var = vars.get(i); - statements += "\n" + getVariableDeclaration(var.getType(), var.getName()) + statements += "\n" + newVariableDeclaration(var.getType(), var.getName()) + getAssignment() + getTupleGet(tupleVar.getName(), i, vars.size()) + getStatementDelimiter(); @@ -369,6 +432,22 @@ } return false; } + + @Override + public Type getWrapperType(Type type) { + if (type == DataConstraintModel.typeInt) { + return new Type("Integer", typeInteger); + } else if (type == DataConstraintModel.typeLong) { + return new Type("Long", typeLong); + } else if (type == DataConstraintModel.typeFloat) { + return new Type("Float", typeFloat); + } else if (type == DataConstraintModel.typeDouble) { + return new Type("Double", typeDouble); + } else if (type == DataConstraintModel.typeBoolean) { + return new Type("Boolean", typeBoolean); + } + return type; + } private String getImplementationTypeName(Type type) { if (type == null) diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java deleted file mode 100644 index 68e4aa9..0000000 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ /dev/null @@ -1,1604 +0,0 @@ -package generators; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Stack; - -import code.ast.Annotation; -import code.ast.Block; -import code.ast.CompilationUnit; -import code.ast.FieldDeclaration; -import code.ast.ImportDeclaration; -import code.ast.MethodDeclaration; -import code.ast.TypeDeclaration; -import code.ast.VariableDeclaration; -import models.Edge; -import models.Node; -import models.algebra.Expression; -import models.algebra.Field; -import models.algebra.Parameter; -import models.algebra.Position; -import models.algebra.Symbol; -import models.algebra.Term; -import models.algebra.Type; -import models.algebra.Variable; -import models.dataConstraintModel.Channel; -import models.dataConstraintModel.ChannelMember; -import models.dataConstraintModel.DataConstraintModel; -import models.dataConstraintModel.ResourceHierarchy; -import models.dataConstraintModel.ResourcePath; -import models.dataConstraintModel.Selector; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.DataTransferChannel; -import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; -import models.dataFlowModel.PushPullAttribute; -import models.dataFlowModel.PushPullValue; -import models.dataFlowModel.DataFlowEdge; -import models.dataFlowModel.DataFlowGraph; -import models.dataFlowModel.ResourceNode; -import models.dataFlowModel.ChannelNode; -import models.dataFlowModel.StoreAttribute; - -/** - * Generator for Jersey prototypes - * - * @author Nitta - * - */ -public class JerseyCodeGenerator { - public static final Type typeVoid = new Type("Void", "void"); - public static final Type typeClient = new Type("Client", "Client"); - public static boolean differentTreesAsDifferentServices = true; - private static String defaultMainTypeName = "Main"; - static String mainTypeName = defaultMainTypeName; - - public static String getMainTypeName() { - return mainTypeName; - } - - public static void setMainTypeName(String mainTypeName) { - JerseyCodeGenerator.mainTypeName = mainTypeName; - } - - public static void resetMainTypeName() { - JerseyCodeGenerator.mainTypeName = defaultMainTypeName; - } - - public static String getComponentName(ResourceHierarchy res) { - String name = res.getResourceName(); - if (res.getNumParameters() > 0) { - if (name.length() > 3 && name.endsWith("ies")) { - name = name.substring(0, name.length() - 3) + "y"; - } else if (name.length() > 1 && name.endsWith("s")) { - name = name.substring(0, name.length() - 1); - } else { - name += "Element"; - } - } - return name.substring(0, 1).toUpperCase() + name.substring(1); - } - - public static String toVariableName(String name) { - return name.substring(0, 1).toLowerCase() + name.substring(1); - } - - public static Type getImplStateType(ResourceHierarchy res) { - Set children = res.getChildren(); - if (children == null || children.size() == 0) { - // leaf resource. - return res.getResourceStateType(); - } else { - ResourceHierarchy child = children.iterator().next(); - if (children.size() == 1 && child.getNumParameters() > 0) { - // map or list. - if (DataConstraintModel.typeList.isAncestorOf(res.getResourceStateType())) { - // list. - if (generatesComponent(child)) { - return new Type("List", "ArrayList<>", "List<" + getComponentName(child) + ">", DataConstraintModel.typeList); - } else { - 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 null; - } else { - // class - return res.getResourceStateType(); - } - } - } - - public static boolean generatesComponent(ResourceHierarchy res) { - 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; - if (res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0 - && (res.getChildren().iterator().next().getChildren() == null || res.getChildren().iterator().next().getChildren().size() == 0)) return false; - return true; -// return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); - } - - static public ArrayList doGenerate(DataFlowGraph graph, DataTransferModel model) { - ArrayList codes = new ArrayList<>(); -// ArrayList resources = StoreResourceCheck(graph); - Collection resources = graph.getResourceNodes(); - Map resourceComponents = new HashMap<>(); - Map resourceConstructors = new HashMap<>(); - List> getters = new ArrayList<>(); - Map> updates = new HashMap<>(); - Map> inputs = new HashMap<>(); - List> fields = new ArrayList<>(); - Map> descendantGetters = new HashMap<>(); - Map getterAccessors = new HashMap<>(); - Map> inputAccessors = new HashMap<>(); - Map> constructorParams = new HashMap<>(); - Map priorMemberForInputChannel = new HashMap<>(); - - // For each resource node. - for (Node n : resources) { - ResourceNode resourceNode = (ResourceNode) n; - TypeDeclaration component = null; - if (generatesComponent(resourceNode.getResourceHierarchy())) { - String resourceName = getComponentName(resourceNode.getResourceHierarchy()); - - component = resourceComponents.get(resourceNode.getResourceHierarchy()); - if (component == null) { - // Add compilation unit for each resource. - component = new TypeDeclaration(resourceName); - if (resourceNode.getResourceHierarchy().getParent() == null) { - // For a root node. - component.addAnnotation(new Annotation("Component")); - component.addAnnotation(new Annotation("Path", "\"/" + resourceNode.getResourceName() + "\"")); - } - resourceComponents.put(resourceNode.getResourceHierarchy(), component); - - CompilationUnit cu = new CompilationUnit(component); - cu.addImport(new ImportDeclaration("java.util.*")); - if (resourceNode.getResourceHierarchy().getParent() == null) { - // For a root node. - cu.addImport(new ImportDeclaration("jakarta.ws.rs.*")); - cu.addImport(new ImportDeclaration("jakarta.ws.rs.client.*")); - cu.addImport(new ImportDeclaration("jakarta.ws.rs.core.*")); - cu.addImport(new ImportDeclaration("org.springframework.stereotype.Component")); - cu.addImport(new ImportDeclaration("com.fasterxml.jackson.databind.ObjectMapper")); - cu.addImport(new ImportDeclaration("com.fasterxml.jackson.core.JsonProcessingException")); - } - codes.add(cu); - - // Declare the field to store the state in the type of each resource. - if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { - ResourceHierarchy res = resourceNode.getResourceHierarchy(); - Set children = res.getChildren(); - if (children == null || children.size() == 0) { - // leaf resource. - Type fieldType = getImplStateType(res); - component.addField(new FieldDeclaration(fieldType, "value", getInitializer(res))); - // Add a parameter to initialize the state field to the constructor. -// Map nameToParam = constructorParams.get(res); -// if (nameToParam == null) { -// nameToParam = new HashMap<>(); -// constructorParams.put(resourceNode.getResourceHierarchy(), nameToParam); -// } -// String varName = "value"; -// if (nameToParam.get(varName) == null) { -// nameToParam.put(varName, new VariableDeclaration(fieldType, varName)); -// } - } else { - ResourceHierarchy child = children.iterator().next(); - if (children.size() == 1 && child.getNumParameters() > 0) { - // map or list. - component.addField(new FieldDeclaration(getImplStateType(res), "value", getInitializer(res))); - } else { - // class - for (ResourceHierarchy c: children) { - String childTypeName = getComponentName(c); - Type childType = null; - if (generatesComponent(c)) { - // The child has a component. - childType = new Type(childTypeName, childTypeName); - String fieldName = toVariableName(childTypeName); - component.addField(new FieldDeclaration(childType, fieldName, "new " + childTypeName + "()")); - } - } - } - } - } - - // Declare the getter method to obtain the resource state in the component of each resource. - MethodDeclaration stateGetter = new MethodDeclaration("getValue", getImplStateType(resourceNode.getResourceHierarchy())); - if (resourceNode.getResourceHierarchy().getParent() == null) { - // Since this getter is also an accessor. - stateGetter.addAnnotation(new Annotation("Produces", "MediaType.APPLICATION_JSON")); - stateGetter.addAnnotation(new Annotation("GET")); - } - component.addMethod(stateGetter); - } - if (component != null) { - // (#1) Declare the getter methods in this resource to obtain descendant resources. (complementary to #2) - Set descendants = descendantGetters.get(resourceNode.getResourceHierarchy()); - if (descendants == null) { - descendants = new HashSet<>(); - descendantGetters.put(resourceNode.getResourceHierarchy(), descendants); - } - for (ResourceNode child: resourceNode.getChildren()) { - // 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)); - } - 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); - } - } - -// // 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 the state field and reference fields in the parent component. - boolean bDeclareClientField = false; - if (component == null) { - // Declare reference fields for push/pull data transfer. - boolean noPullTransfer = true; - for (Edge resToCh : resourceNode.getOutEdges()) { - DataFlowEdge re = (DataFlowEdge) resToCh; - DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); - for (Edge chToRes: re.getDestination().getOutEdges()) { - ResourceHierarchy dstRes = ((ResourceNode) chToRes.getDestination()).getResourceHierarchy(); - // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = false; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (((ResourceNode) chToRes.getDestination()).getInSideResources().contains(cm.getResource()) && cm.isOutside()) { - outsideOutputResource = true; // Regarded as push transfer. - break; - } - } - if (outsideOutputResource) { - // Declare a field in the parent component to refer to the destination resource of push transfer. - if (!generatesComponent(dstRes)) { - dstRes = dstRes.getParent(); - } - String dstResName = getComponentName(dstRes); -// if (resourceNode.getOutSideResource().getCommonPrefix(dstRes) == null && differentTreesAsDifferentServices) { - // Inter-service - if (!bDeclareClientField) { - // Declare a client field to connect to the destination resource of push transfer. - FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), clientField)); - bDeclareClientField = true; - } -// } else { -// // Inner-service -// // Declare a field to directly refer to the destination resource of push transfer. -// if (resourceNode.getParent().getResourceHierarchy() != dstRes.getResourceHierarchy()) { -// FieldDeclaration refFieldForPush = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); -// fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPush)); -// } -// } - } - } - } - for (Edge chToRes : resourceNode.getInEdges()) { - for (Edge resToCh: chToRes.getSource().getInEdges()) { - DataFlowEdge re = (DataFlowEdge) resToCh; - DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); - ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(ch); - // Check if the input resource is outside of the channel scope. - boolean outsideInputResource = false; - for (ChannelMember cm: ch.getInputChannelMembers()) { - if (cm.getResource().equals(srcRes) && cm.isOutside()) { - outsideInputResource = true; // Regarded as pull transfer. - break; - } - } - if (outsideInputResource) { - // Declare a field in the parent component to refer to the source resource of pull transfer. - if (!generatesComponent(srcRes.getResourceHierarchy())) { - srcRes = srcRes.getParent(); - } - String srcResName = getComponentName(srcRes.getResourceHierarchy()); -// if (resourceNode.getOutSideResource().getCommonPrefix(srcRes) == null && differentTreesAsDifferentServices) { - // Inter-service - if (!bDeclareClientField) { - // Declare a client field to connect to the source resource of pull transfer. - FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), clientField)); - bDeclareClientField = true; - } -// } else { -// // Inner-service -// // Declare a field to directly refer to the source resource of pull transfer. -// if (resourceNode.getParent().getResourceHierarchy() != srcRes.getResourceHierarchy()) { -// FieldDeclaration refFieldForPull = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); -// fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), refFieldForPull)); -// } -// } - noPullTransfer = false; - } - } - } - // Declare the state field in the parent component. - ResourceHierarchy res = resourceNode.getResourceHierarchy(); - if (((StoreAttribute) resourceNode.getAttribute()).isStored() && noPullTransfer && res.getNumParameters() == 0) { - String resName = getComponentName(res); - FieldDeclaration stateField = new FieldDeclaration(res.getResourceStateType(), toVariableName(resName)); - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), stateField)); - - - Map nameToParam = constructorParams.get(resourceNode.getParent().getResourceHierarchy()); - if (nameToParam == null) { - nameToParam = new HashMap<>(); - constructorParams.put(resourceNode.getParent().getResourceHierarchy(), nameToParam); - } - String varName = toVariableName(resName); - if (nameToParam.get(varName) == null) { - nameToParam.put(varName, new VariableDeclaration(res.getResourceStateType(), varName)); - } - } - } - - // (#2) Declare the getter method to obtain the resource state in an ancestor component. (complementary to #1) - 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) { - ResourceHierarchy r = entry.getKey(); - MethodDeclaration m = entry.getValue(); - if (r == ancestorNode.getResourceHierarchy() && m.getName().equals(getterName) - && (m.getParameters() == null ? 0 : m.getParameters().size()) == pathParams.size()) { - bExists = true; - break; - } - } - if (!bExists) { - Type resType = getImplStateType(resourceNode.getResourceHierarchy()); - MethodDeclaration stateGetter = null; - if (pathParams.size() == 0) { - stateGetter = new MethodDeclaration(getterName, resType); - } else { - stateGetter = new MethodDeclaration(getterName, false, resType, pathParams); - } - getters.add(new AbstractMap.SimpleEntry<>(ancestorNode.getResourceHierarchy(), stateGetter)); - } - } - - // Declare the getter accessor in the root resource. - if (resourceNode.getResourceHierarchy().getParent() != null) { - // For a non-root resource - MethodDeclaration getterAccessor = null; - List mainGetterParams = new ArrayList<>(); - String resourcePath = getGetterResourcePathAndPathParams(resourceNode.getPrimaryResourcePath(), mainGetterParams); - if (resourcePath.indexOf('/') > 0) { - // Remove the root resource from the path - resourcePath = resourcePath.substring(resourcePath.indexOf('/')); - } else { - resourcePath = ""; - } - if (mainGetterParams.size() > 0) { - getterAccessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()) + "Value", - false, - getImplStateType(resourceNode.getResourceHierarchy()), - mainGetterParams); - } else { - getterAccessor = new MethodDeclaration("get" + getComponentName(resourceNode.getResourceHierarchy()) + "Value", - getImplStateType(resourceNode.getResourceHierarchy())); - } - getterAccessor.setBody(new Block()); - ResourcePath resPath = new ResourcePath(resourceNode.getPrimaryResourcePath()); - for (int i = 0; i < mainGetterParams.size(); i++) { - Parameter pathParam = new Parameter(mainGetterParams.get(i).getName()); - resPath.replacePathParam(i, pathParam, null); - } - Expression getState = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(resPath, resPath.getRoot()); - getterAccessor.getBody().addStatement("return " + getState.toImplementation(new String[] {null}) + ";"); - - getterAccessor.addAnnotation(new Annotation("Produces", "MediaType.APPLICATION_JSON")); - getterAccessor.addAnnotation(new Annotation("GET")); - if (resourcePath.length() > 0) { - getterAccessor.addAnnotation(new Annotation("Path", "\"" + resourcePath + "\"")); - } - getterAccessors.put(resourceNode.getResourceHierarchy(), getterAccessor); - } - - // Declare a client field for push data transfer. - for (Edge resToCh: resourceNode.getOutEdges()) { - DataFlowEdge re = (DataFlowEdge) resToCh; - ChannelNode directDstChNode = (ChannelNode) re.getDestination(); - DataTransferChannel directDstCh = directDstChNode.getChannel(); - // Check if the input resource is outside of the channel scope. - boolean outsideInputResource = false; - for (ChannelMember cm: directDstCh.getInputChannelMembers()) { - if (cm.getResource().equals(resourceNode.getOutSideResource(directDstCh)) && cm.isOutside()) { - outsideInputResource = true; // Regarded as pull transfer. - break; - } - } - // Should take into account the channel hierarchy. - Set ancestorDstChannels = directDstChNode.getAncestors(); - Set descendantDstChannels = directDstChNode.getDescendants(); - Set outEdges = new HashSet<>(); - outEdges.addAll(directDstChNode.getOutEdges()); - for (ChannelNode ancestorDst: ancestorDstChannels) { - outEdges.addAll(ancestorDst.getOutEdges()); - } - for (ChannelNode descendantDst: descendantDstChannels) { - outEdges.addAll(descendantDst.getOutEdges()); - } - for (Edge chToRes: outEdges) { - // For each data transfer to dstNode:ResourceNode. - ResourceNode dstNode = ((ResourceNode) chToRes.getDestination()); - ChannelNode chNode = (ChannelNode) chToRes.getSource(); - DataTransferChannel ch = chNode.getChannel(); - // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = false; - ChannelMember out = null; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (dstNode.getInSideResources().contains(cm.getResource())) { - out = cm; - if (cm.isOutside()) { - outsideOutputResource = true; - break; - } - } - } - ResourcePath dstRes = out.getResource(); - // Also take into account the channel hierarchy to determine push/pull transfer. - if (descendantDstChannels.contains(chNode)) { - outsideOutputResource = true; // Regarded as (broadcasting) push transfer. - } - if (ancestorDstChannels.contains(chNode)) { - outsideInputResource = true; // Regarded as (collecting) pull transfer. - } - if (!bDeclareClientField && ((((PushPullAttribute) re.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource)) { - // For push transfer. - if (!generatesComponent(dstRes.getResourceHierarchy())) { - dstRes = dstRes.getParent(); - } - String dstResName = getComponentName(dstRes.getResourceHierarchy()); - if (outsideOutputResource || (resourceNode.getOutSideResource(ch).getCommonPrefix(dstRes) == null && differentTreesAsDifferentServices)) { - // Inter-service - if (!bDeclareClientField) { - // Declare a client field to connect to the destination resource of push transfer. - FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); - if (component != null) { - // A component is created for this resource. - component.addField(clientField); - } else { - // No component is created for this resource. - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), clientField)); - } - bDeclareClientField = true; - } - } else { - // Inner-service - // Declare a field to directly refer to the destination resource of push transfer. - FieldDeclaration dstRefField = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); - if (component != null) { - // A component is created for this resource. - if (resourceNode.getResourceHierarchy() != dstRes.getResourceHierarchy()) { - component.addField(dstRefField); - } - } else { - // No component is created for this resource. - if (resourceNode.getParent().getResourceHierarchy() != dstRes.getResourceHierarchy()) { - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), dstRefField)); - } - } - } - } - } - } - // Declare update methods called by other resources for push data transfer - // and reference fields for pull data transfer. - for (Edge chToRes : resourceNode.getInEdges()) { - ChannelNode directSrcChannel = (ChannelNode) chToRes.getSource(); - DataTransferChannel ch = directSrcChannel.getChannel(); - // Should take into account the channel hierarchy. - Set ancestorSrcChannels = directSrcChannel.getAncestors(); - Set descendantSrcChannels = directSrcChannel.getDescendants(); - Set inEdges = new HashSet<>(); - inEdges.addAll(directSrcChannel.getInEdges()); - for (ChannelNode ancestorSrc: ancestorSrcChannels) { - inEdges.addAll(ancestorSrc.getInEdges()); - } - for (ChannelNode descendantSrc: descendantSrcChannels) { - inEdges.addAll(descendantSrc.getInEdges()); - } - for (Edge resToCh: inEdges) { - // For each data transfer from srcResPath:ResourcePath to resourceNode:ResourceNode. - DataFlowEdge re = (DataFlowEdge) resToCh; - ChannelNode indirectSrcChNode = (ChannelNode) re.getDestination(); - DataTransferChannel indirectSrcCh = indirectSrcChNode.getChannel(); - ResourcePath srcResPath = ((ResourceNode) re.getSource()).getOutSideResource(indirectSrcCh); - // Check if the input resource is outside of the channel scope. - boolean outsideInputResource = false; - for (ChannelMember cm: indirectSrcCh.getInputChannelMembers()) { - if (cm.getResource().equals(srcResPath) && cm.isOutside()) { - outsideInputResource = true; // Regarded as pull transfer. - break; - } - } - // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = false; - ChannelMember out = null; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (resourceNode.getInSideResources().contains(cm.getResource())) { - out = cm; - if (cm.isOutside()) { - outsideOutputResource = true; // Regarded as push transfer. - break; - } - } - } - // Also take into account the channel hierarchy to determine push/pull transfer. - if (ancestorSrcChannels.contains(indirectSrcChNode)) { - outsideOutputResource = true; // Regarded as (broadcasting) push transfer. - } - if (descendantSrcChannels.contains(indirectSrcChNode)) { - outsideInputResource = true; // Regarded as (collecting) pull transfer. - } - String srcResName = getComponentName(srcResPath.getResourceHierarchy()); - Type srcType = srcResPath.getResourceStateType(); - if (!generatesComponent(srcResPath.getResourceHierarchy())) { - srcResPath = srcResPath.getParent(); - } - if ((((PushPullAttribute) re.getAttribute()).getSelectedOption() != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { - // For pull transfer. - if (outsideInputResource || (resourceNode.getInSideResource(ch).getCommonPrefix(srcResPath) == null && differentTreesAsDifferentServices)) { - // Inter-service - if (!bDeclareClientField) { - // Declare a client field to connect to the source resource of pull transfer. - FieldDeclaration clientField = new FieldDeclaration(typeClient, "client", "ClientBuilder.newClient()"); - if (component != null) { - // A component is created for this resource. - component.addField(clientField); - } else { - // No component is created for this resource. - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), clientField)); - } - bDeclareClientField = true; - } - } else { - // Inner-service - // Declare a field to directly refer to the source resource of pull transfer. - FieldDeclaration srcRefField = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); - if (component != null) { - // A component is created for this resource. - if (resourceNode.getResourceHierarchy() != srcResPath.getResourceHierarchy()) { - component.addField(srcRefField); - } - } else { - // No component is created for this resource. - if (resourceNode.getParent().getResourceHierarchy() != srcResPath.getResourceHierarchy()) { - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), srcRefField)); - } - } - } - } else { - // For push transfer. - boolean hasRestAPI = false; - boolean isRestAPI = false; - if (outsideOutputResource || (resourceNode.getInSideResource(ch).getCommonPrefix(srcResPath) == null && differentTreesAsDifferentServices)) { - // Inter-service - hasRestAPI = true; - if (resourceNode.getParent() == null) { - // A root resource - isRestAPI = true; - } - } - // Declare an update method in the type of the destination resource. - ArrayList params = new ArrayList<>(); - getUpdateResourcePathAndPathParams(out.getResource(), params, isRestAPI); // Path parameters to identify the self resource. - for (Selector selector: ch.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - VariableDeclaration chParam = new VariableDeclaration(selVar.getType(), selVar.getName()); - if (isRestAPI) chParam.addAnnotation(new Annotation("FormParam", "\"" + selVar.getName() + "\"")); - params.add(chParam); // A channel parameter to specify the context of the collaboration. - } - } - String srcName = toVariableName(srcResName); - VariableDeclaration param = new VariableDeclaration(srcType, srcName); - if (isRestAPI) param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); - params.add(param); // The state of the source resource to carry the data-flow. - for (ResourcePath refRes: ch.getReferenceResources()) { - if (!refRes.equals(resourceNode.getInSideResource(ch))) { - String refName = toVariableName(getComponentName(refRes.getResourceHierarchy())); - param = new VariableDeclaration(refRes.getResourceStateType(), refName); - if (isRestAPI) param.addAnnotation(new Annotation("FormParam", "\"" + refName + "\"")); - params.add(param); - } - } - MethodDeclaration update = null; - if (component != null) { - // A component is created for this resource. - update = new MethodDeclaration("updateFrom" + srcResName, false, typeVoid, params); - } else { - // No component is created for this resource. - String resourceName = getComponentName(resourceNode.getResourceHierarchy()); - update = new MethodDeclaration("update" + resourceName + "From" + srcResName, false, typeVoid, params); - } - // Determine whether the update method is put or post or delete. - boolean isPut = false; - boolean isDelete = false; - for (ChannelMember cm: ch.getOutputChannelMembers()) { - if (resourceNode.getInSideResources().contains(cm.getResource())) { - if (cm.getStateTransition().isRightUnary()) { - isPut = true; - } else { - isPut = false; - Expression nextExp = cm.getStateTransition().getNextStateExpression(); - if (nextExp instanceof Term) { - Symbol rootSymbol = ((Term) nextExp).getSymbol(); - if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { - isDelete = true; - } else if (rootSymbol.equals(DataConstraintModel.cond)) { - Expression childExp = ((Term) nextExp).getChild(1); - if (childExp instanceof Term) { - rootSymbol = ((Term) childExp).getSymbol(); - if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { - isDelete = true; - } - } - childExp = ((Term) nextExp).getChild(2); - if (childExp instanceof Term) { - rootSymbol = ((Term) childExp).getSymbol(); - if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { - isDelete = true; - } - } - } -// HashMap subTerms = ((Term) nextExp).getSubTerms(Term.class); -// for (Term subTerm: subTerms.values()) { -// Symbol rootSymbol = subTerm.getSymbol(); -// if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { -// isDelete = true; -// break; -// } -// } - } - } - } - } - if (isRestAPI) { - if (isPut) { - update.addAnnotation(new Annotation("PUT")); - } else { - if (!isDelete) { - update.addAnnotation(new Annotation("POST")); - } else { - update.addAnnotation(new Annotation("DELETE")); - } - } - } - // Calculate in-degree of the destination resource. - Set inResources = new HashSet<>(); - for (ResourceNode rn: graph.getResourceNodes(out.getResource().getResourceHierarchy())) { - // ResourceNodes that have the same ResourceHierarchy. - for (Edge chToRes2: rn.getInEdges()) { - for (Edge resToCh2: chToRes2.getSource().getInEdges()) { - inResources.add(((ResourceNode) resToCh2.getSource()).getResourceHierarchy()); - } - } - } - int inDegree = inResources.size(); - if (inDegree > 1 - || (inDegree == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { - // Declare a field to cache the state of the source resource in the type of the destination resource. - ResourceHierarchy cacheRes = ((ResourceNode) re.getSource()).getResourceHierarchy(); - FieldDeclaration cacheField = new FieldDeclaration(cacheRes.getResourceStateType(), srcName, getInitializer(cacheRes)); - if (component != null) { - // A component is created for this resource. - component.addField(cacheField); - } else { - // No component is created for this resource. - fields.add(new AbstractMap.SimpleEntry<>(resourceNode.getParent().getResourceHierarchy(), cacheField)); - } - if (inDegree > 1) { - // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. - if (isRestAPI) update.addAnnotation(new Annotation("Path", "\"/" + srcName + "\"")); - } - } - if (component != null) { - // A component is created for this resource. - component.addMethod(update); - } else { - // No component is created for this resource. - String updateMethodName = update.getName(); - Map nameToMethod = updates.get(resourceNode.getParent().getResourceHierarchy()); - if (nameToMethod == null) { - nameToMethod = new HashMap<>(); - updates.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod); - } - if (nameToMethod.get(updateMethodName) == null) { - nameToMethod.put(updateMethodName, update); - } - } - if (hasRestAPI && !isRestAPI) { - // Declare an update accessor method in the type of root resource. - String updateMethodName = update.getName(); - params = new ArrayList<>(); - String resourcePath = getUpdateResourcePathAndPathParams(out.getResource(), params, true); // Path parameters to identify the self resource. - if (resourcePath.indexOf('/') > 0) { - // Remove the root resource from the path - resourcePath = resourcePath.substring(resourcePath.indexOf('/')); - } else { - resourcePath = ""; - } - for (Selector selector: ch.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - VariableDeclaration chParam = new VariableDeclaration(selVar.getType(), selVar.getName()); - chParam.addAnnotation(new Annotation("FormParam", "\"" + selVar.getName() + "\"")); - params.add(chParam); // A channel parameter to specify the context of the collaboration. - } - } - param = new VariableDeclaration(srcType, srcName); - param.addAnnotation(new Annotation("FormParam", "\"" + srcName + "\"")); - params.add(param); // The state of the source resource to carry the data-flow. - for (ResourcePath refRes: ch.getReferenceResources()) { - if (!refRes.equals(resourceNode.getInSideResource(ch))) { - String refName = toVariableName(getComponentName(refRes.getResourceHierarchy())); - param = new VariableDeclaration(refRes.getResourceStateType(), refName); - param.addAnnotation(new Annotation("FormParam", "\"" + refName + "\"")); - params.add(param); - } - } - MethodDeclaration updateAccessor = new MethodDeclaration(updateMethodName, false, typeVoid, params); - if (isPut) { - updateAccessor.addAnnotation(new Annotation("PUT")); - } else { - if (!isDelete) { - updateAccessor.addAnnotation(new Annotation("POST")); - } else { - updateAccessor.addAnnotation(new Annotation("DELETE")); - } - } - if (inDegree > 1) { - // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. - resourcePath += "/" + toVariableName(srcResName); - } - updateAccessor.addAnnotation(new Annotation("Path", "\"" + resourcePath + "\"")); - Map nameToMethod = updates.get(resourceNode.getResourceHierarchy().getRoot()); - if (nameToMethod == null) { - nameToMethod = new HashMap<>(); - updates.put(resourceNode.getResourceHierarchy().getRoot(), nameToMethod); - } - if (nameToMethod.get(updateMethodName) == null) { - nameToMethod.put(updateMethodName, updateAccessor); - } - } - } - } - } - - // Declare the input method in each resource and the root resource. - for (Channel ch : model.getInputChannels()) { - for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) { - if (!cm.isOutside()) { - if (priorMemberForInputChannel.get(ch) == null) { - priorMemberForInputChannel.put(ch, cm); // The receiver of the input event when multiple output resources are defined for the channel. - } - } - } - for (ChannelMember cm : ((DataTransferChannel) ch).getOutputChannelMembers()) { - if (resourceNode.getInSideResources().contains(cm.getResource())) { - Expression message = cm.getStateTransition().getMessageExpression(); - if (message instanceof Term) { - // In each resource. - ArrayList resInputParams = new ArrayList<>(); - ArrayList rootInputParams = new ArrayList<>(); - String resourcePath = getInputMethodResourcePathAndPathParams(cm.getResource(), rootInputParams); // Path parameters for the input REST API. - if (resourcePath.indexOf('/') > 0) { - // Remove the root resource from the path - resourcePath = resourcePath.substring(resourcePath.indexOf('/')); - } else { - resourcePath = ""; - } - // The path parameters are not to be passed to the input method of each resource (resInputParams) - // because they are always equal to either channel selectors or message parameters. - - // Channel parameters to specify the context of the collaboration. - for (Selector selector: ch.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - VariableDeclaration chParam = new VariableDeclaration(selVar.getType(), selVar.getName()); - resInputParams.add(chParam); - } - } - // Message parameters to carry the data-flows. - for (Map.Entry varEnt: message.getVariables().entrySet()) { - Variable var = varEnt.getValue(); - String refVarName = null; - for (ChannelMember refCm: ((DataTransferChannel) ch).getReferenceChannelMembers()) { - Expression varExp = refCm.getStateTransition().getMessageExpression().getSubTerm(varEnt.getKey()); - if (varExp != null && varExp instanceof Variable) { - if (refCm.getStateTransition().getCurStateExpression().contains(varExp)) { - refVarName = refCm.getResource().getLeafResourceName(); - break; - } - } - } - if (refVarName != null) { - // var has come from a reference resource. - VariableDeclaration param = new VariableDeclaration(var.getType(), refVarName); - resInputParams.add(param); - } else { - // var has not come from reference resource. - String paramName = var.getName(); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - resInputParams.add(param); - if (!resourcePath.contains("{" + paramName+ "}")) { - param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("FormParam", "\"" + paramName + "\"")); - rootInputParams.add(param); - } - } - } - - if (resourceNode.getResourceHierarchy().getParent() != null && (component != null || resourceNode.getResourceHierarchy().getParent().getParent() != null)) { - // The case that the input accessor is needed. - String inputMethodName = ((Term) message).getSymbol().getImplName(); - if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) { - inputMethodName += "For" + getComponentName(cm.getResource().getResourceHierarchy()); - } - MethodDeclaration input = new MethodDeclaration(inputMethodName, false, typeVoid, resInputParams); - if (component != null) { - // A component is created for this resource. - component.addMethod(input); - } else { - // No component is created for this resource. - Map nameToMethod = inputs.get(resourceNode.getParent().getResourceHierarchy()); - if (nameToMethod == null) { - nameToMethod = new HashMap<>(); - inputs.put(resourceNode.getParent().getResourceHierarchy(), nameToMethod); - } - if (nameToMethod.get(inputMethodName) == null) { - nameToMethod.put(inputMethodName, input); - } - } - } - - // For the root resource. - if (priorMemberForInputChannel.get(ch) ==null || cm == priorMemberForInputChannel.get(ch)) { - // If cm is the receiver of the input event. - priorMemberForInputChannel.put(ch, cm); - String messageSymbol = ((Term) message).getSymbol().getImplName(); - MethodDeclaration inputAccessor = new MethodDeclaration(messageSymbol, false, typeVoid, rootInputParams); - if (cm.getStateTransition().isRightUnary()) { - inputAccessor.addAnnotation(new Annotation("PUT")); - } else { - boolean isDelete = false; - Expression nextExp = cm.getStateTransition().getNextStateExpression(); - if (nextExp instanceof Term) { - Symbol rootSymbol = ((Term) nextExp).getSymbol(); - if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { - isDelete = true; - } else if (rootSymbol.equals(DataConstraintModel.cond)) { - Expression childExp = ((Term) nextExp).getChild(1); - if (childExp instanceof Term) { - rootSymbol = ((Term) childExp).getSymbol(); - if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { - isDelete = true; - } - } - childExp = ((Term) nextExp).getChild(2); - if (childExp instanceof Term) { - rootSymbol = ((Term) childExp).getSymbol(); - if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { - isDelete = true; - } - } - } -// HashMap subTerms = ((Term) nextExp).getSubTerms(Term.class); -// for (Term subTerm: subTerms.values()) { -// Symbol rootSymbol = subTerm.getSymbol(); -// if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { -// isDelete = true; -// break; -// } -// } - } - if (!isDelete) { - inputAccessor.addAnnotation(new Annotation("POST")); - } else { - inputAccessor.addAnnotation(new Annotation("DELETE")); - } - } - if (resourcePath.length() > 0) { - inputAccessor.addAnnotation(new Annotation("Path", "\"" + resourcePath + "\"")); - } - Map nameToMethod = inputAccessors.get(resourceNode.getResourceHierarchy()); - if (nameToMethod == null) { - nameToMethod = new HashMap<>(); - inputAccessors.put(resourceNode.getResourceHierarchy(), nameToMethod); - } - nameToMethod.put(messageSymbol, inputAccessor); - } - } else if (message instanceof Variable) { - // In each resource. - ArrayList resInputParams = new ArrayList<>(); - int v = 1; - if (cm.getResource().getLastParam() != null) { - Expression pathParam = cm.getResource().getLastParam(); - if (pathParam instanceof Variable) { - Variable var = (Variable) pathParam; - String paramName = var.getName(); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - resInputParams.add(param); - } else if (pathParam instanceof Term) { - Term var = (Term) pathParam; - String paramName = "v" + v; - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - resInputParams.add(param); - } - v++; - } - if (cm.getResource().getResourceHierarchy().getParent() != null && cm.getResource().getResourceHierarchy().getParent().getParent() != null) { - String inputMethodName = ((Variable) message).getName(); - if (((DataTransferChannel) ch).getOutputChannelMembers().size() > 1) { - inputMethodName += "For" + getComponentName(cm.getResource().getResourceHierarchy()); - } - MethodDeclaration input = new MethodDeclaration(inputMethodName, false, typeVoid, null); - if (component != null) { - // A component is created for this resource. - component.addMethod(input); - } else { - // No component is created for this resource. - Map nameToMethod = inputs.get(cm.getResource().getParent().getResourceHierarchy()); - if (nameToMethod == null) { - nameToMethod = new HashMap<>(); - inputs.put(cm.getResource().getParent().getResourceHierarchy(), nameToMethod); - } - if (nameToMethod.get(inputMethodName) == null) { - nameToMethod.put(inputMethodName, input); - } - } - } - - // For the root resource. - if (priorMemberForInputChannel.get(ch) ==null || cm == priorMemberForInputChannel.get(ch)) { - // If cm is the receiver of the input event. - priorMemberForInputChannel.put(ch, cm); - ArrayList rootInputParams = new ArrayList<>(); - String resourcePath = getGetterResourcePathAndPathParams(cm.getResource(), rootInputParams); - if (resourcePath.indexOf('/') > 0) { - // Remove the root resource from the path - resourcePath = resourcePath.substring(resourcePath.indexOf('/')); - } else { - resourcePath = ""; - } - String messageSymbol = ((Variable) message).getName(); - MethodDeclaration inputAccessor = new MethodDeclaration(messageSymbol, false, typeVoid, rootInputParams); - if (cm.getStateTransition().isRightUnary()) { - inputAccessor.addAnnotation(new Annotation("PUT")); - } else { - boolean isDelete = false; - Expression nextExp = cm.getStateTransition().getNextStateExpression(); - if (nextExp instanceof Term) { - Symbol rootSymbol = ((Term) nextExp).getSymbol(); - if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { - isDelete = true; - } else if (rootSymbol.equals(DataConstraintModel.cond)) { - Expression childExp = ((Term) nextExp).getChild(1); - if (childExp instanceof Term) { - rootSymbol = ((Term) childExp).getSymbol(); - if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { - isDelete = true; - } - } - childExp = ((Term) nextExp).getChild(2); - if (childExp instanceof Term) { - rootSymbol = ((Term) childExp).getSymbol(); - if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { - isDelete = true; - } - } - } -// HashMap subTerms = ((Term) nextExp).getSubTerms(Term.class); -// for (Term subTerm: subTerms.values()) { -// Symbol rootSymbol = subTerm.getSymbol(); -// if (rootSymbol.equals(DataConstraintModel.delete) || rootSymbol.equals(DataConstraintModel.remove)) { -// isDelete = true; -// break; -// } -// } - } - if (!isDelete) { - inputAccessor.addAnnotation(new Annotation("POST")); - } else { - inputAccessor.addAnnotation(new Annotation("DELETE")); - } - } - if (resourcePath.length() > 0) { - inputAccessor.addAnnotation(new Annotation("Path", "\"" + resourcePath + "\"")); - } - Map nameToMethod = inputAccessors.get(resourceNode.getResourceHierarchy()); - if (nameToMethod == null) { - nameToMethod = new HashMap<>(); - inputAccessors.put(resourceNode.getResourceHierarchy(), nameToMethod); - } - nameToMethod.put(messageSymbol, inputAccessor); - } - } - } - } - } - } - - // Add leaf getter methods to the parent components. - for (Map.Entry entry: getters) { - resourceComponents.get(entry.getKey()).addMethod(entry.getValue()); - } - - // Add leaf update methods to the parent components. - for (Map.Entry> entry: updates.entrySet()) { - for (MethodDeclaration update: entry.getValue().values()) { - resourceComponents.get(entry.getKey()).addMethod(update); - } - } - - // Add leaf input methods to the parent components. - for (Map.Entry> entry: inputs.entrySet()) { - for (MethodDeclaration input: entry.getValue().values()) { - resourceComponents.get(entry.getKey()).addMethod(input); - } - } - - // Add leaf reference fields to the parent components. - for (Map.Entry entry: fields) { - ResourceHierarchy resource = entry.getKey(); - FieldDeclaration field = entry.getValue(); - TypeDeclaration component = resourceComponents.get(resource); - boolean existsField = false; - for (FieldDeclaration fld: component.getFields()) { - if (fld.getName().equals(field.getName())) { - existsField = true; - break; - } - } - if (!existsField) { - component.addField(field); - if (field.getType().equals(typeClient)) { - for (CompilationUnit cu: codes) { - if (cu.types().contains(component)) { - cu.addImport(new ImportDeclaration("jakarta.ws.rs.client.*")); - break; - } - } - } - } - } - - // Add constructor parameters to the ancestor components. - for (ResourceNode root: graph.getRootResourceNodes()) { - addConstructorParameters(root.getResourceHierarchy(), resourceComponents, resourceConstructors, constructorParams); - } - - // Add accessors. - for (ResourceHierarchy rootRes: model.getResourceHierarchies()) { - if (rootRes.getParent() == null) { - // root resource - TypeDeclaration rootComponent = resourceComponents.get(rootRes); - // Add getter accessors. - for (ResourceHierarchy res: getterAccessors.keySet()) { - if (rootRes.isAncestorOf(res)) { - rootComponent.addMethod(getterAccessors.get(res)); - } - } - // Add input accessors. - for (ResourceHierarchy res: inputAccessors.keySet()) { - if (rootRes.isAncestorOf(res)) { - for (MethodDeclaration inputAccessor: inputAccessors.get(res).values()) { - rootComponent.addMethod(inputAccessor); - } - } - } - } - } - - // Declare the Pair class. - boolean isCreatedPair = false; - for(Node n : resources) { - ResourceNode rn = (ResourceNode) n; - if(isCreatedPair) continue; - if(model.getType("Pair").isAncestorOf(rn.getResourceStateType())) { - TypeDeclaration type = new TypeDeclaration("Pair"); - type.addField(new FieldDeclaration(new Type("Double", "T"), "left")); - type.addField(new FieldDeclaration(new Type("Double", "T"), "right")); - - MethodDeclaration constructor = new MethodDeclaration("Pair", true); - constructor.addParameter(new VariableDeclaration(new Type("Double", "T"), "left")); - constructor.addParameter(new VariableDeclaration(new Type("Double", "T"), "right")); - Block block = new Block(); - block.addStatement("this.left = left;"); - block.addStatement("this.right = right;"); - constructor.setBody(block); - type.addMethod(constructor); - - for(FieldDeclaration field : type.getFields()) { - MethodDeclaration getter = new MethodDeclaration( - "get" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1), - new Type("Double","T")); - getter.setBody(new Block()); - getter.getBody().addStatement("return " + field.getName() + ";"); - type.addMethod(getter); - } - -// MethodDeclaration toStr = new MethodDeclaration("toString", false, DataConstraintModel.typeString, null); -// block = new Block(); -// block.addStatement("return \"{\\\"\" + left + \"\\\":\\\"\" + right + \"\\\"}\";"); -// toStr.setBody(block); -// type.addMethod(toStr); - - CompilationUnit cu = new CompilationUnit(type); - cu.addImport(new ImportDeclaration("java.util.*")); - codes.add(cu); - - isCreatedPair = true; - } - } - - return codes; - } - - private static List addConstructorParameters(ResourceHierarchy resource, - Map resourceComponents, - Map resourceConstructors, - Map> constructorParams) { - List params = new ArrayList<>(); - for (ResourceHierarchy child: resource.getChildren()) { - params.addAll(addConstructorParameters(child, resourceComponents, resourceConstructors, constructorParams)); - } - if (constructorParams.get(resource) != null) { - for (VariableDeclaration param: constructorParams.get(resource).values()) { - params.add(param); - } - } - if (params.size() > 0) { - MethodDeclaration constructor = resourceConstructors.get(resource); - if (constructor == null) { - if (resourceComponents.get(resource) != null) { - String resourceName = getComponentName(resource); - constructor = new MethodDeclaration(resourceName, true); - Block body = new Block(); - constructor.setBody(body); - resourceComponents.get(resource).addMethod(constructor); - resourceConstructors.put(resource, constructor); - } - } - if (constructor != null) { - for (VariableDeclaration param: params) { - constructor.addParameter(param); - constructor.getBody().addStatement("this." + toVariableName(param.getName()) + " = " + toVariableName(param.getName()) + ";"); - } - } - } - if (resource.getNumParameters() > 0) params.clear(); - return params; - } - - private static String getGetterResourcePathAndPathParams(ResourcePath resPath, List pathParams) { - int v = 1; - List params = new ArrayList<>(); - for (Expression pathParam: resPath.getPathParams()) { - if (pathParam instanceof Variable) { - Variable var = (Variable) pathParam; - String paramName = var.getName(); - params.add("{" + paramName + "}"); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - pathParams.add(param); - } else if (pathParam instanceof Term) { - Term var = (Term) pathParam; - String paramName = "v" + v; - params.add("{" + paramName + "}"); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - pathParams.add(param); - } - v++; - } - return resPath.getResourceHierarchy().toResourcePath(params); - } - - private static String getUpdateResourcePathAndPathParams(ResourcePath resPath, ArrayList rootParams, boolean isRestAPI) { - int v = 1; - List params = new ArrayList<>(); - for (Expression pathParam: resPath.getPathParams()) { - if (pathParam instanceof Variable) { - Variable var = (Variable) pathParam; - String paramName = null; - if (isRestAPI) { - paramName = var.getName(); - } else { - paramName = "self" + (v > 1 ? v : ""); - } - params.add("{" + paramName + "}"); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - if (isRestAPI) param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - rootParams.add(param); - } else if (pathParam instanceof Term) { - Term var = (Term) pathParam; - String paramName = null; - if (isRestAPI) { - paramName = "v" + v; - } else { - paramName = "self" + (v > 1 ? v : ""); - } - params.add("{" + paramName + "}"); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - if (isRestAPI) param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - rootParams.add(param); - } - v++; - } - return resPath.getResourceHierarchy().toResourcePath(params); - } - - private static String getInputMethodResourcePathAndPathParams(ResourcePath resPath, ArrayList rootInputParams) { - int v = 1; - List params = new ArrayList<>(); - if (resPath.getLastParam() != null) { - Expression pathParam = resPath.getLastParam(); - if (pathParam instanceof Variable) { - Variable var = (Variable) pathParam; - String paramName = var.getName(); - params.add("{" + paramName + "}"); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - rootInputParams.add(param); - } else if (pathParam instanceof Term) { - Term var = (Term) pathParam; - String paramName = "v" + v; - params.add("{" + paramName + "}"); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - rootInputParams.add(param); - } - v++; - } - if (resPath.getParent() != null) { - for (Expression pathParam: resPath.getParent().getPathParams()) { - if (pathParam instanceof Variable) { - Variable var = (Variable) pathParam; - String paramName = var.getName(); - params.add("{" + paramName + "}"); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - rootInputParams.add(param); - } else if (pathParam instanceof Term) { - Term var = (Term) pathParam; - String paramName = "v" + v; - params.add("{" + paramName + "}"); - VariableDeclaration param = new VariableDeclaration(var.getType(), paramName); - param.addAnnotation(new Annotation("PathParam", "\"" + paramName + "\"")); - rootInputParams.add(param); - } - v++; - } - } - return resPath.getResourceHierarchy().toResourcePath(params); - } - - private static String getInitializer(ResourceHierarchy res) { - Type stateType = res.getResourceStateType(); - String initializer = null; - if (res.getInitialValue() != null) { - initializer = res.getInitialValue().toImplementation(new String[] {""}); - } else if (stateType != null) { - initializer = DataConstraintModel.getDefaultValue(stateType); - } - return initializer; - } - - static public ArrayList getCodes(ArrayList codeTree) { - ArrayList codes = new ArrayList<>(); - for (TypeDeclaration type : codeTree) { - codes.add("public class " + type.getTypeName() + "{"); - for (FieldDeclaration field : type.getFields()) { - if (type.getTypeName() != mainTypeName) { - String cons = "\t" + "private " + field.getType().getInterfaceTypeName() + " " - + field.getName(); - if (DataConstraintModel.isListType(field.getType())) - cons += " = new " + field.getType().getImplementationTypeName() + "()"; - cons += ";"; - codes.add(cons); - } else { - String cons = "\t" + "private " + field.getType().getInterfaceTypeName() + " " - + field.getName() + " = new " + field.getType().getTypeName() + "("; - cons += ");"; - codes.add(cons); - } - } - codes.add(""); - for (MethodDeclaration method : type.getMethods()) { - String varstr = "\t" + "public " + method.getReturnType().getInterfaceTypeName() + " " - + method.getName() + "("; - if (method.getParameters() != null) { - for (VariableDeclaration var : method.getParameters()) { - varstr += var.getType().getInterfaceTypeName() + " " + var.getName() + ","; - } - if (!method.getParameters().isEmpty()) - varstr = varstr.substring(0, varstr.length() - 1); - } - if (method.getBody() != null) { - for (String str : method.getBody().getStatements()) { - codes.add("\t\t" + str + ";"); - } - } - codes.add(varstr + ")" + "{"); - codes.add("\t" + "}"); - codes.add(""); - } - codes.add("}"); - codes.add(""); - } - return codes; - } - - static public IResourceStateAccessor pushAccessor = new IResourceStateAccessor() { - @Override - public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { - ResourcePath targetRes = target.getResource(); - ResourcePath fromRes = from.getResource(); - if (targetRes.equals(fromRes)) { - return new Field("value", - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - // use the cached value as the current state - return new Field(toVariableName(getComponentName(targetRes.getResourceHierarchy())), - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - - @Override - public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { - ResourcePath targetRes = target.getResource(); - return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - - @Override - public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { - if (fromRes != null && targetRes.equals(fromRes)) { - return new Field("value", - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - return null; - } - }; - static public IResourceStateAccessor pullAccessor = new IResourceStateAccessor() { - @Override - public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { - ResourcePath targetRes = target.getResource(); - if (from != null && !target.isOutside()) { - ResourcePath fromRes = from.getResource(); - if (targetRes.getCommonPrefix(fromRes) != null) { - return getDirectStateAccessorFor(targetRes, fromRes); - } - } - // for reference channel member - return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - - @Override - public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { - ResourcePath targetRes = target.getResource(); - if (from != null && !target.isOutside()) { - ResourcePath fromRes = from.getResource(); - if (targetRes.getCommonPrefix(fromRes) != null) { - return getDirectStateAccessorFor(targetRes, fromRes); - } - } - // Get the next state through a local variable which is to be initialized by a response of a GET API. - return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - - @Override - public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { - if (fromRes != null && !fromRes.getResourceHierarchy().isAncestorOf(targetRes.getResourceHierarchy())) { - if (targetRes.equals(fromRes)) { - return new Field("value", - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - // for reference channel member - return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } else { - // (#3) access from an ancestor or outside of the hierarchy (must be kept consistent with #4) - Stack pathStack = new Stack<>(); - ResourcePath curPath = targetRes; - do { - if (fromRes != null && curPath.equals(fromRes)) break; - pathStack.push(curPath); - curPath = curPath.getParent(); - } while (curPath != null); - // iterate from the `from' resource - Term getter = null; - int arity = 2; - boolean doesChainInvocations = true; - while (!pathStack.empty()) { - curPath = pathStack.pop(); - String typeName = getComponentName(curPath.getResourceHierarchy()); - if (getter == null && fromRes == null) { - // root resource - String fieldName = toVariableName(typeName); - getter = new Field(fieldName, new Type(typeName, typeName)); - } else { - 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) { - Expression param = curPath.getLastParam(); - if (param != null) { - newGetter.addChild(param); - newGetter.getSymbol().setArity(2); - } - } - getter = newGetter; - } else { - // add the last path parameter. - if (curPath.getResourceHierarchy().getNumParameters() > 0) { - Expression param = curPath.getLastParam(); - if (param != null) { - getter.getSymbol().setArity(arity); - getter.addChild(param); - } - } - } - arity = 2; - doesChainInvocations = true; - } else { - // to get a descendant resource directly. (e.g, .todos.{year}.{month}.{day}.{id} ==> .getTodos().getTodo(year, month, day, id)) - if (doesChainInvocations) { - Term newGetter = new Term(new Symbol("get" + typeName, -1, Symbol.Type.METHOD)); - newGetter.addChild(getter); - getter = newGetter; - doesChainInvocations = false; - } - if (curPath.getResourceHierarchy().getNumParameters() > 0) { - // may change the symbol name - getter.getSymbol().changeName("get" + typeName); - // add a path parameter. - Expression param = curPath.getLastParam(); - if (param != null) { - getter.getSymbol().setArity(arity); - getter.addChild(param); - arity++; - } - } - } - } - } - - if (generatesComponent(targetRes.getResourceHierarchy())) { - Term newGetter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); - newGetter.addChild(getter); - getter = newGetter; - } - return getter; - } - } - }; - static public IResourceStateAccessor refAccessor = new IResourceStateAccessor() { - @Override - public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { - ResourcePath targetRes = target.getResource(); - ResourcePath fromRes = from.getResource(); - if (targetRes.equals(fromRes)) { - return new Field("value", - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - // for reference channel member - return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - - @Override - public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { - ResourcePath targetRes = target.getResource(); - return new Parameter(toVariableName(getComponentName(targetRes.getResourceHierarchy())), - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - - @Override - public Expression getDirectStateAccessorFor(ResourcePath targetRes, ResourcePath fromRes) { - if (fromRes != null && targetRes.equals(fromRes)) { - return new Field("value", - targetRes.getResourceStateType() != null ? targetRes.getResourceStateType() - : DataConstraintModel.typeInt); - } - return null; - } - }; -} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java deleted file mode 100644 index 9552937..0000000 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ /dev/null @@ -1,1740 +0,0 @@ -package generators; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.Stack; - -import algorithms.TypeInference; -import code.ast.CodeUtil; -import code.ast.CompilationUnit; -import code.ast.MethodDeclaration; -import code.ast.TypeDeclaration; -import code.ast.VariableDeclaration; -import models.Edge; -import models.Node; -import models.algebra.Constant; -import models.algebra.Expression; -import models.algebra.Field; -import models.algebra.InvalidMessage; -import models.algebra.Parameter; -import models.algebra.ParameterizedIdentifierIsFutureWork; -import models.algebra.Position; -import models.algebra.Symbol; -import models.algebra.Term; -import models.algebra.Type; -import models.algebra.UnificationFailed; -import models.algebra.ValueUndefined; -import models.algebra.Variable; -import models.dataConstraintModel.Channel; -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; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.DataTransferChannel; -import models.dataFlowModel.PushPullAttribute; -import models.dataFlowModel.PushPullValue; -import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; -import models.dataFlowModel.ChannelNode; -import models.dataFlowModel.DataFlowEdge; -import models.dataFlowModel.DataFlowGraph; -import models.dataFlowModel.ResourceNode; -import models.dataFlowModel.StoreAttribute; -import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; - -public class JerseyMethodBodyGenerator { - private static String baseURL = "http://localhost:8080"; - - public static ArrayList doGenerate(DataFlowGraph graph, DataTransferModel model, ArrayList codes) { - // Create a map from type names (lower case) to their types. - Map componentMap = new HashMap<>(); - for (CompilationUnit code: codes) { - for (TypeDeclaration component: code.types()) { - componentMap.put(component.getTypeName(), component); - } - } - - // Generate the body of each update or getter method. - try { - Set chainedCalls = new HashSet<>(); - Map> referredResources = new HashMap<>(); - for (Edge e: graph.getEdges()) { - DataFlowEdge resToCh = (DataFlowEdge) e; - if (!resToCh.isChannelToResource()) { - PushPullAttribute pushPull = (PushPullAttribute) resToCh.getAttribute(); - ResourceNode src = (ResourceNode) resToCh.getSource(); - ChannelNode directDstChNode = (ChannelNode) resToCh.getDestination(); - DataTransferChannel directDstCh = directDstChNode.getChannel(); - // Should take into account the channel hierarchy. - Set ancestorDstChannels = directDstChNode.getAncestors(); - Set descendantDstChannels = directDstChNode.getDescendants(); - Set outEdges = new HashSet<>(); - outEdges.addAll(directDstChNode.getOutEdges()); - for (ChannelNode ancestorDst: ancestorDstChannels) { - outEdges.addAll(ancestorDst.getOutEdges()); - } - for (ChannelNode descendantDst: descendantDstChannels) { - outEdges.addAll(descendantDst.getOutEdges()); - } - for (Edge chToRes: outEdges) { - // For each data transfer from src:ResourceNode to dst:ResourceNode. - ResourceNode dst = (ResourceNode) chToRes.getDestination(); - String srcResourceName = JerseyCodeGenerator.getComponentName(src.getResourceHierarchy()); - String dstResourceName = JerseyCodeGenerator.getComponentName(dst.getResourceHierarchy()); - TypeDeclaration srcComponent = componentMap.get(srcResourceName); - TypeDeclaration dstComponent = componentMap.get(dstResourceName); -// DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); - ChannelNode chNode = (ChannelNode) chToRes.getSource(); - DataTransferChannel ch = chNode.getChannel(); - for (ChannelMember out: ch.getOutputChannelMembers()) { - if (dst.getInSideResources().contains(out.getResource())) { - // Check if the input resource is outside of the channel scope. - boolean outsideInputResource = false; - ChannelMember in = null; - for (ChannelMember cm: directDstCh.getInputChannelMembers()) { - if (src.getOutSideResources().contains(cm.getResource())) { - in = cm; - if (cm.isOutside()) { - outsideInputResource = true; // Regarded as pull transfer. - break; - } - } - } - // Check if the output resource is outside of the channel scope. - boolean outsideOutputResource = out.isOutside(); - // Also take into account the channel hierarchy to determine push/pull transfer. - if (descendantDstChannels.contains(chNode)) { - outsideOutputResource = true; // Regarded as (broadcasting) push transfer. - } - if (ancestorDstChannels.contains(chNode)) { - outsideInputResource = true; // Regarded as (collecting) pull transfer. - } - if ((pushPull.getSelectedOption() == PushPullValue.PUSH && !outsideInputResource) || outsideOutputResource) { - // for push data transfer - MethodDeclaration update = null; - if (dstComponent == null) { - String dstParentResourceName = JerseyCodeGenerator.getComponentName(dst.getResourceHierarchy().getParent()); - dstComponent = componentMap.get(dstParentResourceName); - update = getUpdateMethod(dstComponent, dstResourceName, srcResourceName); - } else { - update = getUpdateMethod(dstComponent, null, srcResourceName); - } - if (((StoreAttribute) dst.getAttribute()).isStored()) { - // update stored state of dst side resource (when every incoming edge is in push style) - Term unifiedMassage = null; - if (directDstCh != ch) { - unifiedMassage = directDstCh.fillOutsideResourcePaths(out, JerseyCodeGenerator.pushAccessor, null).getValue(); - } - Expression updateExp = null; - if (ch.getReferenceChannelMembers().size() == 0) { - Term message = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pushAccessor, null).getValue(); - if (unifiedMassage == null) { - unifiedMassage = message; - } else { - unifiedMassage = (Term) unifiedMassage.unify(message); - } - updateExp = ch.deriveUpdateExpressionOf(out, unifiedMassage, JerseyCodeGenerator.pushAccessor); - } else { - // if there exists one or more reference channel member. - HashMap inputResourceToStateAccessor = new HashMap<>(); - for (ChannelMember c: ch.getInputChannelMembers()) { - inputResourceToStateAccessor.put(c, JerseyCodeGenerator.pushAccessor); - } - for (ChannelMember c: ch.getReferenceChannelMembers()) { - inputResourceToStateAccessor.put(c, JerseyCodeGenerator.refAccessor); - } - Term message = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pushAccessor, inputResourceToStateAccessor).getValue(); - if (unifiedMassage == null) { - unifiedMassage = message; - } else { - unifiedMassage = (Term) unifiedMassage.unify(message); - } - updateExp = ch.deriveUpdateExpressionOf(out, unifiedMassage, JerseyCodeGenerator.pushAccessor); - } - // 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 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); - int numOfOutResourcesWithTheSameHierarchy = 0; - for (ResourcePath outResPath: ch.getOutputResources()) { - if (outResPath.getResourceHierarchy().equals(outRes)) { - numOfOutResourcesWithTheSameHierarchy++; - } - } - String updateStatement = ""; - if (JerseyCodeGenerator.generatesComponent(outRes)) { - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - updateStatement = sideEffects[0]; - if (updateStatement.endsWith("\n")) { - updateStatement = updateStatement.substring(0, updateStatement.length() - 1); - } - } else { - updateStatement = sideEffects[0] + "this.value = " + newState + ";"; - } - } else { - if (sideEffects[0] != null) { - updateStatement = sideEffects[0]; - updateStatement = updateStatement.replace(".value", "." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(outRes))); - if (updateStatement.endsWith("\n")) { - updateStatement = updateStatement.substring(0, updateStatement.length() - 1); - } - } - if (DataConstraintModel.typeList.isAncestorOf(outRes.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.set); - selector.addChild(new Field("value")); - selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newList = selector.toImplementation(sideEffects2); - updateStatement += sideEffects2[0]; - } else if (DataConstraintModel.typeMap.isAncestorOf(outRes.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.insert); - selector.addChild(new Field("value")); - selector.addChild(new Variable(update.getParameters().get(update.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newMap = selector.toImplementation(sideEffects2); - updateStatement += sideEffects2[0]; - } else if (!(updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect())) { - updateStatement += "this." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(outRes)) + " = " + newState + ";"; - } - } - // add an update statement of the state of dst side resource. - if (numOfOutResourcesWithTheSameHierarchy == 1) { - update.addFirstStatement(updateStatement); - } else { - Term conditions = null; - int v = 1; - Map>> resourcePaths = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pushAccessor); - for (Expression pathParam: out.getResource().getPathParams()) { - if (pathParam instanceof Variable) { - String selfParamName = ((Variable) pathParam).getName(); - Expression arg = null; - for (Selector selector: ch.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - if (selVar.getName().equals(selfParamName)) { - arg = selVar; - break; - } - } - } - if (arg == null) { - ResourcePath filledPath = resourcePaths.get(out).getKey(); - arg = filledPath.getPathParams().get(v - 1); - } - Term condition = new Term(DataConstraintModel.eq, new Expression[] { - new Parameter("self" + (v > 1 ? v : ""), DataConstraintModel.typeString), - arg}); - if (conditions == null) { - conditions = condition; - } else { - conditions = new Term(DataConstraintModel.and, new Expression[] { - conditions, - condition}); - } - } - v++; - } - String ifStatement = "if (" + conditions.toImplementation(new String[] {""})+ ") {\n"; - update.addFirstStatement(ifStatement + "\t" + updateStatement.replace("\n", "\n\t") + "\n}"); - } - } - // Calculate in-degree (PUSH transfer) of the destination resource. - int inDegree = 0; - Set inEdges = new HashSet<>(); - inEdges.addAll(chNode.getInEdges()); - for (ChannelNode ancestor: chNode.getAncestors()) { - inEdges.addAll(ancestor.getInEdges()); - } - for (ChannelNode descendant: chNode.getDescendants()) { - inEdges.addAll(descendant.getInEdges()); - } - for (Edge resToCh2: inEdges) { - DataFlowEdge df =(DataFlowEdge) resToCh2; - if (((PushPullAttribute) df.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { - inDegree++; - } - } - if (inDegree > 1 - || (inDegree == 1 && directDstCh.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { - // update a cache of src side resource (when incoming edges are multiple) - String cacheStatement = "this." + JerseyCodeGenerator.toVariableName(srcResourceName) + " = " + JerseyCodeGenerator.toVariableName(srcResourceName) + ";"; - if (update.getBody() == null || !update.getBody().getStatements().contains(cacheStatement)) { - update.addStatement(cacheStatement); - } - } - // For a post/put REST API. - if (outsideOutputResource - || (in.getResource().getCommonPrefix(out.getResource()) == null && JerseyCodeGenerator.differentTreesAsDifferentServices)) { - // Inter-services - if (dst.getResourceHierarchy().getParent() != null) { - // If not a root resource. - TypeDeclaration rootComponent = componentMap.get(JerseyCodeGenerator.getComponentName(dst.getResourceHierarchy().getRoot())); - MethodDeclaration update2 = update; - update = getMethod(rootComponent, update2.getName()); // get the accessor to the update method. - // To make the accessor call the update method. - ResourcePath outResPath = new ResourcePath(out.getResource()); - for (int i = 0; i < outResPath.getPathParams().size(); i++) { - Parameter pathParam = new Parameter(update.getParameters().get(i).getName()); - outResPath.replacePathParam(i, pathParam, null); - } - Expression resExp = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(outResPath, outResPath.getRoot()); - String args = ""; - String delimiter = ""; - if (resExp instanceof Term) { - // To access the parent resource if the leaf resource is primitive and cannot declare the update method, or to remove getValue(). - if (((Term) resExp).getChildren().size() > 1 && ((Term) resExp).getChild(1) instanceof Variable) { - args += delimiter + ((Variable)((Term) resExp).getChild(1)).getName(); - delimiter = ", "; - } - resExp = ((Term) resExp).getChild(0); - } - int v = 0; - for (VariableDeclaration var: update2.getParameters()) { - if (v < out.getResource().getPathParams().size()) { - if (out.getResource().getPathParams().get(v) instanceof Variable) { - args += delimiter + ((Variable) out.getResource().getPathParams().get(v)).getName(); - } else if (out.getResource().getPathParams().get(v) instanceof Term) { - args += delimiter + "v" + (v + 1); - } - } else { - args += delimiter + var.getName(); - } - delimiter = ", "; - v++; - } - if (resExp != null) { - String resourceAccess = resExp.toImplementation(new String[] {""}); - update.addStatement(resourceAccess + "." + update2.getName() + "(" + args + ");"); - } else { - update.addStatement(update2.getName() + "(" + args + ");"); - } - } - // 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(); - String paramConverter = ""; - if (DataConstraintModel.typeList.isAncestorOf(paramType) && paramType != DataConstraintModel.typeList) { - Type compType = TypeInference.getListComponentType(paramType); - if (DataConstraintModel.typeTuple.isAncestorOf(compType)) { - param.setType(DataConstraintModel.typeListStr); - param.setName(paramName + "_json"); - paramConverter += paramType.getInterfaceTypeName() + " " + paramName + " = new " + paramType.getImplementationTypeName() + "();\n"; - paramConverter += "for (String str: " + param.getName() + ") {\n"; - String mapTypeName = convertFromEntryToMapType(compType); - paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(str, HashMap.class);\n"; - paramConverter += "\t" + paramName + ".add(" + getCodeForConversionFromMapToTuple(compType, "i") + ");\n"; - paramConverter += "}"; - update.addThrow("JsonProcessingException"); - } else if (DataConstraintModel.typePair.isAncestorOf(compType)) { - param.setType(DataConstraintModel.typeListStr); - param.setName(paramName + "_json"); - paramConverter += paramType.getInterfaceTypeName() + " " + paramName + " = new " + paramType.getImplementationTypeName() + "();\n"; - paramConverter += "for (String str: " + param.getName() + ") {\n"; - String mapTypeName = convertFromEntryToMapType(compType); - paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(str, HashMap.class);\n"; - 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); - param.setName(paramName + "_json"); - paramConverter += paramType.getInterfaceTypeName() + " " + paramName + ";\n"; - paramConverter += "{\n"; - String mapTypeName = convertFromEntryToMapType(paramType); - paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(" + paramName + "_json" + ", HashMap.class);\n"; - paramConverter += "\t" + paramName + " = " + getCodeForConversionFromMapToTuple(paramType, "i") + ";\n"; - paramConverter += "}"; - update.addThrow("JsonProcessingException"); - } else if (DataConstraintModel.typePair.isAncestorOf(paramType)) { - param.setType(DataConstraintModel.typeString); - param.setName(paramName + "_json"); - paramConverter += paramType.getInterfaceTypeName() + " " + paramName + ";\n"; - paramConverter += "{\n"; - String mapTypeName = convertFromEntryToMapType(paramType); - paramConverter += "\t" + mapTypeName + " i = new ObjectMapper().readValue(" + paramName + "_json" + ", HashMap.class);\n"; - 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.getBody() == null || !update.getBody().getStatements().contains(paramConverter))) { - update.addFirstStatement(paramConverter); - } - } - } - if (((StoreAttribute) dst.getAttribute()).isStored()) { - // returns the state stored in a field. - MethodDeclaration getter = null; - if (JerseyCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { - getter = getMethod(dstComponent, "getValue"); - } else { - getter = getGetterMethod(dstComponent, dstResourceName); - } - if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - if (dst.getResourceHierarchy().getNumParameters() == 0) { - if (JerseyCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { - // dst has a component. - getter.addStatement("return value;"); - } else { - // dst has no component. - String dstResName = JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(dst.getResourceHierarchy())); - getter.addStatement("return " + dstResName + ";"); - } - } else { - String[] sideEffects = new String[] {""}; - if (DataConstraintModel.typeList.isAncestorOf(dst.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.get); - selector.addChild(new Field("value")); - selector.addChild(dst.getSelectors().get(dst.getSelectors().size() - 1).getExpression()); - String curState = selector.toImplementation(sideEffects); - getter.addStatement(sideEffects[0] + "return " + curState + ";"); - } else if (DataConstraintModel.typeMap.isAncestorOf(dst.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.lookup); - selector.addChild(new Field("value")); - selector.addChild(dst.getSelectors().get(dst.getSelectors().size() - 1).getExpression()); - String curState = selector.toImplementation(sideEffects); - getter.addStatement(sideEffects[0] + "return " + curState + ";"); - } - } - } - } - // src side (for a chain of update method invocations) - String httpMethod = null; - if (out.getStateTransition().isRightUnary()) { - httpMethod = "put"; - } else { - httpMethod = "post"; - } - String srcName = null; - if (srcComponent == null) { - String srcParentResourceName = JerseyCodeGenerator.getComponentName(src.getResourceHierarchy().getParent()); - srcComponent = componentMap.get(srcParentResourceName); - srcName = srcResourceName; - } - // For caller update methods - for (MethodDeclaration srcUpdate: getUpdateMethods(srcComponent, srcName)) { - if (srcUpdate != null) { - List>> params = new ArrayList<>(); - ResourcePath dstRes = out.getResource(); - // Values of channel parameters. - for (Selector selector: ch.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - params.add(new AbstractMap.SimpleEntry<>(selVar.getType(), - new AbstractMap.SimpleEntry<>(selVar.getName(), selVar.getName()))); - } - } - // Value of the source side (input side) resource. - String srcFieldName = "this.value"; - if (!JerseyCodeGenerator.generatesComponent(src.getResourceHierarchy())) { - srcFieldName = JerseyCodeGenerator.toVariableName(srcResourceName); - } - params.add(new AbstractMap.SimpleEntry<>(src.getResourceStateType(), - new AbstractMap.SimpleEntry<>(JerseyCodeGenerator.toVariableName(srcResourceName), srcFieldName))); - // Get the value of reference member to call the update method. - Set referredSet = referredResources.get(srcUpdate); - if (ch.getReferenceChannelMembers().size() > 0) { - for (ChannelMember rc: ch.getReferenceChannelMembers()) { - // For each reference channel member, get the current state of the reference side resource by pull data transfer. - ResourcePath ref = rc.getResource(); - if (referredSet == null) { - referredSet = new HashSet<>(); - referredResources.put(srcUpdate, referredSet); - } - if (!dst.getInSideResources().contains(ref)) { - String refResourceName = JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(ref.getResourceHierarchy())); - Type refResourceType = ref.getResourceStateType(); - if (!referredSet.contains(ref)) { - referredSet.add(ref); - String[] sideEffects = new String[] {""}; - ResourcePath srcRes = in.getResource(); - if (!JerseyCodeGenerator.generatesComponent(srcRes.getResourceHierarchy())) { - srcRes = srcRes.getParent(); - } - if (rc.isOutside() || (ref.getCommonPrefix(srcRes) == null && JerseyCodeGenerator.differentTreesAsDifferentServices)) { - List pathParams = new ArrayList<>(); - for (Expression pathExp: ref.getPathParams()) { - pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); - } - generatePullDataTransfer(srcUpdate, refResourceName, ref.getResourceHierarchy().toResourcePath(pathParams), refResourceType); - } else { - Expression refGetter = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(ref, srcRes); - String refExp = refGetter.toImplementation(sideEffects); - String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); - srcUpdate.addFirstStatement(sideEffects[0] + refTypeName + " " + refResourceName + " = " + refExp + ";"); - } - } - // Value of a reference side resource. - params.add(new AbstractMap.SimpleEntry<>(refResourceType, new AbstractMap.SimpleEntry<>(refResourceName, refResourceName))); - } - } - } - if (outsideOutputResource || (in.getResource().getCommonPrefix(dstRes) == null && JerseyCodeGenerator.differentTreesAsDifferentServices)) { - // Inter-servces - String[] sideEffects = new String[] {""}; - List pathParams = new ArrayList<>(); - for (Expression pathExp: dstRes.getPathParams()) { - pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); - } - String srcResName = JerseyCodeGenerator.toVariableName(srcResourceName); - if (inDegree <= 1) { - srcResName = null; - } - Map>> filledPaths = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pushAccessor); - String dstPath = null; - if (filledPaths != null && filledPaths.get(out) != null) { - ResourcePath filledDstPath = filledPaths.get(out).getKey(); - dstPath = filledDstPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - } else { - dstPath = dstRes.getResourceHierarchy().toResourcePath(pathParams); - } - // Call the update method. - if (!chainedCalls.contains(srcUpdate)) { - // The first call to an update method in this method - srcUpdate.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, true)); - srcUpdate.addStatement("String result = " + getHttpMethodCallStatement(baseURL, dstPath, srcResName, httpMethod)); - srcUpdate.addThrow("JsonProcessingException"); - chainedCalls.add(srcUpdate); - } else { - // After the second time of call to update methods in this method - srcUpdate.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, false)); - srcUpdate.addStatement("result = " + getHttpMethodCallStatement(baseURL, dstPath, srcResName, httpMethod)); - srcUpdate.addThrow("JsonProcessingException"); - } - if (descendantDstChannels.contains(chNode)) { - // For hierarchical channels (broadcasting push transfer). - if (ch.getSelectors() != null && ch.getSelectors().size() > 0) { - Expression selExp = ch.getSelectors().get(0).getExpression(); - Type selType = null; - String varName = null; - if (selExp instanceof Variable) { - selType = ((Variable) selExp).getType(); - varName = ((Variable) selExp).getName(); - ChannelMember insideChMem = null; - for (ChannelMember cm :ch.getInputChannelMembers()) { - if (!cm.isOutside()) { - insideChMem = cm; - break; - } - } - if (insideChMem == null) { - for (ChannelMember cm :ch.getReferenceChannelMembers()) { - if (!cm.isOutside()) { - insideChMem = cm; - break; - } - } - } - if (insideChMem == null) { - for (ChannelMember cm :ch.getOutputChannelMembers()) { - if (!cm.isOutside()) { - insideChMem = cm; - break; - } - } - } - ResourcePath insideResPath = insideChMem.getResource(); - while (insideResPath.getParent() != null && (insideResPath.getLastParam() == null || !insideResPath.getLastParam().equals(selExp))) { - insideResPath = insideResPath.getParent(); - } - insideResPath = insideResPath.getParent(); - String parent = null; - if (JerseyCodeGenerator.generatesComponent(insideResPath.getResourceHierarchy())) { - Expression getter = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(insideResPath, src.getPrimaryResourcePath()); - Term valueGetter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); - valueGetter.addChild(getter); - parent = valueGetter.toImplementation(new String[] {""}); - } else { - parent = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(insideResPath, src.getPrimaryResourcePath()).toImplementation(new String[] {""}); - } - if (insideResPath != null) { - if (selType.equals(DataConstraintModel.typeInt)) { - // make a for loop (for a list) for broadcasting. - srcUpdate.addFirstStatement("for (int " + varName + " = 0; " + varName +" < " + parent + ".size(); " + varName + "++) {"); - srcUpdate.addStatement("}"); - } else if (selType.equals(DataConstraintModel.typeString)) { - // make a for loop (for a map) for broadcasting. - srcUpdate.addFirstStatement("for (String " + varName + ": " + parent + ".keySet()) {"); - srcUpdate.addStatement("}"); - } - } - } else if (selExp instanceof Term) { - // not supported. - } - } - } - srcUpdate.addThrow("JsonProcessingException"); - } else { - // Intra-service - String updateMethodName = null; - if (JerseyCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { - updateMethodName = "updateFrom" + srcResourceName; - } else { - updateMethodName = "update" + dstResourceName + "From" + srcResourceName; - } - String callParams = ""; - String delimiter = ""; - // Values of path parameters. - for (Expression pathParam: dstRes.getPathParams()) { - if (pathParam instanceof Variable) { - Variable pathVar = (Variable) pathParam; - callParams += delimiter + pathVar.getName(); - delimiter = ", "; - } - } - // Values of other parameters. - for (Map.Entry> paramEnt: params) { - callParams += delimiter + paramEnt.getValue().getValue(); - delimiter = ", "; - } - // Call the update method. - if (srcComponent != dstComponent) { - srcUpdate.addStatement("this." + JerseyCodeGenerator.toVariableName(dstResourceName) + "." + updateMethodName + "(" + callParams + ");"); - } else { - srcUpdate.addStatement("this." + updateMethodName + "(" + callParams + ");"); - } - if (update != null && update.getThrows() != null && update.getThrows().getExceptions().contains("JsonProcessingException")) { - srcUpdate.addThrow("JsonProcessingException"); - } - } - } - } - // For caller input methods - for (MethodDeclaration srcInput: getInputMethods(srcComponent, src, model)) { - List>> params = new ArrayList<>(); - ResourcePath dstRes = out.getResource(); - // Values of channel parameters. - for (Selector selector: ch.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - params.add(new AbstractMap.SimpleEntry<>(selVar.getType(), - new AbstractMap.SimpleEntry<>(selVar.getName(), selVar.getName()))); - } - } - // Value of the source side (input side) resource. - String srcFieldName = "this.value"; - if (!JerseyCodeGenerator.generatesComponent(src.getResourceHierarchy())) { - srcFieldName = JerseyCodeGenerator.toVariableName(srcResourceName); - } - params.add(new AbstractMap.SimpleEntry<>(src.getResourceStateType(), - new AbstractMap.SimpleEntry<>(JerseyCodeGenerator.toVariableName(srcResourceName), srcFieldName))); - // Get the value of reference member to call the update method. - Set referredSet = referredResources.get(srcInput); - for (ChannelMember rc: ch.getReferenceChannelMembers()) { - // For each reference channel member, get the current state of the reference side resource by pull data transfer. - ResourcePath ref = rc.getResource(); - if (referredSet == null) { - referredSet = new HashSet<>(); - referredResources.put(srcInput, referredSet); - } - if (!dst.getInSideResources().contains(ref)) { - String refResourceName = JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(ref.getResourceHierarchy())); - Type refResourceType = ref.getResourceStateType(); - if (!referredSet.contains(ref)) { - referredSet.add(ref); - String[] sideEffects = new String[] {""}; - ResourcePath srcRes = in.getResource(); - if (!JerseyCodeGenerator.generatesComponent(srcRes.getResourceHierarchy())) { - srcRes = srcRes.getParent(); - } - if (rc.isOutside() || (ref.getCommonPrefix(srcRes) == null && JerseyCodeGenerator.differentTreesAsDifferentServices)) { - List pathParams = new ArrayList<>(); - for (Expression pathExp: ref.getPathParams()) { - pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); - } - generatePullDataTransfer(srcInput, refResourceName, ref.getResourceHierarchy().toResourcePath(pathParams), refResourceType); - } else { - Expression refGetter = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(ref, srcRes); - String refExp = refGetter.toImplementation(sideEffects); - String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); - srcInput.addFirstStatement(sideEffects[0] + refTypeName + " " + refResourceName + " = " + refExp + ";"); - } - } - // Value of a reference side resource. - params.add(new AbstractMap.SimpleEntry<>(refResourceType, new AbstractMap.SimpleEntry<>(refResourceName, refResourceName))); - } - } - if (outsideOutputResource || (in.getResource().getCommonPrefix(dstRes) == null && JerseyCodeGenerator.differentTreesAsDifferentServices)) { - // Inter-services - String[] sideEffects = new String[] {""}; - List pathParams = new ArrayList<>(); - for (Expression pathExp: dstRes.getPathParams()) { - pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); - } - String srcResName = JerseyCodeGenerator.toVariableName(srcResourceName); - if (inDegree <= 1) { - srcResName = null; - } - Map>> filledPaths = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pushAccessor); - String dstPath = null; - if (filledPaths != null && filledPaths.get(out) != null) { - ResourcePath filledDstPath = filledPaths.get(out).getKey(); - dstPath = filledDstPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - } else { - dstPath = dstRes.getResourceHierarchy().toResourcePath(pathParams); - } - // Call the update method. - if (!chainedCalls.contains(srcInput)) { - // First call to an update method in this method - srcInput.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, true)); - srcInput.addStatement("String result = " + getHttpMethodCallStatement(baseURL, dstPath, srcResName, httpMethod)); - srcInput.addThrow("JsonProcessingException"); - chainedCalls.add(srcInput); - } else { - // After the second time of call to update methods in this method - srcInput.addStatement(getHttpMethodParamsStatement(srcComponent.getTypeName(), params, false)); - srcInput.addStatement("result = " + getHttpMethodCallStatement(baseURL, dstPath, srcResName, httpMethod)); - srcInput.addThrow("JsonProcessingException"); - } - if (descendantDstChannels.contains(chNode)) { - // For hierarchical channels (broadcasting push transfer). - if (ch.getSelectors() != null && ch.getSelectors().size() > 0) { - Expression selExp = ch.getSelectors().get(0).getExpression(); - Type selType = null; - String forVarName = null; - if (selExp instanceof Variable) { - selType = ((Variable) selExp).getType(); - forVarName = ((Variable) selExp).getName(); - ChannelMember insideChMem = null; - for (ChannelMember cm :ch.getInputChannelMembers()) { - if (!cm.isOutside()) { - insideChMem = cm; - break; - } - } - if (insideChMem == null) { - for (ChannelMember cm :ch.getReferenceChannelMembers()) { - if (!cm.isOutside()) { - insideChMem = cm; - break; - } - } - } - if (insideChMem == null) { - for (ChannelMember cm :ch.getOutputChannelMembers()) { - if (!cm.isOutside()) { - insideChMem = cm; - break; - } - } - } - ResourcePath insideResPath = insideChMem.getResource(); - while (insideResPath.getParent() != null && (insideResPath.getLastParam() == null || !insideResPath.getLastParam().equals(selExp))) { - insideResPath = insideResPath.getParent(); - } - insideResPath = insideResPath.getParent(); - String parent = null; - if (JerseyCodeGenerator.generatesComponent(insideResPath.getResourceHierarchy())) { - Expression getter = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(insideResPath, src.getPrimaryResourcePath()); - Term valueGetter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); - valueGetter.addChild(getter); - parent = valueGetter.toImplementation(new String[] {""}); - } else { - parent = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(insideResPath, src.getPrimaryResourcePath()).toImplementation(new String[] {""}); - } - if (insideResPath != null) { - if (selType.equals(DataConstraintModel.typeInt)) { - // make a for loop (for a list) for broadcasting. - srcInput.addFirstStatement("for (int " + forVarName + " = 0; " + forVarName +" < " + parent + ".size(); " + forVarName + "++) {"); - srcInput.addStatement("}"); - } else if (selType.equals(DataConstraintModel.typeString)) { - // make a for loop (for a map) for broadcasting. - srcInput.addFirstStatement("for (String " + forVarName + ": " + parent + ".keySet()) {"); - srcInput.addStatement("}"); - } - } - } else if (selExp instanceof Term) { - // not supported. - } - } - } - srcInput.addThrow("JsonProcessingException"); - } else { - // Intra-service - String updateMethodName = null; - if (JerseyCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { - updateMethodName = "updateFrom" + srcResourceName; - } else { - updateMethodName = "update" + dstResourceName + "From" + srcResourceName; - } - String callParams = ""; - String delimiter = ""; - // Values of path parameters. - for (Expression pathParam: dstRes.getPathParams()) { - if (pathParam instanceof Variable) { - Variable pathVar = (Variable) pathParam; - callParams += delimiter + pathVar.getName(); - delimiter = ", "; - } - } - // Values of other parameters. - for (Map.Entry> paramEnt: params) { - callParams += delimiter + paramEnt.getValue().getValue(); - delimiter = ", "; - } - // Call the update method. - if (srcComponent != dstComponent) { - srcInput.addStatement("this." + JerseyCodeGenerator.toVariableName(dstResourceName) + "." + updateMethodName + "(" + callParams + ");"); - } else { - srcInput.addStatement("this." + updateMethodName + "(" + callParams + ");"); - } - if (update != null && update.getThrows() != null && update.getThrows().getExceptions().contains("JsonProcessingException")) { - srcInput.addThrow("JsonProcessingException"); - } - } - } - } else if ((pushPull.getSelectedOption() != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { - // for pull (or push/pull) data transfer - if (dstComponent == null) { - String dstParentResourceName = JerseyCodeGenerator.getComponentName(dst.getResourceHierarchy().getParent()); - dstComponent = componentMap.get(dstParentResourceName); - } - MethodDeclaration getter = null; - if (JerseyCodeGenerator.generatesComponent(dst.getResourceHierarchy())) { - getter = getMethod(dstComponent, "getValue"); - } else { - getter = getGetterMethod(dstComponent, dstResourceName); - } - if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { - // The first time to fill the getter method's body. - - // Data transfer on the same channel hierarchy. - String[] sideEffects = new String[] {""}; - // For each reference channel member, get the current state of the reference side resource by pull data transfer. - for (ChannelMember rc: ch.getReferenceChannelMembers()) { - ResourcePath refRes = rc.getResource(); - String refResourceName = JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(refRes.getResourceHierarchy())); - Type refResourceType = refRes.getResourceStateType(); - ResourcePath dstRes = out.getResource(); - if (!JerseyCodeGenerator.generatesComponent(dstRes.getResourceHierarchy())) { - dstRes = dstRes.getParent(); - } - if (rc.isOutside() || (refRes.getCommonPrefix(dstRes) == null && JerseyCodeGenerator.differentTreesAsDifferentServices)) { - List pathParams = new ArrayList<>(); - for (Expression pathExp: refRes.getPathParams()) { - sideEffects = new String[] {""}; - pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); - } - generatePullDataTransfer(getter, refResourceName, refRes.getResourceHierarchy().toResourcePath(pathParams), refResourceType); - } else { - Expression refGetter = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(refRes, dstRes); - sideEffects = new String[] {""}; - String refExp = refGetter.toImplementation(sideEffects); - String refTypeName = refResourceType.getInterfaceTypeName(); - getter.addFirstStatement(sideEffects[0] + refTypeName + " " + refResourceName + " = " + refExp + ";"); - } - } - - // Construct the base message. - Map.Entry>>, Term> resourcePathsAndMessage = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pullAccessor, null); - Map>> resourcePaths = resourcePathsAndMessage.getKey(); - Term messageTerm = resourcePathsAndMessage.getValue(); - - // Data transfer from path depending resource. - for (Entry>> pathEnt: resourcePaths.entrySet()) { - ChannelMember cm = pathEnt.getKey(); - ResourcePath src2 = pathEnt.getValue().getKey(); - // get outside src2 resource state by pull data transfer. - if (cm.isOutside() || src2.getCommonPrefix(dst.getInSideResource(ch)) == null) { - // Data transfer from an outside input resource is regarded as PULL transfer. - List pathParams = new ArrayList<>(); - for (Expression pathExp: src2.getPathParams()) { - sideEffects = new String[] {""}; - pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); - } - // generate a pull data transfer from a depending in/ref resource. - Type srcResourceType = src2.getResourceStateType(); - String srcResName2 = JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(src2.getResourceHierarchy())); - String srcPath2 = src2.toResourcePath().replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - generatePullDataTransfer(getter, srcResName2, srcPath2, srcResourceType); - } - } - - // Data transfer from the descendant channel hierarchies. - Stack> channelItrStack = new Stack<>(); - DataTransferChannel curChannel = ch; - if (curChannel.getChildren() != null && curChannel.getChildren().size() > 0) { - // retrieve descendant channels recursively. - // (For each descendant channel, data transfer from every input resource is regarded as PULL transfer.) - Iterator chItr = curChannel.getChildren().iterator(); - do { - if (!chItr.hasNext()) { - chItr = channelItrStack.pop(); - } else { - curChannel = (DataTransferChannel) chItr.next(); - // generate pull data transfers. - Set chMems = new HashSet<>(curChannel.getInputChannelMembers()); - chMems.addAll(curChannel.getReferenceChannelMembers()); - for (ChannelMember cm2: chMems) { - if (resourcePaths == null || !resourcePaths.keySet().contains(cm2)) { - // not a depending channel member. - ResourcePath src2 = cm2.getResource(); - Type srcResType2 = src2.getResourceStateType(); - String srcResName2 = JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(src2.getResourceHierarchy())); - String srcPath2 = src2.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - generatePullDataTransfer(getter, srcResName2, srcPath2, srcResType2); - } else { - // a depending channel member. - ResourcePath src2 = resourcePaths.get(cm2).getKey(); - // get outside src2 resource state by pull data transfer. - if (cm2.isOutside() || src2.getCommonPrefix(dst.getInSideResource(curChannel)) == null) { - // generate a pull data transfer from a depending in/ref resource. - Type srcResType2 = src2.getResourceStateType(); - String srcResName2 = JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(src2.getResourceHierarchy())); - String srcPath2 = src2.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - generatePullDataTransfer(getter, srcResName2, srcPath2, srcResType2); - } - } - } - // collect the message constraints by a descendant channel. - List varsForSideEffects = new ArrayList<>(); - int v = 0; - resourcePathsAndMessage = curChannel.fillOutsideResourcePaths(out, JerseyCodeGenerator.pullAccessor, null); - if (resourcePathsAndMessage != null) { - resourcePaths = resourcePathsAndMessage.getKey(); - Term messageTermSub = resourcePathsAndMessage.getValue(); - for (Map.Entry subTermEnt: messageTermSub.getSubTerms(Term.class).entrySet()) { - Term subTerm = subTermEnt.getValue(); - if (!(subTerm instanceof Constant) && subTerm.getSymbol().isImplWithSideEffect()) { - Variable var = new Variable("v" + v, subTerm.getType()); - varsForSideEffects.add(var); - v++; - // Add a side effect statement within the loop - Position pos = new Position(); - pos.addHeadOrder(0); - subTerm.replaceSubTerm(pos, var); - sideEffects = new String[] {""}; - String curState = messageTermSub.toImplementation(sideEffects); - getter.addStatement(sideEffects[0].replaceAll("\n", "")); - // Cancel the side effects in the return value. - pos = subTermEnt.getKey(); - messageTermSub.replaceSubTerm(pos, var); - } - } - if (messageTerm == null) { - messageTerm = messageTermSub; - } else { - messageTerm = (Term) messageTerm.unify(messageTermSub); - } - if (messageTerm == null) { - throw new UnificationFailed(); - } - } - // enclosed by a for loop - Expression selExp = curChannel.getSelectors().get(0).getExpression(); - Type selType = null; - String varName = null; - if (selExp instanceof Variable) { - selType = ((Variable) selExp).getType(); - varName = ((Variable) selExp).getName(); - ChannelMember insideChMem = null; - for (ChannelMember cm2 :curChannel.getInputChannelMembers()) { - if (!cm2.isOutside()) { - insideChMem = cm2; - break; - } - } - if (insideChMem == null) { - for (ChannelMember cm2 :curChannel.getReferenceChannelMembers()) { - if (!cm2.isOutside()) { - insideChMem = cm2; - break; - } - } - } - ResourcePath insideResPath = insideChMem.getResource(); - while (insideResPath.getParent() != null && (insideResPath.getLastParam() == null || !insideResPath.getLastParam().equals(selExp))) { - insideResPath = insideResPath.getParent(); - } - insideResPath = insideResPath.getParent(); - String parent = null; - if (insideResPath != null) { - if (insideResPath.getCommonPrefix(dst.getInSideResource(ch)) != null) { - if (JerseyCodeGenerator.generatesComponent(insideResPath.getResourceHierarchy())) { - Expression parentGetter = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(insideResPath, dst.getInSideResource(ch)); - Term valueGetter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); - valueGetter.addChild(parentGetter); - parent = valueGetter.toImplementation(new String[] {""}); - } else { - parent = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(insideResPath, dst.getInSideResource(ch)).toImplementation(new String[] {""}); - } - } else { - parent = JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(insideResPath.getResourceHierarchy())); - } - if (selType.equals(DataConstraintModel.typeInt)) { - // make a for loop (for a list) for data collecting. - getter.addFirstStatement("for (int " + varName + " = 0; " + varName +" < " + parent + ".size(); " + varName + "++) {"); - } else if (selType.equals(DataConstraintModel.typeString)) { - // make a for loop (for a map) for data collecting. - getter.addFirstStatement("for (String " + varName + ": " + parent + ".keySet()) {"); - } - if (insideResPath.getCommonPrefix(dst.getInSideResource(ch)) == null) { - Type parentResType = insideResPath.getResourceStateType(); - String parentResName = JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(insideResPath.getResourceHierarchy())); - String parentResPath = insideResPath.toString().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - generatePullDataTransfer(getter, parentResName, parentResPath, parentResType); - } - } - } - // initialize the variables to hold side effects within the loop - for (Variable var: varsForSideEffects) { - getter.addFirstStatement(var.getType().getInterfaceTypeName() + " " + var.getName() + " = new " + var.getType().getImplementationTypeName() + "();"); - } - // end of the loop - getter.addStatement("}"); - if (curChannel.getChildren() != null && curChannel.getChildren().size() > 0) { - channelItrStack.push(chItr); - chItr = curChannel.getChildren().iterator(); - } - } - } while (!channelItrStack.isEmpty()); - } - // generate a return statement. - Expression curExp = ch.deriveUpdateExpressionOf(out, messageTerm, JerseyCodeGenerator.pullAccessor); - sideEffects = new String[] {""}; - String curState = curExp.toImplementation(sideEffects); - if (ch.getChildren() == null || ch.getChildren().size() == 0) { - getter.addStatement(sideEffects[0] + "return " + curState + ";"); - } else { - getter.addStatement("return " + curState + ";"); - } - } - // get src resource state by pull data transfer. - if (src.getNumberOfParameters() == 0 && src.getOutSideResource(ch).getCommonPrefix(dst.getInSideResource(ch)) == null) { - Type srcResourceType = src.getResourceStateType(); - List pathParams = new ArrayList<>(); - generatePullDataTransfer(getter, src.getResourceName(), src.getResourceHierarchy().toResourcePath(pathParams), srcResourceType); - } - } - } - } - } - } - } - - // for source nodes - for (ResourceHierarchy resource: model.getResourceHierarchies()) { - String resourceName = JerseyCodeGenerator.getComponentName(resource); - TypeDeclaration component = componentMap.get(resourceName); - if (JavaCodeGenerator.generatesComponent(resource)) { - if (component != null) { - // state getter method - Type resourceType = JerseyCodeGenerator.getImplStateType(resource); - MethodDeclaration stateGetter = getMethod(component, "getValue"); - if (stateGetter.getBody() == null || stateGetter.getBody().getStatements().size() == 0) { - if (model.isPrimitiveType(resourceType)) { - // primitive type - stateGetter.addStatement("return value;"); - } else { - if (resource.getChildren() != null && resource.getChildren().size() == 1 && resource.getChildren().iterator().next().getNumParameters() > 0) { - // list or map - String implTypeName = resourceType.getImplementationTypeName(); - // copy the current state to be returned as a 'value' - stateGetter.addStatement("return new " + implTypeName + "(value);"); - } else { - if (resource.getChildren() == null || resource.getChildren().size() == 0) { - // a leaf resource - String implTypeName = resourceType.getImplementationTypeName(); - stateGetter.addStatement("return new " + implTypeName + "(value);"); - } else { - Term composer = null; - Term composerSub = new Constant(DataConstraintModel.nil); - composerSub.setType(DataConstraintModel.typeMap); - for (ResourceHierarchy child: resource.getChildren()) { - String childTypeName = JerseyCodeGenerator.getComponentName(child); - String fieldName = JerseyCodeGenerator.toVariableName(childTypeName); - Term childGetter = null; - if (!JerseyCodeGenerator.generatesComponent(child)) { - // the child is not a class - childGetter = new Term(new Symbol("get" + childTypeName, 1, Symbol.Type.METHOD)); - childGetter.addChild(new Constant("this")); - } else { - // the child is a class - childGetter = new Term(new Symbol("getValue", 1, Symbol.Type.METHOD)); - childGetter.addChild(new Field(fieldName, JerseyCodeGenerator.getImplStateType(child))); - } - composer = new Term(DataConstraintModel.insert); - composer.addChild(composerSub); - composer.addChild(new Constant(fieldName, DataConstraintModel.typeString)); // key - composer.addChild(childGetter); // value - composer.setType(DataConstraintModel.typeMap); - composerSub = composer; - } - composer.setType(stateGetter.getReturnType()); - String[] sideEffects = new String[] {null}; - String returnValue = composer.toImplementation(sideEffects); - if (sideEffects[0] != null) { - stateGetter.addStatement(sideEffects[0] + "return " + returnValue+ ";"); - } else { - stateGetter.addStatement("return " + returnValue+ ";"); - } - } - } - } - } - - // (#4) descendant getter method (the implementation must be kept consistent with #3) - if (resource.getChildren().size() > 0) { - for (ResourceHierarchy child: resource.getChildren()) { - 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; - break; - } - } - 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; - } 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; - } - 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; - if (DataConstraintModel.typeList.isAncestorOf(parent.getResourceStateType())) { - params++; - } else if (DataConstraintModel.typeMap.isAncestorOf(parent.getResourceStateType())) { - params++; - } - children = descendant.getChildren(); - } while (children != null && children.size() == 1 && (descendant = children.iterator().next()) != null); - } - } - } - } - - // methods for input events - Map> ioChannelsAndMembers = getIOChannelsAndMembers(resource, model); - for (Map.Entry> entry: ioChannelsAndMembers.entrySet()) { - DataTransferChannel ch = entry.getKey(); - Set outs = entry.getValue(); - for (ChannelMember out: outs) { - MethodDeclaration input = null; - if (JerseyCodeGenerator.generatesComponent(resource)) { - // A component is generated for this resource. - input = getInputMethod(component, out, ch.getOutputChannelMembers().size()); - } else { - // No component is generated for this resource. - ResourceHierarchy parent = resource.getParent(); - if (parent != null) { - TypeDeclaration parentType = componentMap.get(JerseyCodeGenerator.getComponentName(parent)); - input = getInputMethod(parentType, out, ch.getOutputChannelMembers().size()); - } - } - if (input != null) { - // In each resource - Set referredSet = referredResources.get(input); - for (ChannelMember rc: ch.getReferenceChannelMembers()) { - // For each reference channel member, get the current state of the reference side resource by pull data transfer. - ResourcePath ref = rc.getResource(); - if (referredSet == null) { - referredSet = new HashSet<>(); - referredResources.put(input, referredSet); - } - if (!out.getResource().equals(ref)) { - String refResourceName = ref.getLeafResourceName(); - Type refResourceType = ref.getResourceStateType(); - if (!referredSet.contains(ref)) { - referredSet.add(ref); - String[] sideEffects = new String[] {""}; - ResourcePath dstRes = out.getResource(); - if (!JerseyCodeGenerator.generatesComponent(dstRes.getResourceHierarchy())) { - dstRes = dstRes.getParent(); - } - if (rc.isOutside() || (ref.getCommonPrefix(dstRes) == null && JerseyCodeGenerator.differentTreesAsDifferentServices)) { - List pathParams = new ArrayList<>(); - for (Expression pathExp: ref.getPathParams()) { - pathParams.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); - } - generatePullDataTransfer(input, refResourceName, ref.getResourceHierarchy().toResourcePath(pathParams), refResourceType); - } else { - Expression refGetter = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(ref, dstRes); - String refExp = refGetter.toImplementation(sideEffects); - String refTypeName = refResourceType.getInterfaceTypeName(); - input.addFirstStatement(sideEffects[0] + refTypeName + " " + refResourceName + " = " + refExp + ";"); - } - } - } - } - Expression updateExp = ch.deriveUpdateExpressionOf(out, JerseyCodeGenerator.refAccessor).getKey(); - // 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 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); - if (JerseyCodeGenerator.generatesComponent(resource)) { - String updateStatement; - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - updateStatement = sideEffects[0]; - if (updateStatement.endsWith("\n")) { - updateStatement = updateStatement.substring(0, updateStatement.length() - 1); - } - } else { - updateStatement = sideEffects[0] + "this.value = " + newState + ";"; - } - if (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement)) { - input.addStatement(updateStatement); - } - } else { - String updateStatement = ""; - if (sideEffects[0] != null) { - updateStatement = sideEffects[0]; - updateStatement = updateStatement.replace(".value", "." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(resource))); - if (updateStatement.endsWith("\n")) { - updateStatement = updateStatement.substring(0, updateStatement.length() - 1); - } - } - if (DataConstraintModel.typeList.isAncestorOf(resource.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.set); - selector.addChild(new Field("value")); - selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newList = selector.toImplementation(sideEffects2); - updateStatement += sideEffects2[0]; - } else if (DataConstraintModel.typeMap.isAncestorOf(resource.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.insert); - selector.addChild(new Field("value")); - selector.addChild(new Variable(input.getParameters().get(input.getParameters().size() - 2).getName())); - selector.addChild(new Constant(newState)); - String[] sideEffects2 = new String[] {""}; - String newMap = selector.toImplementation(sideEffects2); - updateStatement += sideEffects2[0]; - } else if (!(updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect())) { - updateStatement += "this." + JerseyCodeGenerator.toVariableName(JerseyCodeGenerator.getComponentName(resource)) + " = " + newState + ";"; - } - if (updateStatement != null && (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement))) { - input.addStatement(updateStatement); - } - } - - if (out.getResource().getParent() != null && out.getResource().getParent().getParent() != null) { - // In the root resource - Expression message = out.getStateTransition().getMessageExpression(); - String inputAccessorName = input.getName(); - if (message instanceof Term) { - inputAccessorName = ((Term) message).getSymbol().getImplName(); - } else if (message instanceof Variable) { - inputAccessorName = ((Variable) message).getName(); - } - MethodDeclaration inputAccessor = getMethod(componentMap.get(JerseyCodeGenerator.getComponentName(resource.getRoot())), inputAccessorName); - if (inputAccessor != null) { - ResourcePath outResPath = new ResourcePath(out.getResource()); - for (int i = 0; i < outResPath.getPathParams().size(); i++) { - Parameter pathParam = new Parameter(inputAccessor.getParameters().get(i).getName()); - outResPath.replacePathParam(i, pathParam, null); - } - // The expression of the receiver (resource) of the input method. - Expression resExp = JerseyCodeGenerator.pullAccessor.getDirectStateAccessorFor(outResPath, outResPath.getRoot()); - String args = ""; - String delimiter = ""; - if (resExp instanceof Term) { - // To access the parent resource if the leaf resource is primitive and cannot declare the input method, or to remove getValue(). - if (((Term) resExp).getChildren().size() > 1 && ((Term) resExp).getChild(1) instanceof Variable) { - args += delimiter + ((Variable)((Term) resExp).getChild(1)).getName(); - delimiter = ", "; - } - resExp = ((Term) resExp).getChild(0); - } - // Values of channel parameters. - for (Selector selector: ch.getAllSelectors()) { - if (selector.getExpression() instanceof Variable) { - Variable selVar = (Variable) selector.getExpression(); - args += delimiter + selVar.getName(); - delimiter = ", "; - } - } - // Values of message parameters. - if (message instanceof Term) { - for (Variable mesVar: message.getVariables().values()) { - args += delimiter + mesVar.getName(); - delimiter = ", "; - } - } - if (resExp != null) { - String resourceAccess = resExp.toImplementation(new String[] {""}); - inputAccessor.addStatement(resourceAccess + "." + input.getName() + "(" + args + ");"); - } else { - inputAccessor.addStatement(input.getName() + "(" + args + ");"); - } - if (input != null && input.getThrows() != null && input.getThrows().getExceptions().contains("JsonProcessingException")) { - inputAccessor.addThrow("JsonProcessingException"); - } - } - } - } - } - } - } - } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork - | InvalidMessage | UnificationFailed | ValueUndefined e1) { - e1.printStackTrace(); - } - return codes; - } - - private static void replaceJsonTermWithConstructorInvocation(Expression exp, Type replacedJsonType, String replacingClassName, TypeDeclaration descendantComponent) { - // Replace each json term in exp with the corresponding constructor invocation. - Type descendantType = new Type(replacingClassName, replacingClassName); - Map subTerms = ((Term) exp).getSubTerms(Term.class); - Iterator> termEntItr = subTerms.entrySet().iterator(); - while (termEntItr.hasNext()) { - Entry termEnt = termEntItr.next(); - Term jsonTerm = termEnt.getValue(); - if (jsonTerm.getType() != null) { - if (jsonTerm.getType().equals(replacedJsonType)) { - if (jsonTerm instanceof JsonTerm || jsonTerm.getSymbol().equals(DataConstraintModel.addMember)) { - String constructorInvocation = "new " + replacingClassName + "("; - MethodDeclaration descendantConstructor = getConstructor(descendantComponent); - if (descendantConstructor != null) { - String delimiter = ""; - for (VariableDeclaration var: descendantConstructor.getParameters()) { - // Extract the argument of each constructor parameter from jsonTerm. - JsonAccessor jsonMember = new JsonAccessor(DataConstraintModel.dot); - jsonMember.addChild(jsonTerm); - jsonMember.addChild(new Constant(var.getName(), DataConstraintModel.typeString)); - Expression param = jsonMember.reduce(); // Reduce {"name": "foo", age: 25}.name => "foo" - 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()); - } - } - constructorInvocation = constructorInvocation + delimiter + param.toImplementation(null); - } else { - constructorInvocation = constructorInvocation + delimiter + var.getName(); - } - delimiter = ", "; - } - } - constructorInvocation += ")"; - ((Term) exp).replaceSubTerm(termEnt.getKey(), new Constant(constructorInvocation)); - subTerms = ((Term) exp).getSubTerms(Term.class); - termEntItr = subTerms.entrySet().iterator(); - } else { - jsonTerm.setType(descendantType); - } - } else { - Type oldType = jsonTerm.getType(); - Type newType = new Type(oldType.getTypeName(), - oldType.getImplementationTypeName().replace(replacedJsonType.getInterfaceTypeName(), replacingClassName), - oldType.getInterfaceTypeName().replace(replacedJsonType.getInterfaceTypeName(), replacingClassName)); - for (Type parent: oldType.getParentTypes()) { - newType.addParentType(parent); - } - jsonTerm.setType(newType); - } - } - } - } - - private static void generatePullDataTransfer(MethodDeclaration methodBody, String fromResourceName, String fromResourcePath, Type fromResourceType) { - String varName = new String(fromResourceName); - String respTypeName = fromResourceType.getInterfaceTypeName(); - String respImplTypeName = fromResourceType.getImplementationTypeName(); - String respConverter = ""; - if (DataConstraintModel.typeList.isAncestorOf(fromResourceType) && fromResourceType != DataConstraintModel.typeList) { - Type compType = TypeInference.getListComponentType(fromResourceType); - if (DataConstraintModel.typeTuple.isAncestorOf(compType)) { - varName += "_json"; - String mapTypeName = convertFromEntryToMapType(compType); - respTypeName = "List<" + mapTypeName + ">"; - respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + " = new " + fromResourceType.getImplementationTypeName() + "();\n"; - respConverter += "for (" + mapTypeName + " i: " + varName + ") {\n"; - 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"; - respTypeName = convertFromEntryToMapType(fromResourceType); - respConverter += fromResourceType.getInterfaceTypeName() + " " + fromResourceName + " = " + getCodeForConversionFromMapToTuple(fromResourceType, varName) + ";"; - respImplTypeName = "HashMap"; - } else if (DataConstraintModel.typePair.isAncestorOf(fromResourceType)) { - varName += "_json"; - 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); - } - methodBody.addFirstStatement(respTypeName + " " + varName + " = " + getHttpMethodCallStatementWithResponse(baseURL, fromResourcePath, "get", respImplTypeName)); - } - - private static String convertFromEntryToMapType(Type type) { - String mapTypeName = null; - if (DataConstraintModel.typePair.isAncestorOf(type)) { - Type compType = TypeInference.getPairComponentType(type); - String wrapperType = DataConstraintModel.getWrapperType(compType); - if (wrapperType != null) { - mapTypeName = "Map"; - } 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"); - for (int idx = mapTypeName.indexOf("<", 0); idx >= 0; idx = mapTypeName.indexOf("<", idx + 1)) { - int to = mapTypeName.indexOf(",", idx); - if (to > idx) { - mapTypeName = mapTypeName.substring(0, idx + 1) + "String" + mapTypeName.substring(to); // All elements except for the last one have the string type. - } - } - } - return mapTypeName; - } - - private static String getCodeForConversionFromMapToTuple(Type tupleType, String mapVar) { - String decoded = "$x"; - List elementsTypes = TypeInference.getTupleComponentTypes(tupleType); - String elementBase = mapVar; - for (Type elmType: elementsTypes.subList(0, elementsTypes.size() - 1)) { - elementBase += ".entrySet().iterator().next()"; - if (elmType == DataConstraintModel.typeBoolean - || elmType == DataConstraintModel.typeInt - || elmType == DataConstraintModel.typeLong - || elmType == DataConstraintModel.typeFloat - || elmType == DataConstraintModel.typeDouble) { - String elmVal = new JavaSpecific().getStringToValueExp(elmType.getImplementationTypeName(), elementBase + ".getKey()"); - decoded = decoded.replace("$x", "new AbstractMap.SimpleEntry<>(" + elmVal + ", $x)"); - } else if (elmType == DataConstraintModel.typeString) { - decoded = decoded.replace("$x", "new AbstractMap.SimpleEntry<>(" + elementBase + ".getKey(), $x)"); - } else { - // To do. - } - elementBase += ".getValue()"; - } - decoded = decoded.replace("$x", elementBase); - return decoded; - } - - private static String getCodeForConversionFromMapToPair(Type pairType, String mapVar) { - String decoded = "$x"; - decoded = decoded.replace("$x", "new Pair<>(" + mapVar + ".get(\"left\"), $x)"); - decoded = decoded.replace("$x", mapVar + ".get(\"right\")"); - return decoded; - } - - 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 = new JavaSpecific().getStringToValueExp(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 + "\", " + new JavaSpecific().getValueToStringExp(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) { - 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 getHttpMethodCallStatementWithResponse(String baseURL, String resourceName, String httpMethod, String respImplName) { - String responseShortTypeName = respImplName; - if (respImplName.contains("<")) { - responseShortTypeName = respImplName.substring(0, respImplName.indexOf("<")); - } - return "client.target(\"" + baseURL + "\").path(\"/" + resourceName + "\").request()." + httpMethod + "(" + responseShortTypeName + ".class);"; - } - - private static MethodDeclaration getConstructor(TypeDeclaration component) { - for (MethodDeclaration m: component.getMethods()) { - if (m.isConstructor()) return m; - } - return null; - } - - private static MethodDeclaration getUpdateMethod(TypeDeclaration component, String dstResName, String srcResName) { - for (MethodDeclaration m: component.getMethods()) { - if (dstResName == null) { - if (m.getName().equals("updateFrom" + srcResName)) return m; - } else { - if (m.getName().equals("update" + dstResName + "From" + srcResName)) return m; - } - } - return null; - } - - private static List getUpdateMethods(TypeDeclaration component, String resName) { - List updates = new ArrayList<>(); - for (MethodDeclaration m: component.getMethods()) { - if (resName == null) { - if (m.getName().startsWith("updateFrom")) { - updates.add(m); - } - } else { - if (m.getName().startsWith("update" + resName + "From")) { - updates.add(m); - } - } - } - 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().equals("get" + resourceName)) { - getters.add(m); - } - } - return getters; - } - - private static Map> getIOChannelsAndMembers(ResourceHierarchy resource, DataTransferModel model) { - Map> ioChannelsAndMembers = new HashMap<>(); - for (Channel c: model.getInputChannels()) { - DataTransferChannel ch = (DataTransferChannel) c; - // I/O channel - for (ChannelMember out: ch.getOutputChannelMembers()) { - if (resource.equals(out.getResource().getResourceHierarchy())) { - if (out.getStateTransition().getMessageExpression() instanceof Term || out.getStateTransition().getMessageExpression() instanceof Variable) { - Set channelMembers = ioChannelsAndMembers.get(ch); - if (channelMembers == null) { - channelMembers = new HashSet<>(); - ioChannelsAndMembers.put(ch, channelMembers); - } - channelMembers.add(out); - } - } - } - } - return ioChannelsAndMembers; - } - - private static List getInputMethods(TypeDeclaration component, ResourceNode resource, DataTransferModel model) { - List inputs = new ArrayList<>(); - for (Channel c: model.getInputChannels()) { - DataTransferChannel channel = (DataTransferChannel) c; - // I/O channel - for (ChannelMember out: channel.getOutputChannelMembers()) { - if (resource.getInSideResources().contains(out.getResource())) { - MethodDeclaration input = getInputMethod(component, out, channel.getOutputChannelMembers().size()); - inputs.add(input); - } - } - } - return inputs; - } - - private static MethodDeclaration getInputMethod(TypeDeclaration component, ChannelMember cm, int outNumber) { - String inputMethodName = null; - if (cm.getStateTransition().getMessageExpression() instanceof Term) { - Term message = (Term) cm.getStateTransition().getMessageExpression(); - inputMethodName = message.getSymbol().getImplName(); - } else if (cm.getStateTransition().getMessageExpression() instanceof Variable) { - Variable message = (Variable) cm.getStateTransition().getMessageExpression(); - inputMethodName = message.getName(); - } - if (outNumber > 1) { - inputMethodName += "For" + JerseyCodeGenerator.getComponentName(cm.getResource().getResourceHierarchy()); - } - MethodDeclaration input = getMethod(component, inputMethodName); - return input; - } - - private static MethodDeclaration getMethod(TypeDeclaration component, String methodName) { - for (MethodDeclaration m: component.getMethods()) { - if (m.getName().equals(methodName)) return m; - } - return null; - } -} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java index a9f4c3c..dd5e93b 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseySpecific.java @@ -3,9 +3,10 @@ import java.util.List; import java.util.Map; -import algorithms.TypeInference; import code.ast.Annotation; +import code.ast.Block; import code.ast.CompilationUnit; +import code.ast.EnhancedForStatement; import code.ast.FieldDeclaration; import code.ast.ImportDeclaration; import code.ast.MethodDeclaration; @@ -13,9 +14,10 @@ import code.ast.VariableDeclaration; import models.algebra.Type; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ListType; public class JerseySpecific extends RestApiSpecific { - public static final Type typeClient = new Type("Client", "Client"); + public static final Type typeClient = new Type("Client", new code.ast.SimpleType("Client")); public JerseySpecific() { langSpec = new JavaSpecific(); @@ -109,20 +111,25 @@ 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 += langSpec.getForStatementForCollection("i", compType.getInterfaceTypeName(), value) + "\n"; - } else { - statements += langSpec.getForStatementForCollection("i", wrapperType, value) + "\n"; + if (paramType instanceof ListType) { + Type compType = ((ListType) paramType).getElementType(); + Type wrapperType = langSpec.getWrapperType(compType); + EnhancedForStatement forStatement = null; + if (!langSpec.isValueType(compType)) { + forStatement = langSpec.getForStatementForCollection(langSpec.newVariableDeclaration(compType, "i"), value); + } else { + forStatement = langSpec.getForStatementForCollection(langSpec.newVariableDeclaration(wrapperType, "i"), value); + } + Block forBlock = new Block(); + if (DataConstraintModel.typeTuple.isAncestorOf(compType) || DataConstraintModel.typePair.isAncestorOf(paramType) || DataConstraintModel.typeList.isAncestorOf(compType) || DataConstraintModel.typeMap.isAncestorOf(paramType)) { + forBlock.addStatement("form.param(\"" + paramName + "\", " + langSpec.getConstructorInvocation("ObjectMapper", null) + ".writeValueAsString(i))" + langSpec.getStatementDelimiter()); // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} + } else { + forBlock.addStatement("form.param(\"" + paramName + "\", i.toString())" + langSpec.getStatementDelimiter()); + } + forStatement.setBody(forBlock); + statements += forStatement; +// return "Entity entity = Entity.entity(" + paramName + ".toString(), MediaType.APPLICATION_JSON);"; } - if (DataConstraintModel.typeTuple.isAncestorOf(compType) || DataConstraintModel.typePair.isAncestorOf(paramType) || DataConstraintModel.typeList.isAncestorOf(compType) || DataConstraintModel.typeMap.isAncestorOf(paramType)) { - statements += "\tform.param(\"" + paramName + "\", " + langSpec.getConstructorInvocation("ObjectMapper", null) + ".writeValueAsString(i))" + langSpec.getStatementDelimiter() + "\n"; // typeTuple: {"1.0":2.0}, typePair: {"left": 1.0, "right":2.0} - } else { - statements += "\tform.param(\"" + paramName + "\", i.toString())" + langSpec.getStatementDelimiter() + "\n"; - } - statements += langSpec.getEndForStatement("i") + "\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 + "\", " + langSpec.getConstructorInvocation("ObjectMapper", null) + ".writeValueAsString(" + value + "))" + langSpec.getStatementDelimiter() + "\n"; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/generators/TypeInference.java new file mode 100644 index 0000000..1d9f4f9 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/TypeInference.java @@ -0,0 +1,2381 @@ +package generators; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import models.Node; +import models.algebra.Constant; +import models.algebra.Expression; +import models.algebra.Position; +import models.algebra.Symbol; +import models.algebra.Term; +import models.algebra.Type; +import models.algebra.Variable; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonType; +import models.dataConstraintModel.ListType; +import models.dataConstraintModel.MapType; +import models.dataConstraintModel.ResourceHierarchy; +import models.dataConstraintModel.ResourcePath; +import models.dataConstraintModel.Selector; +import models.dataConstraintModel.StateTransition; +import models.dataConstraintModel.TupleType; +import models.dataFlowModel.DataTransferModel; +import models.dataFlowModel.ResourceNode; + +/** + * Type inference for data transfer model + * + * @author Nitta + * + */ +public class TypeInference { + private ILanguageSpecific langSpec; + private Map listTypes = new HashMap<>(); + private Map listComponentTypes = new HashMap<>(); + private Map, Type> tupleTypes = new HashMap<>(); + private Map> tupleComponentTypes = new HashMap<>(); + private Map pairTypes = new HashMap<>(); + private Map pairComponentTypes = new HashMap<>(); + private Map, Type> mapTypes = new HashMap<>(); + private Map> mapComponentTypes = new HashMap<>(); + private Map, Type> jsonTypes = new HashMap<>(); + private Map> jsonMemberTypes = new HashMap<>(); + + public TypeInference(ILanguageSpecific langSpec) { + this.langSpec = langSpec; + } + + public Type getListType(Type compType) { + return listTypes.get(compType); + } + + public Type getListComponentType(Type listType) { + return listComponentTypes.get(listType); + } + + public Collection getListTypes() { + return listTypes.values(); + } + + public Type getTupleType(List compTypes) { + return tupleTypes.get(compTypes); + } + + public List getTupleComponentTypes(Type tupleType) { + return tupleComponentTypes.get(tupleType); + } + + public Collection getTupleTypes() { + return tupleTypes.values(); + } + + public Type getPairType(Type compType) { + return pairTypes.get(compType); + } + + public Type getPairComponentType(Type pairType) { + return pairComponentTypes.get(pairType); + } + + public Type getMapType(List compTypes) { + return mapTypes.get(compTypes); + } + + public List getMapComponentTypes(Type mapType) { + return mapComponentTypes.get(mapType); + } + + public Type getJsonType(Map memberTypes) { + return jsonTypes.get(memberTypes); + } + + public Map getJsonMemberTypes(Type jsonType) { + return jsonMemberTypes.get(jsonType); + } + + public void infer(DataTransferModel model) { + Map> resources = new HashMap<>(); + Map> resourcePathParams = new HashMap<>(); + Map variables = new HashMap<>(); + Map, Type>>> messages = new HashMap<>(); + Map consOrSet = new HashMap<>(); + Map tuple = new HashMap<>(); + Map pair = new HashMap<>(); + Map map = new HashMap<>(); + Map json = new HashMap<>(); + + // Maps from the objectId of each expression to its belonging group that has the same type as the expression + Map> expToResource = new HashMap<>(); + Map> expToPathParams = new HashMap<>(); + Map> expToVariable = new HashMap<>(); + Map> expToMessage = new HashMap<>(); + Map>> expToConsOrSet = new HashMap<>(); + Map>> expToTuple = new HashMap<>(); + Map>> expToPair = new HashMap<>(); + Map>> expToMap = new HashMap<>(); + Map>> expToJson = new HashMap<>(); + + // Maps from the objectId of each group to the set of updated expressions. + Map> updateFromResource = new HashMap<>(); + Set updateFromResourceOwnership = new HashSet<>(); + Map> updateFromVariable = new HashMap<>(); + Map> updateFromMessage = new HashMap<>(); + Map> updateFromConsOrSet = new HashMap<>(); + Map> updateFromTuple = new HashMap<>(); + Map> updateFromPair = new HashMap<>(); + Map> updateFromMap = new HashMap<>(); + Map> updateFromJson = new HashMap<>(); + + listComponentTypes.put(DataConstraintModel.typeList, null); + listComponentTypes.put(DataConstraintModel.typeListInt, DataConstraintModel.typeInt); + listComponentTypes.put(DataConstraintModel.typeListStr, DataConstraintModel.typeString); + listTypes.put(DataConstraintModel.typeInt, DataConstraintModel.typeListInt); + listTypes.put(DataConstraintModel.typeString, DataConstraintModel.typeListStr); + pairComponentTypes.put(DataConstraintModel.typePair, null); + pairComponentTypes.put(DataConstraintModel.typePairInt, DataConstraintModel.typeInt); + pairComponentTypes.put(DataConstraintModel.typePairStr, DataConstraintModel.typeString); + pairComponentTypes.put(DataConstraintModel.typePairDouble, DataConstraintModel.typeDouble); + pairTypes.put(DataConstraintModel.typeInt, DataConstraintModel.typePairInt); + pairTypes.put(DataConstraintModel.typeString, DataConstraintModel.typePairStr); + pairTypes.put(DataConstraintModel.typeDouble, DataConstraintModel.typePairDouble); + tupleComponentTypes.put(DataConstraintModel.typeTuple, Arrays.asList(new Type[] { null, null })); + mapComponentTypes.put(DataConstraintModel.typeMap, Arrays.asList(new Type[] { null, null })); + + // 1. Collect type information from the architecture model. + Collection channels = new HashSet<>(model.getInputChannels()); + channels.addAll(model.getChannels()); + for (Channel ch : channels) { + // 1.1 Group expressions by resources. + IGroupExpressionsByResource groupExpressionsByResource = new IGroupExpressionsByResource() { + public void groupForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + StateTransition st = cm.getStateTransition(); + ResourceHierarchy res = cm.getResource().getResourceHierarchy(); + List identicalResources = resources.get(res); + if (identicalResources == null) { + identicalResources = new ArrayList<>(); + resources.put(res, identicalResources); + } + identicalResources.add(st.getCurStateExpression()); + expToResource.put(System.identityHashCode(st.getCurStateExpression()), identicalResources); + if (st.getNextStateExpression() != null) { + identicalResources.add(st.getNextStateExpression()); + expToResource.put(System.identityHashCode(st.getNextStateExpression()), identicalResources); + } + Map updatedExps = getUpdateSet(updateFromResource, identicalResources); + Type resType = res.getResourceStateType(); + Expression exp = st.getCurStateExpression(); + Type expType = getExpTypeIfUpdatable(resType, exp); + if (expType != null) { + res.setResourceStateType(expType); + for (Expression resExp : identicalResources) { + if (resExp != exp) { + if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { + ((Variable) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); + } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { + ((Term) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); + } + } + } + } else if (exp instanceof Variable) { + if (compareTypes(((Variable) exp).getType(), resType)) { + ((Variable) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } + } else if (exp instanceof Term) { + if (compareTypes(((Term) exp).getType(), resType)) { + ((Term) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } + } + resType = res.getResourceStateType(); + exp = st.getNextStateExpression(); + if (exp != null) { + expType = getExpTypeIfUpdatable(resType, exp); + if (expType != null) { + res.setResourceStateType(expType); + for (Expression resExp : identicalResources) { + if (resExp != exp) { + if (resExp instanceof Variable && compareTypes(((Variable) resExp).getType(), expType)) { + ((Variable) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); + } else if (resExp instanceof Term && compareTypes(((Term) resExp).getType(), expType)) { + ((Term) resExp).setType(expType); + updatedExps.put(System.identityHashCode(resExp), resExp); + } + } + } + } else if (exp instanceof Variable) { + if (compareTypes(((Variable) exp).getType(), resType)) { + ((Variable) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } + } else if (exp instanceof Term) { + if (compareTypes(((Term) exp).getType(), resType)) { + ((Term) exp).setType(resType); + updatedExps.put(System.identityHashCode(exp), exp); + } + } + } + } + for (Channel childCh: ch.getChildren()) { + groupForChannel(childCh); + } + } + }; + groupExpressionsByResource.groupForChannel(ch); + + // 1.2 Group expressions by variable. + IGroupExpressionsByVariable groupExpressionsByVariable = new IGroupExpressionsByVariable() { + public void groupForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + StateTransition st = cm.getStateTransition(); + Map> locals = new HashMap<>(); + Map localTypes = new HashMap<>(); + List allVariables = new ArrayList<>(); + allVariables.addAll(st.getCurStateExpression().getVariables().values()); + allVariables.addAll(st.getMessageExpression().getVariables().values()); + if (st.getNextStateExpression() != null) { + allVariables.addAll(st.getNextStateExpression().getVariables().values()); + } + for (Selector s: ch.getAllSelectors()) { // add channel selectors + if (s.getExpression() instanceof Variable) { + allVariables.add((Variable) s.getExpression()); + } + } + ResourcePath resPath = cm.getResource(); + for (Expression param: resPath.getPathParams()) { // add path parameters + if (param instanceof Variable) { + allVariables.add((Variable) param); + } else if (param instanceof Term) { + allVariables.addAll(((Term) param).getVariables().values()); + } + } + for (Variable var : allVariables) { + List sameVariable = locals.get(var.getName()); + if (sameVariable == null) { + sameVariable = new ArrayList<>(); + sameVariable.add(var); + expToVariable.put(System.identityHashCode(var), sameVariable); + locals.put(var.getName(), sameVariable); + localTypes.put(var.getName(), var.getType()); + } else { + sameVariable.add(var); + expToVariable.put(System.identityHashCode(var), sameVariable); + Type varType = localTypes.get(var.getName()); + Map updatedVars = getUpdateSet(updateFromVariable, sameVariable); + if (compareTypes(varType, var.getType())) { + localTypes.put(var.getName(), var.getType()); + for (Expression v : sameVariable) { + if (v != var) { + if (compareTypes(((Variable) v).getType(), var.getType())) { + ((Variable) v).setType(var.getType()); + updatedVars.put(System.identityHashCode(v), v); + } + } + } + } else if (compareTypes(var.getType(), varType)) { + var.setType(varType); + updatedVars.put(System.identityHashCode(var), var); + } + } + } + for (String varName : locals.keySet()) { + variables.put(System.identityHashCode(locals.get(varName)), localTypes.get(varName)); + } + } + for (Channel childCh: ch.getChildren()) { + groupForChannel(childCh); + } + } + }; + groupExpressionsByVariable.groupForChannel(ch); + + // 1.3 Group expressions by message. + IGroupExpressionsByMessage groupExpressionsByMessage = new IGroupExpressionsByMessage() { + public void groupForChannel(Channel rootCh, Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + Expression message = cm.getStateTransition().getMessageExpression(); + if (message instanceof Variable) { + Type msgType = ((Variable) message).getType(); + Map, Type>> msgTypeMap = messages.get(rootCh); + if (msgTypeMap == null) { + msgTypeMap = new HashMap<>(); + messages.put(rootCh, msgTypeMap); + } + Map.Entry, Type> typeAndExps = msgTypeMap.get(0); + if (typeAndExps == null) { + List exps = new ArrayList<>(); + exps.add(message); + typeAndExps = new AbstractMap.SimpleEntry<>(exps, msgType); + msgTypeMap.put(0, typeAndExps); + expToMessage.put(System.identityHashCode(message), exps); + } else { + typeAndExps.getKey().add(message); + expToMessage.put(System.identityHashCode(message), typeAndExps.getKey()); + Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); + if (compareTypes(typeAndExps.getValue(), msgType)) { + typeAndExps.setValue(msgType); + for (Expression e : typeAndExps.getKey()) { + if (e != message) { + if (e instanceof Variable) { + ((Variable) e).setType(msgType); + updateExps.put(System.identityHashCode(e), e); + } + } + } + } else if (compareTypes(msgType, typeAndExps.getValue())) { + ((Variable) message).setType(typeAndExps.getValue()); + updateExps.put(System.identityHashCode(message), message); + } + } + } else if (message instanceof Term) { + Map, Type>> msgTypeMap = messages.get(rootCh); + if (msgTypeMap == null) { + msgTypeMap = new HashMap<>(); + messages.put(rootCh, msgTypeMap); + } + for (int i = 0; i < ((Term) message).getArity(); i++) { + Expression arg = ((Term) message).getChild(i); + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } else { + continue; + } + Map.Entry, Type> typeAndExps = msgTypeMap.get(i); + if (typeAndExps == null) { + List exps = new ArrayList<>(); + exps.add(arg); + typeAndExps = new AbstractMap.SimpleEntry<>(exps, argType); + msgTypeMap.put(i, typeAndExps); + expToMessage.put(System.identityHashCode(arg), exps); + } else { + typeAndExps.getKey().add(arg); + expToMessage.put(System.identityHashCode(arg), typeAndExps.getKey()); + Map updateExps = getUpdateSet(updateFromMessage, typeAndExps.getKey()); + if (compareTypes(typeAndExps.getValue(), argType)) { + typeAndExps.setValue(argType); + for (Expression e : typeAndExps.getKey()) { + if (e != arg) { + if (e instanceof Variable) { + ((Variable) e).setType(argType); + updateExps.put(System.identityHashCode(e), e); + } + } + } + } else if (compareTypes(argType, typeAndExps.getValue())) { + if (arg instanceof Variable) { + ((Variable) arg).setType(typeAndExps.getValue()); + updateExps.put(System.identityHashCode(arg), arg); + } else if (arg instanceof Term) { + ((Term) arg).setType(typeAndExps.getValue()); + updateExps.put(System.identityHashCode(arg), arg); + } + } + } + } + } + } + for (Channel childCh: ch.getChildren()) { + groupForChannel(rootCh, childCh); + } + } + }; + groupExpressionsByMessage.groupForChannel(ch, ch); + + // 1.4 Extract constraints on expressions in each term. + IExtractConstraintsOnExpressionsInTerm extractConstraintsOnExpressionsInTerm = new IExtractConstraintsOnExpressionsInTerm() { + public void extractForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + StateTransition st = cm.getStateTransition(); + List terms = new ArrayList<>(); + if (st.getCurStateExpression() instanceof Term) { + Map subTerms = ((Term) st.getCurStateExpression()).getSubTerms(Term.class); + terms.addAll(subTerms.values()); + } + if (st.getMessageExpression() instanceof Term) { + Map subTerms = ((Term) st.getMessageExpression()).getSubTerms(Term.class); + terms.addAll(subTerms.values()); + } + if (st.getNextStateExpression() != null && st.getNextStateExpression() instanceof Term) { + Map subTerms = ((Term) st.getNextStateExpression()).getSubTerms(Term.class); + terms.addAll(subTerms.values()); + } + for (Term t : terms) { + Symbol symbol = t.getSymbol(); + if (symbol.equals(DataConstraintModel.cons) || symbol.equals(DataConstraintModel.set) || symbol.equals(DataConstraintModel.append)) { + // If the root symbol of the term is cons or set. + List consExps = new ArrayList<>(); + consExps.add(t); // list term + updateExpressionBelonging(expToConsOrSet, t, consExps); + if (symbol.equals(DataConstraintModel.cons)) { + // If the root symbol of the term is cons. + for (Expression e : t.getChildren()) { + consExps.add(e); + updateExpressionBelonging(expToConsOrSet, e, consExps); + } + } else if (symbol.equals(DataConstraintModel.append)) { + // If the root symbol of the term is append. + Expression e = t.getChildren().get(1); + consExps.add(e); // list element + updateExpressionBelonging(expToConsOrSet, e, consExps); + e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + } else { + // If the root symbol of the term is set. + Expression e = t.getChildren().get(2); + consExps.add(e); // list element + updateExpressionBelonging(expToConsOrSet, e, consExps); + e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + } + Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); + if (newType != null) { + // If the type of the 2nd argument of cons (1st argument of set/append) is more concrete than the type of the term. + t.setType(newType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + } else { + Type arg2Type = null; + if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { + arg2Type = ((Variable) consExps.get(2)).getType(); + if (compareTypes(arg2Type, t.getType())) { + // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set/append). + ((Variable) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { + arg2Type = ((Term) consExps.get(2)).getType(); + if (compareTypes(arg2Type, t.getType())) { + // If the type of the term is more concrete than the type of the 2nd argument of cons (1st argument of set/append). + ((Term) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } + } + Type newCompType = getExpTypeIfUpdatable(listComponentTypes.get(t.getType()), consExps.get(1)); + if (newCompType != null) { + // If the type of the 1st argument of cons (3rd argument of set) is more concrete than the type of list component. + Type newListType = listTypes.get(newCompType); + if (newListType == null) { + // Create new list type. + newListType = createNewListType(newCompType, DataConstraintModel.typeList); + } + t.setType(newListType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { + ((Variable) consExps.get(2)).setType(newListType); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { + ((Term) consExps.get(2)).setType(newListType); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } + consOrSet.put(System.identityHashCode(consExps), t.getType()); + } else if (symbol.equals(DataConstraintModel.head) || symbol.equals(DataConstraintModel.get)) { + // If the root symbol of the term is head or get. + List consExps = new ArrayList<>(); + Expression e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + consExps.add(t); // list's component + updateExpressionBelonging(expToConsOrSet, t, consExps); + consExps.add(null); + Type listType = listTypes.get(t.getType()); + if (listType == null && t.getType() != null) { + // Create a new list type. + listType = createNewListType(t.getType(), DataConstraintModel.typeList); + } + Type newListType = getExpTypeIfUpdatable(listType, consExps.get(0)); + if (newListType != null) { + // If the type of the component of the 1st argument is more concrete than the type of the term. + Type newCompType = listComponentTypes.get(newListType); + if (newCompType != null) { + t.setType(newCompType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + } + consOrSet.put(System.identityHashCode(consExps), newListType); + } else { + // If the type of the term is more concrete than the type of the component of the 1st argument. + if (consExps.get(0) != null && consExps.get(0) instanceof Variable) { + ((Variable) consExps.get(0)).setType(listType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); + } else if (consExps.get(0) != null && consExps.get(0) instanceof Term) { + ((Term) consExps.get(0)).setType(listType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(0)), consExps.get(0)); + } + consOrSet.put(System.identityHashCode(consExps), listType); + } + } else if (symbol.equals(DataConstraintModel.tail)) { + // If the root symbol of the term is tail. + List consExps = new ArrayList<>(); + consExps.add(t); // list term + updateExpressionBelonging(expToConsOrSet, t, consExps); + consExps.add(null); // list's component + Expression e = t.getChildren().get(0); + consExps.add(e); // list argument + updateExpressionBelonging(expToConsOrSet, e, consExps); + Type newType = getExpTypeIfUpdatable(t.getType(), consExps.get(2)); + if (newType != null) { + // If the type of the argument is more concrete than the type of the term. + t.setType(newType); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(t), t); + } else { + Type argType = null; + if (consExps.get(2) != null && consExps.get(2) instanceof Variable) { + argType = ((Variable) consExps.get(2)).getType(); + if (compareTypes(argType, t.getType())) { + // If the type of the term is more concrete than the type of the argument. + ((Variable) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } else if (consExps.get(2) != null && consExps.get(2) instanceof Term) { + argType = ((Term) consExps.get(2)).getType(); + if (compareTypes(argType, t.getType())) { + // If the type of the term is more concrete than the type of the argument. + ((Term) consExps.get(2)).setType(t.getType()); + Map updateCons = getUpdateSet(updateFromConsOrSet, consExps); + updateCons.put(System.identityHashCode(consExps.get(2)), consExps.get(2)); + } + } + } + consOrSet.put(System.identityHashCode(consExps), t.getType()); + } else if (symbol.equals(DataConstraintModel.tuple)) { + // If the root symbol of the term is tuple. + List tupleExps = new ArrayList<>(); + List newArgTypesList = new ArrayList<>(); + tupleExps.add(t); // tuple term + updateExpressionBelonging(expToTuple, t, tupleExps); + for (Expression e : t.getChildren()) { + tupleExps.add(e); // tuple's component + updateExpressionBelonging(expToTuple, e, tupleExps); + if (e instanceof Variable) { + newArgTypesList.add(((Variable) e).getType()); + } else if (e instanceof Term) { + newArgTypesList.add(((Term) e).getType()); + } else { + newArgTypesList.add(null); + } + } + if (t.getType() == DataConstraintModel.typeTuple) { + Type newTupleType = tupleTypes.get(newArgTypesList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(newArgTypesList, DataConstraintModel.typeTuple); + } + // Update the type of the tuple term and record the updated expression. + t.setType(newTupleType); + Map updateExps = getUpdateSet(updateFromTuple, tupleExps); + updateExps.put(System.identityHashCode(t), t); + } + tuple.put(System.identityHashCode(tupleExps), t.getType()); + } else if (symbol.equals(DataConstraintModel.pair)) { + // If the root symbol of the term is pair. + List pairExps = new ArrayList<>(); + pairExps.add(t); // pair + updateExpressionBelonging(expToPair, t, pairExps); + if (t.getType() == DataConstraintModel.typePair) { + for (Expression e : t.getChildren()) { + pairExps.add(e); // left/right + updateExpressionBelonging(expToPair, e, pairExps); + Type newArgType = null; + if (e instanceof Variable) { + newArgType = (((Variable) e).getType()); + + } else if (e instanceof Term) { + newArgType = (((Term) e).getType()); + } + + if (newArgType != null) { + Type newPairType = pairTypes.get(newArgType); + if (newPairType != null) { + t.setType(newPairType); + Map updateExps = getUpdateSet(updateFromPair, pairExps); + updateExps.put(System.identityHashCode(t), t); + } + } + } + pair.put(System.identityHashCode(pairExps), t.getType()); + + } + } else if (symbol.equals(DataConstraintModel.fst)) { + // If the root symbol of the term is fst. + List tupleExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + tupleExps.add(arg); // tuple argument + updateExpressionBelonging(expToTuple, arg, tupleExps); + tupleExps.add(t); // first component + updateExpressionBelonging(expToTuple, t, tupleExps); + tupleExps.add(null); // second component + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newTupleType = DataConstraintModel.typeTuple; + if (argType == DataConstraintModel.typeTuple && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(t.getType()); + newCompTypeList.add(null); + newTupleType = tupleTypes.get(newCompTypeList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); + } + } + if (argType != newTupleType && newTupleType != null) { + // Update the type of the tuple argument and record the updated expression. + if (arg instanceof Variable) { + ((Variable) arg).setType(newTupleType); + argType = newTupleType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newTupleType); + argType = newTupleType; + } + Map updateExps = getUpdateSet(updateFromTuple, tupleExps); + updateExps.put(System.identityHashCode(arg), arg); + } + tuple.put(System.identityHashCode(tupleExps), argType); + } else if (symbol.equals(DataConstraintModel.snd)) { + // If the root symbol of the term is snd. + List tupleExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + tupleExps.add(arg); // tuple argument + updateExpressionBelonging(expToTuple, arg, tupleExps); + tupleExps.add(null); // first component + tupleExps.add(t); // second component + updateExpressionBelonging(expToTuple, t, tupleExps); + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newTupleType = DataConstraintModel.typeTuple; + if (argType == DataConstraintModel.typeTuple && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(null); + if (DataConstraintModel.typeTuple.isAncestorOf(t.getType())) { + List sndTypes = tupleComponentTypes.get(t.getType()); + if (sndTypes != null) { + for (Type t2: sndTypes) { + newCompTypeList.add(t2); + } + } else { + newCompTypeList.add(t.getType()); + } + } else { + newCompTypeList.add(t.getType()); + } + newTupleType = tupleTypes.get(newCompTypeList); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(newCompTypeList, DataConstraintModel.typeTuple); + } + } + if (argType != newTupleType && newTupleType != null) { + // Update the type of the tuple argument and record the updated expression. + if (arg instanceof Variable) { + ((Variable) arg).setType(newTupleType); + argType = newTupleType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newTupleType); + argType = newTupleType; + } + Map updateExps = getUpdateSet(updateFromTuple, tupleExps); + updateExps.put(System.identityHashCode(arg), arg); + } + tuple.put(System.identityHashCode(tupleExps), argType); + } else if (symbol.equals(DataConstraintModel.left)) { + // If the root symbol of the term is left. + List pairExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + pairExps.add(arg); // pair + updateExpressionBelonging(expToPair, arg, pairExps); + pairExps.add(t); // left + updateExpressionBelonging(expToPair, t, pairExps); + pairExps.add(null); // right + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newPairType = DataConstraintModel.typePair; + if (argType == DataConstraintModel.typePair && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(t.getType()); + newCompTypeList.add(null); + newPairType = pairTypes.get(newCompTypeList); + if (newPairType == null) { + // Create new tuple type; + newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); + } + } + if (argType != newPairType && newPairType != null) { + if (arg instanceof Variable) { + ((Variable) arg).setType(newPairType); + argType = newPairType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newPairType); + argType = newPairType; + } + Map updateExps = getUpdateSet(updateFromPair, pairExps); + updateExps.put(System.identityHashCode(arg), arg); + } + pair.put(System.identityHashCode(pairExps), argType); + } else if (symbol.equals(DataConstraintModel.right)) { + // If the root symbol of the term is right. + List pairExps = new ArrayList<>(); + Expression arg = t.getChildren().get(0); + pairExps.add(arg); // pair + updateExpressionBelonging(expToPair, arg, pairExps); + pairExps.add(null); // left + pairExps.add(t); // right + updateExpressionBelonging(expToPair, t, pairExps); + Type argType = null; + if (arg instanceof Variable) { + argType = ((Variable) arg).getType(); + } else if (arg instanceof Term) { + argType = ((Term) arg).getType(); + } + Type newPairType = DataConstraintModel.typePair; + if (argType == DataConstraintModel.typePair && t.getType() != null) { + List newCompTypeList = new ArrayList<>(); + newCompTypeList.add(null); + newCompTypeList.add(t.getType()); + newPairType = pairTypes.get(newCompTypeList); + if (newPairType == null) { + // Create new tuple type; + newPairType = createNewTupleType(newCompTypeList, DataConstraintModel.typePair); + } + } + if (argType != newPairType && newPairType != null) { + if (arg instanceof Variable) { + ((Variable) arg).setType(newPairType); + argType = newPairType; + } else if (arg instanceof Term) { + ((Term) arg).setType(newPairType); + argType = newPairType; + } + Map updateExps = getUpdateSet(updateFromPair, pairExps); + updateExps.put(System.identityHashCode(arg), arg); + } + pair.put(System.identityHashCode(pairExps), argType); + } else if (symbol.equals(DataConstraintModel.lookup)) { + // If the root symbol of the term is lookup. + List mapExps = new ArrayList<>(); + Expression arg1 = t.getChildren().get(0); // map + mapExps.add(arg1); + updateExpressionBelonging(expToMap, arg1, mapExps); + Expression arg2 = t.getChildren().get(1); // key + mapExps.add(arg2); + updateExpressionBelonging(expToMap, arg2, mapExps); + mapExps.add(t); // value + updateExpressionBelonging(expToMap, t, mapExps); + Type arg1Type = null; + if (arg1 instanceof Variable) { + arg1Type = ((Variable) arg1).getType(); + } else if (arg1 instanceof Term) { + arg1Type = ((Term) arg1).getType(); + } + List newCompTypeList = new ArrayList<>(); + if (arg2 instanceof Variable) { + newCompTypeList.add(((Variable) arg2).getType()); + } else if (arg2 instanceof Term) { + newCompTypeList.add(((Term) arg2).getType()); + } else { + newCompTypeList.add(null); + } + newCompTypeList.add(t.getType()); + if (arg1Type == DataConstraintModel.typeMap || arg1Type == null) { + Type newMapType = mapTypes.get(newCompTypeList); + if (newMapType == null) { + // Create new tuple type; + newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); + } + // Update the type of the map argument and record the updated expression. + if (arg1 instanceof Variable) { + ((Variable) arg1).setType(newMapType); + arg1Type = newMapType; + } else if (arg1 instanceof Term) { + ((Term) arg1).setType(newMapType); + arg1Type = newMapType; + } + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(arg1), arg1); + } + map.put(System.identityHashCode(mapExps), arg1Type); + } else if (symbol.equals(DataConstraintModel.insert)) { + // If the root symbol of the term is insert. + List mapExps = new ArrayList<>(); + mapExps.add(t); // map + updateExpressionBelonging(expToMap, t, mapExps); + Expression arg1 = t.getChildren().get(1); // key + mapExps.add(arg1); + updateExpressionBelonging(expToMap, arg1, mapExps); + Expression arg2 = t.getChildren().get(2); // value + mapExps.add(arg2); + updateExpressionBelonging(expToMap, arg2, mapExps); + Expression arg0 = t.getChildren().get(0); // map + mapExps.add(arg0); + updateExpressionBelonging(expToMap, arg0, mapExps); + Type termType = t.getType(); + List newCompTypeList = new ArrayList<>(); + if (arg1 instanceof Variable) { + newCompTypeList.add(((Variable) arg1).getType()); + } else if (arg1 instanceof Term) { + newCompTypeList.add(((Term) arg1).getType()); + } else { + newCompTypeList.add(null); + } + if (arg2 instanceof Variable) { + newCompTypeList.add(((Variable) arg2).getType()); + } else if (arg2 instanceof Term) { + newCompTypeList.add(((Term) arg2).getType()); + } else { + newCompTypeList.add(null); + } + Type newTermType = getExpTypeIfUpdatable(termType, mapExps.get(3)); + if (newTermType != null) { + // If the type of the 1st argument of insert is more concrete than the type of the term. + t.setType(newTermType); + termType = newTermType; + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(t), t); + } else { + Type arg3Type = null; + if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { + arg3Type = ((Variable) mapExps.get(3)).getType(); + if (compareTypes(arg3Type, t.getType())) { + // If the type of the term is more concrete than the type of the 1st argument of insert. + ((Variable) mapExps.get(3)).setType(t.getType()); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { + arg3Type = ((Term) mapExps.get(3)).getType(); + if (compareTypes(arg3Type, t.getType())) { + // If the type of the term is more concrete than the type of the 1st argument of insert. + ((Term) mapExps.get(3)).setType(t.getType()); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + } + } + if (termType == DataConstraintModel.typeMap || termType == null) { + Type newMapType = mapTypes.get(newCompTypeList); + if (newMapType == null) { + // Create new tuple type; + newMapType = createNewMapType(newCompTypeList, DataConstraintModel.typeMap); + } + // Update the type of the map term and record the updated expression. + t.setType(newMapType); + Map updateExps = getUpdateSet(updateFromMap, mapExps); + updateExps.put(System.identityHashCode(t), t); + if (mapExps.get(3) != null && mapExps.get(3) instanceof Variable) { + ((Variable) mapExps.get(3)).setType(newMapType); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } else if (mapExps.get(3) != null && mapExps.get(3) instanceof Term) { + ((Term) mapExps.get(3)).setType(newMapType); + updateExps.put(System.identityHashCode(mapExps.get(3)), mapExps.get(3)); + } + termType = newMapType; + } + map.put(System.identityHashCode(mapExps), termType); + } else if (symbol.equals(DataConstraintModel.addMember)) { + // If the root symbol of the term is addMember (addMember(json, key, value)). + List dotExps = new ArrayList<>(); + Expression jsonArg = t.getChildren().get(0); + Expression keyArg = t.getChildren().get(1); + Expression valueArg = t.getChildren().get(2); + dotExps.add(t); // json + updateExpressionBelonging(expToJson, t, dotExps); + dotExps.add(keyArg); // key + updateExpressionBelonging(expToJson, keyArg, dotExps); + dotExps.add(valueArg); // value + updateExpressionBelonging(expToJson, valueArg, dotExps); + dotExps.add(jsonArg); // json + updateExpressionBelonging(expToJson, jsonArg, dotExps); + Type jsonType = t.getType(); + Type valueType = null; + if (valueArg instanceof Variable) { + valueType = ((Variable) valueArg).getType(); + } else if (valueArg instanceof Term) { + valueType = ((Term) valueArg).getType(); + } + String keyName = null; + if (keyArg instanceof Constant) { + keyName = ((Constant) keyArg).getSymbol().getName(); + } + Type jsonArgType = null; + if (jsonArg instanceof Variable) { + jsonArgType = ((Variable) jsonArg).getType(); + } else if (jsonArg instanceof Term) { + jsonArgType = ((Term) jsonArg).getType(); + } + Type newJsonType = DataConstraintModel.typeJson; + if (jsonType == DataConstraintModel.typeJson && jsonArgType != null && keyName != null) { + Map newMemberTypes = new HashMap<>(((JsonType) jsonArgType).getMemberTypes()); + newMemberTypes.put(keyName, valueType); + newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + // Create new json type; + newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); + } + } + if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { + // Update the type of the json term and record the updated expression. + t.setType(newJsonType); + jsonType = newJsonType; + Map updateExps = getUpdateSet(updateFromJson, dotExps); + updateExps.put(System.identityHashCode(t), t); + } + json.put(System.identityHashCode(dotExps), jsonType); + } else if (symbol.equals(DataConstraintModel.dot)) { + // If the root symbol of the term is dot (json.property). + List dotExps = new ArrayList<>(); + Expression jsonArg = t.getChildren().get(0); + Expression keyArg = t.getChildren().get(1); + dotExps.add(jsonArg); // json + updateExpressionBelonging(expToJson, jsonArg, dotExps); + dotExps.add(keyArg); // key + updateExpressionBelonging(expToJson, keyArg, dotExps); + dotExps.add(t); // value + updateExpressionBelonging(expToJson, t, dotExps); + dotExps.add(null); // json + Type jsonType = null; + if (jsonArg instanceof Variable) { + jsonType = ((Variable) jsonArg).getType(); + } else if (jsonArg instanceof Term) { + jsonType = ((Term) jsonArg).getType(); + } + String keyName = null; + if (keyArg instanceof Constant) { + keyName = ((Constant) keyArg).getSymbol().getName(); + } + Type newJsonType = DataConstraintModel.typeJson; + if (jsonType == DataConstraintModel.typeJson && t.getType() != null && keyName != null) { + Map newMemberTypes = new HashMap<>(); + newMemberTypes.put(keyName, t.getType()); + newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + // Create new json type; + newJsonType = createNewJsonType(newMemberTypes, DataConstraintModel.typeJson); + } + } + if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { + // Update the type of the json argument and record the updated expression. + if (jsonArg instanceof Variable) { + ((Variable) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } else if (jsonArg instanceof Term) { + ((Term) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } + Map updateExps = getUpdateSet(updateFromJson, dotExps); + updateExps.put(System.identityHashCode(jsonArg), jsonArg); + } + json.put(System.identityHashCode(dotExps), jsonType); + } else if (symbol.equals(DataConstraintModel.dotParam)) { + // If the root symbol of the term is dot (json.{param}). + List dotExps = new ArrayList<>(); + Expression jsonArg = t.getChildren().get(0); + Expression keyArg = t.getChildren().get(1); + dotExps.add(jsonArg); // json (list/map) + updateExpressionBelonging(expToJson, jsonArg, dotExps); + dotExps.add(null); // key + dotExps.add(t); // value + updateExpressionBelonging(expToJson, t, dotExps); + dotExps.add(null); // json + Type jsonType = null; + if (jsonArg instanceof Variable) { + jsonType = ((Variable) jsonArg).getType(); + } else if (jsonArg instanceof Term) { + jsonType = ((Term) jsonArg).getType(); + } + Type keyType = null; + if (keyArg instanceof Variable) { + keyType = ((Variable) keyArg).getType(); + } else if (keyArg instanceof Term) { + keyType = ((Term) keyArg).getType(); + } + Type newJsonType = null; + if (keyType == DataConstraintModel.typeInt) { + newJsonType = DataConstraintModel.typeList; + } else if (keyType == DataConstraintModel.typeString) { + newJsonType = DataConstraintModel.typeMap; + } + if (t.getType() != null) { + if ((jsonType == DataConstraintModel.typeList)) { + newJsonType = listTypes.get(t.getType()); + if (newJsonType == null) { + // Create new list type; + newJsonType = createNewListType(t.getType(), DataConstraintModel.typeList); + } + } else if (jsonType == DataConstraintModel.typeMap) { + List keyValueTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, t.getType()}); + newJsonType = mapTypes.get(keyValueTypes); + if (newJsonType == null) { + // Create new map type; + newJsonType = createNewMapType(keyValueTypes, DataConstraintModel.typeMap); + } + } + } + if (jsonType != newJsonType && newJsonType != null && !newJsonType.isAncestorOf(jsonType)) { + // Update the type of the json argument and record the updated expression. + if (jsonArg instanceof Variable) { + ((Variable) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } else if (jsonArg instanceof Term) { + ((Term) jsonArg).setType(newJsonType); + jsonType = newJsonType; + } + Map updateExps = getUpdateSet(updateFromJson, dotExps); + updateExps.put(System.identityHashCode(jsonArg), jsonArg); + } + json.put(System.identityHashCode(dotExps), jsonType); + } else if (symbol.equals(DataConstraintModel.cond)) { + // If the root symbol of the term is if function. + Expression c1 = t.getChild(1); + Expression c2 = t.getChild(2); + List condTerms = new ArrayList<>(); + condTerms.add(t); + condTerms.add(c1); + condTerms.add(c2); + expToVariable.put(System.identityHashCode(t), condTerms); + expToVariable.put(System.identityHashCode(c1), condTerms); + expToVariable.put(System.identityHashCode(c2), condTerms); + Type condType = t.getType(); + Map updatedVars = getUpdateSet(updateFromVariable, condTerms); + Type child1Type = getExpTypeIfUpdatable(condType, c1); + if (child1Type != null) { + condType = child1Type; + t.setType(child1Type); + updatedVars.put(System.identityHashCode(t), t); + } else { + if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), condType)) { + ((Variable) c1).setType(condType); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), condType)) { + ((Term) c1).setType(condType); + updatedVars.put(System.identityHashCode(c1), c1); + } + } + Type child2Type = getExpTypeIfUpdatable(condType, c2); + if (child2Type != null) { + condType = child2Type; + t.setType(child2Type); + updatedVars.put(System.identityHashCode(t), t); + if (c1 instanceof Variable) { + ((Variable) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term) { + ((Term) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } + } else { + if (c2 instanceof Variable && compareTypes(((Variable) c2).getType(), condType)) { + ((Variable) c2).setType(condType); + updatedVars.put(System.identityHashCode(c2), c2); + } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), condType)) { + ((Term) c2).setType(condType); + updatedVars.put(System.identityHashCode(c2), c2); + } + } + variables.put(System.identityHashCode(condTerms), condType); + } else if (symbol.equals(DataConstraintModel.add) || symbol.equals(DataConstraintModel.sub) + || symbol.equals(DataConstraintModel.mul) || symbol.equals(DataConstraintModel.div)) { + // If the root symbol of the term is arithmetic operators. + Expression c1 = t.getChild(0); + Expression c2 = t.getChild(1); + List operands = new ArrayList<>(); + operands.add(t); + operands.add(c1); + operands.add(c2); + expToVariable.put(System.identityHashCode(t), operands); + expToVariable.put(System.identityHashCode(c1), operands); + expToVariable.put(System.identityHashCode(c2), operands); + Type opType = t.getType(); + Map updatedVars = getUpdateSet(updateFromVariable, operands); + Type child1Type = getExpTypeIfUpdatable(opType, c1); + if (child1Type != null) { + opType = child1Type; + t.setType(child1Type); + updatedVars.put(System.identityHashCode(t), t); + } else { + if (c1 instanceof Variable && compareTypes(((Variable) c1).getType(), opType)) { + ((Variable) c1).setType(opType); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term && compareTypes(((Term) c1).getType(), opType)) { + ((Term) c1).setType(opType); + updatedVars.put(System.identityHashCode(c1), c1); + } + } + Type child2Type = getExpTypeIfUpdatable(opType, c2); + if (child2Type != null) { + opType = child2Type; + t.setType(child2Type); + updatedVars.put(System.identityHashCode(t), t); + if (c1 instanceof Variable) { + ((Variable) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } else if (c1 instanceof Term) { + ((Term) c1).setType(child2Type); + updatedVars.put(System.identityHashCode(c1), c1); + } + } else { + if (c2 instanceof Variable && compareTypes(((Variable) c2).getType(), opType)) { + ((Variable) c2).setType(opType); + updatedVars.put(System.identityHashCode(c2), c2); + } else if (c2 instanceof Term && compareTypes(((Term) c2).getType(), opType)) { + ((Term) c2).setType(opType); + updatedVars.put(System.identityHashCode(c2), c2); + } + } + variables.put(System.identityHashCode(operands), opType); + } else if (symbol.getSignature() != null + && symbol.getSignature()[0] == DataConstraintModel.typeList) { + // If the root symbol of the term is the list type (except for the cons function). + List consExps = new ArrayList<>(); + consExps.add(t); + expToVariable.put(System.identityHashCode(t), consExps); + Type condType = t.getType(); + Map updatedVars = getUpdateSet(updateFromVariable, consExps); + for (int i = 1; i < symbol.getSignature().length; i++) { + Type tc = symbol.getSignature()[i]; + if (tc == DataConstraintModel.typeList) { + Expression e = t.getChildren().get(i - 1); + Type newType = getExpTypeIfUpdatable(condType, e); + if (newType != null) { + condType = newType; + for (Expression e2 : consExps) { + if (e2 instanceof Variable) { + ((Variable) e2).setType(newType); + updatedVars.put(System.identityHashCode(e2), e2); + } else if (e2 instanceof Term) { + ((Term) e2).setType(newType); + updatedVars.put(System.identityHashCode(e2), e2); + } + } + } else { + if (e instanceof Variable && compareTypes(((Variable) e).getType(), condType)) { + ((Variable) e).setType(condType); + updatedVars.put(System.identityHashCode(e), e); + } else if (e instanceof Term && compareTypes(((Term) e).getType(), condType)) { + ((Term) e).setType(condType); + updatedVars.put(System.identityHashCode(e), e); + } + } + consExps.add(e); + expToVariable.put(System.identityHashCode(e), consExps); + } + } + variables.put(System.identityHashCode(consExps), condType); + } + } + } + for (Channel childCh: ch.getChildren()) { + extractForChannel(childCh); + } + } + }; + extractConstraintsOnExpressionsInTerm.extractForChannel(ch); + + // 1.5 Extract constraints on path parameters and resources. + IExtractConstraintsOnPathParametersAndResources extractConstraintsOnPathParametersAndResources = new IExtractConstraintsOnPathParametersAndResources() { + public void extractForChannel(Channel ch) { + for (ChannelMember cm : ch.getChannelMembers()) { + ResourcePath rPath = cm.getResource(); + while (rPath != null) { + Expression param = rPath.getLastParam(); + if (param != null) { + ResourceHierarchy parent = rPath.getResourceHierarchy().getParent(); + if (parent != null) { + List pathParams = resourcePathParams.get(parent); + if (pathParams == null) { + pathParams = new ArrayList<>(); + resourcePathParams.put(parent, pathParams); + } + pathParams.add(param); + expToPathParams.put(System.identityHashCode(param), pathParams); + Type parentType = parent.getResourceStateType(); + Type paramType = null; + if (param instanceof Variable) { + paramType = ((Variable) param).getType(); + } else if (param instanceof Term) { + paramType = ((Term) param).getType(); + } + if (paramType != null && parentType == null) { + if (paramType.equals(DataConstraintModel.typeString)) { + parentType = DataConstraintModel.typeMap; + } else if (paramType.equals(DataConstraintModel.typeInt)) { + parentType = DataConstraintModel.typeList; + } + if (parentType != null) { + parent.setResourceStateType(parentType); + updateFromResourceOwnership.add(parent); + } + } + } + } + rPath = rPath.getParent(); + } + } + for (Channel childCh: ch.getChildren()) { + extractForChannel(childCh); + } + } + }; + extractConstraintsOnPathParametersAndResources.extractForChannel(ch); + } + + // 1.6 Extract constraints on resource hierarchies. + for (ResourceHierarchy res: model.getResourceHierarchies()) { + if (res.getResourceStateType() != null) { + updateFromResourceOwnership.add(res); + } + } + + // 2. Propagate type information. + while (updateFromResource.size() > 0 || updateFromVariable.size() > 0 || updateFromMessage.size() > 0 + || updateFromConsOrSet.size() > 0 || updateFromTuple.size() > 0 || updateFromPair.size() > 0 + || updateFromMap.size() > 0 || updateFromJson.size() > 0 || updateFromResourceOwnership.size() > 0) { + if (updateFromResource.size() > 0) { + Set resourceKeys = updateFromResource.keySet(); + Integer resourceKey = resourceKeys.iterator().next(); + Map resourceValue = updateFromResource.get(resourceKey); + updateFromResource.remove(resourceKey); + for (int i : resourceValue.keySet()) { + Expression resExp = resourceValue.get(i); + updateVaribleTypes(resExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(resExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(resExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(resExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(resExp, pair, expToPair, updateFromPair); + updateMapTypes(resExp, map, expToMap, updateFromMap); + updateJsonTypes(resExp, json, expToJson, updateFromJson); + updateResourcePathParamsTypes(resExp, resourcePathParams, updateFromResourceOwnership); + } + } + if (updateFromVariable.size() > 0) { + Set variableKeys = updateFromVariable.keySet(); + Integer variableKey = variableKeys.iterator().next(); + Map variableValue = updateFromVariable.get(variableKey); + updateFromVariable.remove(variableKey); + for (int i : variableValue.keySet()) { + Expression var = variableValue.get(i); + updateResourceTypes(var, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(var, variables, expToVariable, updateFromVariable); + updateMessageTypes(var, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(var, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(var, tuple, expToTuple, updateFromTuple); + updatePairTypes(var, pair, expToPair, updateFromPair); + updateMapTypes(var, map, expToMap, updateFromMap); + updateJsonTypes(var, json, expToJson, updateFromJson); + updateResourcePathParamsTypes(var, resourcePathParams, updateFromResourceOwnership); + } + } + if (updateFromMessage.size() > 0) { + Set messageKeys = updateFromMessage.keySet(); + Integer messageKey = messageKeys.iterator().next(); + Map messageValue = updateFromMessage.get(messageKey); + updateFromMessage.remove(messageKey); + for (int i : messageValue.keySet()) { + Expression mesExp = messageValue.get(i); + updateResourceTypes(mesExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(mesExp, variables, expToVariable, updateFromVariable); + updateConsOrSetTypes(mesExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(mesExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(mesExp, pair, expToPair, updateFromPair); + updateMapTypes(mesExp, map, expToMap, updateFromMap); + updateJsonTypes(mesExp, json, expToJson, updateFromJson); + updateResourcePathParamsTypes(mesExp, resourcePathParams, updateFromResourceOwnership); + } + } + if (updateFromConsOrSet.size() > 0) { + Set consKeys = updateFromConsOrSet.keySet(); + Integer consKey = consKeys.iterator().next(); + Map consValue = updateFromConsOrSet.get(consKey); + updateFromConsOrSet.remove(consKey); + for (int i : consValue.keySet()) { + Expression consExp = consValue.get(i); + updateResourceTypes(consExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(consExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(consExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(consExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(consExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(consExp, pair, expToPair, updateFromPair); + updateMapTypes(consExp, map, expToMap, updateFromMap); + updateJsonTypes(consExp, json, expToJson, updateFromJson); + } + } + if (updateFromTuple.size() > 0) { + Set tupleKeys = updateFromTuple.keySet(); + Integer tupleKey = tupleKeys.iterator().next(); + Map tupleValue = updateFromTuple.get(tupleKey); + updateFromTuple.remove(tupleKey); + for (int i : tupleValue.keySet()) { + Expression tupleExp = tupleValue.get(i); + updateResourceTypes(tupleExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(tupleExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(tupleExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(tupleExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(tupleExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(tupleExp, pair, expToPair, updateFromPair); + updateMapTypes(tupleExp, map, expToMap, updateFromMap); + updateJsonTypes(tupleExp, json, expToJson, updateFromJson); + } + } + if (updateFromPair.size() > 0) { + Set pairKeys = updateFromPair.keySet(); + Integer pairKey = pairKeys.iterator().next(); + Map pairValue = updateFromPair.get(pairKey); + updateFromPair.remove(pairKey); + for (int i : pairValue.keySet()) { + Expression pairExp = pairValue.get(i); + updateResourceTypes(pairExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(pairExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(pairExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(pairExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(pairExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(pairExp, pair, expToPair, updateFromPair); + updateMapTypes(pairExp, map, expToMap, updateFromMap); + updateJsonTypes(pairExp, json, expToJson, updateFromJson); + } + } + if (updateFromMap.size() > 0) { + Set mapKeys = updateFromMap.keySet(); + Integer mapKey = mapKeys.iterator().next(); + Map mapValue = updateFromMap.get(mapKey); + updateFromMap.remove(mapKey); + for (int i : mapValue.keySet()) { + Expression mapExp = mapValue.get(i); + updateResourceTypes(mapExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(mapExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(mapExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(mapExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(mapExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(mapExp, pair, expToPair, updateFromPair); + updateMapTypes(mapExp, map, expToMap, updateFromMap); + updateJsonTypes(mapExp, json, expToJson, updateFromJson); + } + } + if (updateFromJson.size() > 0) { + Set jsonKeys = updateFromJson.keySet(); + Integer jsonKey = jsonKeys.iterator().next(); + Map jsonValue = updateFromJson.get(jsonKey); + updateFromJson.remove(jsonKey); + for (int i : jsonValue.keySet()) { + Expression jsonExp = jsonValue.get(i); + updateResourceTypes(jsonExp, resources, expToResource, updateFromResource, updateFromResourceOwnership); + updateVaribleTypes(jsonExp, variables, expToVariable, updateFromVariable); + updateMessageTypes(jsonExp, messages, expToMessage, updateFromMessage); + updateConsOrSetTypes(jsonExp, consOrSet, expToConsOrSet, updateFromConsOrSet); + updateTupleTypes(jsonExp, tuple, expToTuple, updateFromTuple); + updatePairTypes(jsonExp, pair, expToPair, updateFromPair); + updateMapTypes(jsonExp, map, expToMap, updateFromMap); + updateJsonTypes(jsonExp, json, expToJson, updateFromJson); + } + } + if (updateFromResourceOwnership.size() > 0) { + ResourceHierarchy res = updateFromResourceOwnership.iterator().next(); + updateFromResourceOwnership.remove(res); + updateResourceOwnershipTypes(res, resources, expToResource, updateFromResource, updateFromResourceOwnership); + } + } + } + + private void updateExpressionBelonging(Map>> belonging, Expression exp, List group) { + Set> groups = belonging.get(System.identityHashCode(exp)); + if (groups == null) { + groups = new HashSet<>(); + belonging.put(System.identityHashCode(exp), groups); + groups.add(group); + return; + } + if (!groups.contains(group)) { + groups.add(group); + } + } + + private void updateResourceTypes(Expression exp, Map> resources, Map> expToResource, + Map> updateFromResource, Set updateFromResourceOwnership) { + List identicalResources = expToResource.get(System.identityHashCode(exp)); + if (identicalResources == null) return; + for (ResourceHierarchy res: resources.keySet()) { + if (resources.get(res) == identicalResources) { + Type resType = res.getResourceStateType(); + Type newResType = getExpTypeIfUpdatable(resType, exp); + if (newResType != null) { + res.setResourceStateType(newResType); + updateFromResourceOwnership.add(res); // To update parent and children resources + // Update identical resources + Map updateExps = getUpdateSet(updateFromResource, identicalResources); + for (Expression resExp : identicalResources) { + if (resExp != exp) { + if (resExp instanceof Variable) { + ((Variable) resExp).setType(newResType); + updateExps.put(System.identityHashCode(resExp), resExp); + } else if (resExp instanceof Term) { + ((Term) resExp).setType(newResType); + updateExps.put(System.identityHashCode(resExp), resExp); + } + } + } + } + } + } + } + + private void updateResourcePathParamsTypes(Expression exp, Map> resourcePathParams, Set updateFromResourceOwnership) { + for (ResourceHierarchy parent: resourcePathParams.keySet()) { + List pathParams = resourcePathParams.get(parent); + if (pathParams.contains(exp)) { + Type parentType = parent.getResourceStateType(); + Type paramType = null; + if (exp instanceof Variable) { + paramType = ((Variable) exp).getType(); + } else if (exp instanceof Term) { + paramType = ((Term) exp).getType(); + } + if (paramType != null && parentType == null) { + if (paramType.equals(DataConstraintModel.typeString)) { + parentType = DataConstraintModel.typeMap; + } else if (paramType.equals(DataConstraintModel.typeInt)) { + parentType = DataConstraintModel.typeList; + } + if (parentType != null) { + parent.setResourceStateType(parentType); + updateFromResourceOwnership.add(parent); + } + } + } + } + } + + private void updateResourceOwnershipTypes(ResourceHierarchy res, Map> resources, + Map> expToResource, Map> updateFromResource, Set updateFromResourceOwnership) { + for (ResourceHierarchy parent: resources.keySet()) { + Type resType = res.getResourceStateType(); + Set children = parent.getChildren(); + if (res.equals(parent)) { + // Propagate an update of a parent resource type to its children' types. + if (DataConstraintModel.typeList.isAncestorOf(resType)) { + Type newElementType = listComponentTypes.get(resType); + if (newElementType != null && children != null && children.size() == 1) { + ResourceHierarchy element = children.iterator().next(); + Type elementType = element.getResourceStateType(); + if (compareTypes(elementType, newElementType)) { + element.setResourceStateType(newElementType); + updateFromResourceOwnership.add(element); + } + } + } else if (DataConstraintModel.typeMap.isAncestorOf(resType)) { + List newComponentTypes = mapComponentTypes.get(resType); + if (newComponentTypes != null && newComponentTypes.size() == 2 && children != null && children.size() == 1) { + ResourceHierarchy value = children.iterator().next(); + Type valueType = value.getResourceStateType(); + if (compareTypes(valueType, newComponentTypes.get(1))) { + value.setResourceStateType(newComponentTypes.get(1)); + updateFromResourceOwnership.add(value); + } + } + } else if (DataConstraintModel.typeJson.isAncestorOf(resType)) { + Map newMemberTypes = jsonMemberTypes.get(resType); + if (newMemberTypes != null && newMemberTypes.size() > 0 && children != null && children.size() > 0) { + for (ResourceHierarchy chlid: children) { + String key = chlid.getResourceName(); + Type memberType = chlid.getResourceStateType(); + if (compareTypes(memberType, newMemberTypes.get(key))) { + chlid.setResourceStateType(newMemberTypes.get(key)); + updateFromResourceOwnership.add(chlid); + } + } + } + } + } + if (children.contains(res)) { + // Propagate an update of a child resource type to its parent's type. + Type parentType = parent.getResourceStateType(); + if (parentType != null && DataConstraintModel.typeList.isAncestorOf(parentType)) { + Type oldElementType = listComponentTypes.get(parentType); + if (compareTypes(oldElementType, resType)) { + Type newListType = listTypes.get(resType); + if (newListType == null) { + newListType = createNewListType(resType, parentType); + } + if (newListType != null) { + parent.setResourceStateType(newListType); + updateFromResourceOwnership.add(parent); + } + } + } else if (parentType != null && DataConstraintModel.typeMap.isAncestorOf(parentType)) { + List oldComponentTypes = mapComponentTypes.get(parentType); + if (compareTypes(oldComponentTypes.get(1), resType)) { + List newComponentTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, resType}); + Type newMapType = mapTypes.get(newComponentTypes); + if (newMapType == null) { + newMapType = createNewMapType(newComponentTypes, parentType); + } + if (newMapType != null) { + parent.setResourceStateType(newMapType); + updateFromResourceOwnership.add(parent); + } + } + } else if (parentType != null && DataConstraintModel.typeJson.isAncestorOf(parentType)) { + Map oldMemberTypes = jsonMemberTypes.get(parentType); + String key= res.getResourceName(); + if (oldMemberTypes == null || compareTypes(oldMemberTypes.get(key), resType)) { + Map newMemberTypes = new HashMap<>(); + if (oldMemberTypes != null) newMemberTypes.putAll(oldMemberTypes); + newMemberTypes.put(key, resType); + Type newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + newJsonType = createNewJsonType(newMemberTypes, parentType); + } + if (newJsonType != null) { + parent.setResourceStateType(newJsonType); + updateFromResourceOwnership.add(parent); + } + } + } + } + } + // Propagate an update of the resource to its expressions. + List identicalResources = resources.get(res); + if (identicalResources != null) { + Type newResType = res.getResourceStateType(); + for (Expression resExp: identicalResources) { + Type resType = null; + if (resExp instanceof Variable) { + resType = ((Variable) resExp).getType(); + } else if (resExp instanceof Term) { + resType = ((Term) resExp).getType(); + } + if (resType == null || compareTypes(resType, newResType)) { + Map updateExps = getUpdateSet(updateFromResource, identicalResources); + if (resExp instanceof Variable) { + ((Variable) resExp).setType(newResType); + updateExps.put(System.identityHashCode(resExp), resExp); + } else if (resExp instanceof Term) { + ((Term) resExp).setType(newResType); + updateExps.put(System.identityHashCode(resExp), resExp); + } + } + } + } + } + + private void updateVaribleTypes(Expression exp, Map variables, + Map> expToVariable, Map> updateFromVariable) { + List sameVariable = expToVariable.get(System.identityHashCode(exp)); + if (sameVariable == null) return; + Type varType = variables.get(System.identityHashCode(sameVariable)); + Type newVarType = getExpTypeIfUpdatable(varType, exp); + if (newVarType != null) { + variables.put(System.identityHashCode(sameVariable), newVarType); + Map updateVars = getUpdateSet(updateFromVariable, sameVariable); + for (Expression v : sameVariable) { + if (v != exp) { + if (v instanceof Variable) { + ((Variable) v).setType(newVarType); + updateVars.put(System.identityHashCode(v), v); + } else if (v instanceof Term) { + ((Term) v).setType(newVarType); + updateVars.put(System.identityHashCode(v), v); + } + } + } + } 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); + } + } + } + } + } + + private void updateMessageTypes(Expression exp, + Map, Type>>> messages, + Map> expToMessage, Map> updateFromMessage) { + List messageExps = expToMessage.get(System.identityHashCode(exp)); + if (messageExps == null) return; + Type msgType = null; + Map.Entry, Type> expsAndType = null; + for (Channel c : messages.keySet()) { + for (int i : messages.get(c).keySet()) { + expsAndType = messages.get(c).get(i); + if (expsAndType.getKey() == messageExps) { + msgType = expsAndType.getValue(); + break; + } + } + if (msgType != null) break; + } + if (msgType == null) return; + Type newMsgType = getExpTypeIfUpdatable(msgType, exp); + if (newMsgType != null) { + expsAndType.setValue(newMsgType); + Map updateExps = getUpdateSet(updateFromMessage, messageExps); + for (Expression e : messageExps) { + if (e != exp) { + if (e instanceof Variable) { + ((Variable) e).setType(newMsgType); + updateExps.put(System.identityHashCode(e), e); + } else if (e instanceof Term) { + ((Term) e).setType(newMsgType); + updateExps.put(System.identityHashCode(e), e); + } + } + } + } + } + + private void updateConsOrSetTypes(Expression exp, Map consOrSet, + Map>> expToConsOrSet, Map> updateFromConsOrSet) { + Set> consComponentGroups = expToConsOrSet.get(System.identityHashCode(exp)); + if (consComponentGroups == null) return; + for (List consOrSetComponentGroup: consComponentGroups) { + int idx = consOrSetComponentGroup.indexOf(exp); + switch (idx) { + case 0: + // exp is a list itself. + if (!(exp instanceof Term)) break; + Type listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); + Type expType = getExpTypeIfUpdatable(listType, exp); + if (expType != null) { + consOrSet.put(System.identityHashCode(consOrSetComponentGroup), expType); + Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); + if (consOrSetComponentGroup.get(2) instanceof Variable) { + ((Variable) consOrSetComponentGroup.get(2)).setType(expType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); + } else if (consOrSetComponentGroup.get(2) instanceof Term) { + ((Term) consOrSetComponentGroup.get(2)).setType(expType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); + } + Type compType = listComponentTypes.get(expType); + if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Variable) { + ((Variable) consOrSetComponentGroup.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); + } else if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Term) { + ((Term) consOrSetComponentGroup.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); + } + } + break; + case 1: + // exp is a list's component. + listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); + Type compType = listComponentTypes.get(listType); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + Type newListType = listTypes.get(newCompType); + if (newListType == null) { + // Create new list type. + newListType = createNewListType(newCompType, listType); + } + consOrSet.put(System.identityHashCode(consOrSetComponentGroup), newListType); + Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); + if (consOrSetComponentGroup.get(0) instanceof Term) { + ((Term) consOrSetComponentGroup.get(0)).setType(newListType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(0)), consOrSetComponentGroup.get(0)); + } + if (consOrSetComponentGroup.get(2) instanceof Variable) { + ((Variable) consOrSetComponentGroup.get(2)).setType(newListType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); + } else if (consOrSetComponentGroup.get(2) instanceof Term) { + ((Term) consOrSetComponentGroup.get(2)).setType(newListType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(2)), consOrSetComponentGroup.get(2)); + } + } + break; + case 2: + // exp is a list itself. + listType = consOrSet.get(System.identityHashCode(consOrSetComponentGroup)); + expType = getExpTypeIfUpdatable(listType, exp); + if (expType != null) { + consOrSet.put(System.identityHashCode(consOrSetComponentGroup), expType); + Map updateExps = getUpdateSet(updateFromConsOrSet, consOrSetComponentGroup); + if (consOrSetComponentGroup.get(0) instanceof Term) { + ((Term) consOrSetComponentGroup.get(0)).setType(expType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(0)), consOrSetComponentGroup.get(0)); + } + compType = listComponentTypes.get(expType); + if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Variable) { + ((Variable) consOrSetComponentGroup.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); + } else if (consOrSetComponentGroup.get(1) != null && consOrSetComponentGroup.get(1) instanceof Term) { + ((Term) consOrSetComponentGroup.get(1)).setType(compType); + updateExps.put(System.identityHashCode(consOrSetComponentGroup.get(1)), consOrSetComponentGroup.get(1)); + } + } + } + } + } + + private void updateTupleTypes(Expression exp, Map tuple, + Map>> expToTuple, Map> updateFromTuple) { + Set> tupleComponentGroups = expToTuple.get(System.identityHashCode(exp)); + if (tupleComponentGroups == null) return; + for (List tupleComponentGroup: tupleComponentGroups) { + int idx = tupleComponentGroup.indexOf(exp); + if (idx == 0) { + // exp is a tuple itself. + Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); + Type newTupleType = getExpTypeIfUpdatable(tupleType, exp); + if (newTupleType != null) { + // Propagate an update of a tuple's type to its components' types. + tuple.put(System.identityHashCode(tupleComponentGroup), newTupleType); + List componentTypes = tupleComponentTypes.get(newTupleType); + Map updateExps = getUpdateSet(updateFromTuple, tupleComponentGroup); + for (int i = 1; i < tupleComponentGroup.size(); i++) { + Expression compExp = tupleComponentGroup.get(i); + if (compExp instanceof Variable) { + 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) { + 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); + } + } + } + } + } + } + } else { + // exp is a tuple's component. + Type tupleType = tuple.get(System.identityHashCode(tupleComponentGroup)); + List componentTypes = tupleComponentTypes.get(tupleType); + 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. + Type newTupleType = tupleTypes.get(componentTypes); + if (newTupleType == null) { + // Create new tuple type; + newTupleType = createNewTupleType(componentTypes, tupleType); + } + Map updateExps = getUpdateSet(updateFromTuple, tupleComponentGroup); + Expression tupleExp = tupleComponentGroup.get(0); + if (tupleExp instanceof Variable) { + ((Variable) tupleExp).setType(newTupleType); + updateExps.put(System.identityHashCode(tupleExp), tupleExp); + } else if (tupleExp instanceof Term) { + ((Term) tupleExp).setType(newTupleType); + updateExps.put(System.identityHashCode(tupleExp), tupleExp); + } + tuple.put(System.identityHashCode(tupleComponentGroup), newTupleType); + } + } + } + } + + private void updatePairTypes(Expression exp, Map pair, + Map>> expToPair, Map> updateFromPair) { + Set> pairComponentGroups = expToPair.get(System.identityHashCode(exp)); + if (pairComponentGroups == null) return; + for (List pairComponentGroup: pairComponentGroups) { + int idx = pairComponentGroup.indexOf(exp); + if (idx == 0) { + // exp is a pair itself. + Type pairType = pair.get(System.identityHashCode(pairComponentGroup)); + Type newPairType = getExpTypeIfUpdatable(pairType, exp); + if (newPairType != null) { + // Propagate an update of a pair's type to its components' types. + pair.put(System.identityHashCode(pairComponentGroup), newPairType); + Type componentType = pairComponentTypes.get(newPairType); + Map updateExps = getUpdateSet(updateFromPair, pairComponentGroup); + for (int i = 1; i < pairComponentGroup.size(); i++) { + Expression compExp = pairComponentGroup.get(i); + if (compExp instanceof Variable) { + if (compareTypes(((Variable) compExp).getType(), componentType)) { + ((Variable) compExp).setType(componentType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else if (compExp instanceof Term) { + if (compareTypes(((Term) compExp).getType(), componentType)) { + ((Term) compExp).setType(componentType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } + } + } + } else { + // exp is a pair's component. + Type pairType = pair.get(System.identityHashCode(pairComponentGroup)); + Type compType = pairComponentTypes.get(pairType); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + // Propagate an update of a component's type to its container's (pair's) type. + Type newPairType = pairTypes.get(compType); + if (newPairType != null) { + Map updateExps = getUpdateSet(updateFromPair, pairComponentGroup); + Expression pairExp = pairComponentGroup.get(0); + if (pairExp instanceof Variable) { + ((Variable) pairExp).setType(newPairType); + updateExps.put(System.identityHashCode(pairExp), pairExp); + } else if (pairExp instanceof Term) { + ((Term) pairExp).setType(newPairType); + updateExps.put(System.identityHashCode(pairExp), pairExp); + } + pair.put(System.identityHashCode(pairComponentGroup), newPairType); + } + } + } + } + } + + private void updateMapTypes(Expression exp, Map map, + Map>> expToMap, Map> updateFromMap) { + Set> mapComponentGroups = expToMap.get(System.identityHashCode(exp)); + if (mapComponentGroups == null) return; + for (List mapComponentGroup: mapComponentGroups) { + int idx = mapComponentGroup.indexOf(exp); + if (idx == 0 || idx == 3) { + // exp is a map itself. + Type mapType = map.get(System.identityHashCode(mapComponentGroup)); + Type newMapType = getExpTypeIfUpdatable(mapType, exp); + if (newMapType != null) { + // Propagate an update of a map's type to its components' types. + map.put(System.identityHashCode(mapComponentGroup), newMapType); + List componentTypes = mapComponentTypes.get(newMapType); + Map updateExps = getUpdateSet(updateFromMap, mapComponentGroup); + for (int i = 1; i < mapComponentGroup.size() && i < 3; i++) { + Expression compExp = mapComponentGroup.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); + } + } 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); + } + } + } + // Propagate an update of a map's type to another map's type. + Expression compExp = null; + if (idx == 0 && mapComponentGroup.size() == 4) { // for insert + compExp = mapComponentGroup.get(3); + } else if (idx == 3) { + compExp = mapComponentGroup.get(0); + } + if (compExp != null) { + if (compExp instanceof Variable) { + if (compareTypes(((Variable) compExp).getType(), newMapType)) { + ((Variable) compExp).setType(newMapType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } else if (compExp instanceof Term) { + if (compareTypes(((Term) compExp).getType(), newMapType)) { + ((Term) compExp).setType(newMapType); + updateExps.put(System.identityHashCode(compExp), compExp); + } + } + } + } + } else { + // exp is a map's key or value. + Type mapType = map.get(System.identityHashCode(mapComponentGroup)); + List componentTypes = mapComponentTypes.get(mapType); + Type compType = componentTypes.get(idx - 1); + Type newCompType = getExpTypeIfUpdatable(compType, exp); + if (newCompType != null) { + // Propagate an update of a component's type to its container's (map's) type. + componentTypes = new ArrayList<>(componentTypes); + componentTypes.set(idx - 1, newCompType); + Type newMapType = mapTypes.get(componentTypes); + if (newMapType == null) { + // Create new map type; + newMapType = createNewMapType(componentTypes, mapType); + } + Map updateExps = getUpdateSet(updateFromMap, mapComponentGroup); + Expression mapExp = mapComponentGroup.get(0); + if (mapExp instanceof Variable) { + ((Variable) mapExp).setType(newMapType); + updateExps.put(System.identityHashCode(mapExp), mapExp); + } else if (mapExp instanceof Term) { + ((Term) mapExp).setType(newMapType); + updateExps.put(System.identityHashCode(mapExp), mapExp); + } + if (mapComponentGroup.size() == 4) { // for insert + mapExp = mapComponentGroup.get(3); + if (mapExp instanceof Variable) { + ((Variable) mapExp).setType(newMapType); + updateExps.put(System.identityHashCode(mapExp), mapExp); + } else if (mapExp instanceof Term) { + ((Term) mapExp).setType(newMapType); + updateExps.put(System.identityHashCode(mapExp), mapExp); + } + } + map.put(System.identityHashCode(mapComponentGroup), newMapType); + } + } + } + } + + + private void updateJsonTypes(Expression exp, Map json, + Map>> expToJson, Map> updateFromJson) { + Set> jsonMemberGroups = expToJson.get(System.identityHashCode(exp)); + if (jsonMemberGroups == null) return; + for (List jsonMemberGroup: jsonMemberGroups) { + int idx = jsonMemberGroup.indexOf(exp); + if (idx == 3) { + // exp is a json argument (0:t = addMember(3:json, 1:key, 2:value)). + Type jsonType = json.get(System.identityHashCode(jsonMemberGroup)); + if (jsonType != null && jsonMemberTypes.get(jsonType) != null) { + Map memberTypes = new HashMap<>(jsonMemberTypes.get(jsonType)); + Map argMemberTypes = new HashMap<>(memberTypes); + String keyName = null; + Type valueType = null; + if (jsonMemberGroup.get(1) instanceof Constant) { + keyName = ((Constant) jsonMemberGroup.get(1)).getSymbol().getName(); + valueType = ((Constant) jsonMemberGroup.get(1)).getType(); + argMemberTypes.remove(keyName); + } + Type jsonArgType = jsonTypes.get(argMemberTypes); + Type newJsonArgType = getExpTypeIfUpdatable(jsonArgType, exp); + if (newJsonArgType != null && keyName != null) { + // Propagate an update of a json arg's type to its container's (json's) type. + argMemberTypes = ((JsonType) newJsonArgType).getMemberTypes(); + argMemberTypes.put(keyName, valueType); + memberTypes.putAll(argMemberTypes); + Type newJsonType = jsonTypes.get(memberTypes); + if (newJsonType == null) { + // Create new json type. + newJsonType = createNewJsonType(memberTypes, jsonType); + } + // Update the type of the json term and record the updated expression. + Map updateExps = getUpdateSet(updateFromJson, jsonMemberGroup); + Expression jsonExp = jsonMemberGroup.get(0); + if (jsonExp instanceof Variable) { + ((Variable) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } else if (jsonExp instanceof Term) { + ((Term) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } + json.put(System.identityHashCode(jsonMemberGroup), newJsonType); + } + } + } else if (idx == 2) { + // exp is a value (0:t = addMember(3:json, 1:key, 2:value) or 2:value = dot(0:list/map, 1:key)). + Type jsonType = json.get(System.identityHashCode(jsonMemberGroup)); + Type newJsonType = null; + if (exp instanceof Term && ((Term) exp).getSymbol().equals(DataConstraintModel.dotParam)) { + if (DataConstraintModel.typeList.isAncestorOf(jsonType)) { + Type elementType = listComponentTypes.get(jsonType); + Type newElementType = getExpTypeIfUpdatable(elementType, exp); + if (newElementType != null) { + // Propagate an update of a member's type to its container's (json's) type. + newJsonType = listTypes.get(newElementType); + if (newJsonType == null) { + // Create new json type. + newJsonType = createNewListType(newElementType, jsonType); + } + } + } else if (DataConstraintModel.typeMap.isAncestorOf(jsonType)) { + List keyValueTypes = mapComponentTypes.get(jsonType); + Type newValueType = getExpTypeIfUpdatable(keyValueTypes.get(1), exp); + if (newValueType != null) { + // Propagate an update of a member's type to its container's (json's) type. + List newKeyValueTypes = Arrays.asList(new Type[] {DataConstraintModel.typeString, newValueType}); + newJsonType = mapTypes.get(newKeyValueTypes); + if (newJsonType == null) { + // Create new json type. + newJsonType = createNewMapType(newKeyValueTypes, jsonType); + } + } + } + } else { + Map memberTypes = jsonMemberTypes.get(jsonType); + String keyName = null; + if (jsonMemberGroup.get(1) instanceof Constant) { + keyName = ((Constant) jsonMemberGroup.get(1)).getSymbol().getName(); + } + if (memberTypes != null) { + Type memberType = memberTypes.get(keyName); + Type newMemberType = getExpTypeIfUpdatable(memberType, exp); + if (newMemberType != null && keyName != null) { + // Propagate an update of a member's type to its container's (json's) type. + Map newMemberTypes = new HashMap<>(memberTypes); + newMemberTypes.put(keyName, newMemberType); + newJsonType = jsonTypes.get(newMemberTypes); + if (newJsonType == null) { + // Create new json type. + newJsonType = createNewJsonType(newMemberTypes, jsonType); + } + } + } + } + if (newJsonType != null) { + // Update the type of the json term and record the updated expression. + Map updateExps = getUpdateSet(updateFromJson, jsonMemberGroup); + Expression jsonExp = jsonMemberGroup.get(0); + if (jsonExp instanceof Variable) { + ((Variable) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } else if (jsonExp instanceof Term) { + ((Term) jsonExp).setType(newJsonType); + updateExps.put(System.identityHashCode(jsonExp), jsonExp); + } + json.put(System.identityHashCode(jsonMemberGroup), newJsonType); + } + } + } + } + + private ListType createNewListType(Type compType, Type parentType) { + List childrenTypes = getChildrenTypes(parentType, listComponentTypes.keySet()); + ListType newListType = langSpec.newListType(compType, parentType); + listTypes.put(compType, newListType); + listComponentTypes.put(newListType, compType); + for (Type childType : childrenTypes) { + if (compareTypes(childType, newListType)) { + if (newListType.getParentTypes().contains(parentType)) { + newListType.replaceParentType(parentType, childType); + } else { + newListType.addParentType(childType); + } + } else if (compareTypes(newListType, childType)) { + childType.replaceParentType(parentType, newListType); + } + } + return newListType; + } + + private MapType createNewMapType(List componentTypes, Type parentMapType) { + List childrenTypes = getChildrenTypes(parentMapType, mapComponentTypes.keySet()); + MapType newMapType = langSpec.newMapType(componentTypes.get(0), componentTypes.get(1), parentMapType); + mapTypes.put(componentTypes, newMapType); + mapComponentTypes.put(newMapType, componentTypes); + for (Type childType : childrenTypes) { + if (compareTypes(childType, newMapType)) { + if (newMapType.getParentTypes().contains(parentMapType)) { + newMapType.replaceParentType(parentMapType, childType); + } else { + newMapType.addParentType(childType); + } + } else if (compareTypes(newMapType, childType)) { + childType.replaceParentType(parentMapType, newMapType); + } + } + return newMapType; + } + + private TupleType createNewTupleType(List componentTypes, Type parentTupleType) { + List childrenTypes = getChildrenTypes(parentTupleType, tupleComponentTypes.keySet()); + TupleType newTupleType = langSpec.newTupleType(componentTypes, parentTupleType); + tupleTypes.put(componentTypes, newTupleType); + tupleComponentTypes.put(newTupleType, componentTypes); + for (Type childType : childrenTypes) { + if (compareTypes(childType, newTupleType)) { + if (newTupleType.getParentTypes().contains(parentTupleType)) { + newTupleType.replaceParentType(parentTupleType, childType); + } else { + newTupleType.addParentType(childType); + } + } else if (compareTypes(newTupleType, childType)) { + childType.replaceParentType(parentTupleType, newTupleType); + } + } + return newTupleType; + } + + private JsonType createNewJsonType(Map memberTypes, Type parentJsonType) { + List childrenTypes = getChildrenTypes(parentJsonType, jsonMemberTypes.keySet()); + JsonType newJsonType = langSpec.newJsonType(parentJsonType); + for (String key: memberTypes.keySet()) { + newJsonType.addMemberType(key, memberTypes.get(key)); + } + jsonTypes.put(memberTypes, newJsonType); + jsonMemberTypes.put(newJsonType, memberTypes); + for (Type childType : childrenTypes) { + if (compareTypes(childType, newJsonType)) { + if (newJsonType.getParentTypes().contains(parentJsonType)) { + newJsonType.replaceParentType(parentJsonType, childType); + } else { + newJsonType.addParentType(childType); + } + } else if (compareTypes(newJsonType, childType)) { + childType.replaceParentType(parentJsonType, newJsonType); + } + } + return newJsonType; + } + + /** + * Get children types of a given type from given set of types. + * @param parentType a type + * @param allTypes set of types + * @return list of the children types + */ + private List getChildrenTypes(Type parentType, Set allTypes) { + List childrenTypes = new ArrayList<>(); + for (Type childType : allTypes) { + if (childType.getParentTypes().contains(parentType)) { + childrenTypes.add(childType); + } + } + return childrenTypes; + } + + private String getImplementationTypeName(Type type) { + if (type == null) + return "Object"; + String wrapperType = DataConstraintModel.getWrapperType(type); + if (wrapperType != null) + return wrapperType; + return type.getImplementationTypeName(); + } + + private String getInterfaceTypeName(Type type) { + if (type == null) + return "Object"; + String wrapperType = DataConstraintModel.getWrapperType(type); + if (wrapperType != null) + return wrapperType; + return type.getInterfaceTypeName(); + } + + private > Map getUpdateSet(Map> updateSets, U keySet) { + Map updatedExps = updateSets.get(System.identityHashCode(keySet)); + if (updatedExps == null) { + updatedExps = new HashMap<>(); + updateSets.put(System.identityHashCode(keySet), updatedExps); + } + return updatedExps; + } + + private Type getExpTypeIfUpdatable(Type originalType, Expression newExp) { + Type expType = null; + if (newExp instanceof Term) { + expType = ((Term) newExp).getType(); + } else if (newExp instanceof Variable) { + expType = ((Variable) newExp).getType(); + } + if (compareTypes(originalType, expType)) { + return expType; + } + return null; + } + + /** + * Is an given original type an ancestor of a given new type? + * + * @param originalType original type + * @param newType new type (may not have been registered) + * @return true: if the original type equals to the new type or is an ancestor + * of the new type, false: otherwise + */ + private boolean compareTypes(Type originalType, Type newType) { + if (originalType == null) return true; + if (originalType != newType && newType != null) { + 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; + 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; + } + return true; + } + if (DataConstraintModel.typeTuple.isAncestorOf(originalType) + && DataConstraintModel.typeTuple.isAncestorOf(newType)) { + List originalCompTypes = tupleComponentTypes.get(originalType); + List newCompTypes = tupleComponentTypes.get(newType); + 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) { + if (DataConstraintModel.typeTuple.isAncestorOf(originalCompTypes.get(i))) { + // Unfold the nested tuple's types. + 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))) { + // Unfold the nested tuple's types. + 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; + } + if (DataConstraintModel.typeList.isAncestorOf(originalType) + && DataConstraintModel.typeList.isAncestorOf(newType)) { + Type originalCompType = listComponentTypes.get(originalType); + Type newCompType = listComponentTypes.get(newType); + if (originalCompType != null && (newCompType == null || !originalCompType.isAncestorOf(newCompType))) return false; + return true; + } + if (DataConstraintModel.typeJson.isAncestorOf(originalType) && DataConstraintModel.typeJson.isAncestorOf(newType)) { + Map originalMemberTypes = jsonMemberTypes.get(originalType); + Map newMemberTypes = jsonMemberTypes.get(newType); + if (originalMemberTypes == null) return true; + if (originalMemberTypes.keySet().size() < newMemberTypes.keySet().size() + && newMemberTypes.keySet().containsAll(originalMemberTypes.keySet())) return true; + if (originalMemberTypes.keySet().size() > newMemberTypes.keySet().size()) return false; + if (!newMemberTypes.keySet().containsAll(originalMemberTypes.keySet())) return false; + for (String key: originalMemberTypes.keySet()) { + if (!originalMemberTypes.get(key).isAncestorOf(newMemberTypes.get(key))) return false; + } + return true; + } + } + return false; + } + + private interface IGroupExpressionsByResource { + public void groupForChannel(Channel ch); + } + + private interface IGroupExpressionsByVariable { + public void groupForChannel(Channel ch); + } + + private interface IGroupExpressionsByMessage { + public void groupForChannel(Channel rootCh, Channel ch); + } + + private static interface IExtractConstraintsOnExpressionsInTerm { + public void extractForChannel(Channel ch); + } + + private static interface IExtractConstraintsOnPathParametersAndResources { + public void extractForChannel(Channel ch); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java index b358747..7bae391 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Symbol.java @@ -2,107 +2,80 @@ import java.util.List; +import models.algebra.Symbol.IImplGenerator; +import models.algebra.Symbol.Type; + public class Symbol { protected String name; - protected String implName; protected int arity = 0; // -1: variable number protected Type operatorType = Type.PREFIX; - protected Type implOperatorType = Type.PREFIX; protected Symbol[] inverses = null; protected models.algebra.Type[] signature = null; - protected int[] implParamOrder = null; - protected IImplGenerator generator = null; protected ICalculator calculator = null; + protected SymbolImpl symbolImpl = null; public Symbol(String name) { this.name = name; - this.implName = name; this.arity = 0; + this.symbolImpl = new SymbolImpl(name); } public Symbol(String name, int arity) { this.name = name; - this.implName = name; this.arity = arity; + this.symbolImpl = new SymbolImpl(name, arity); } public Symbol(String name, int arity, Type operatorType) { - this(name, arity); + this.name = name; + this.arity = arity; this.operatorType = operatorType; - this.implOperatorType = operatorType; + this.symbolImpl = new SymbolImpl(name, arity, operatorType); } public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType) { this.name = name; - this.implName = implName; this.arity = arity; this.operatorType = operatorType; - this.implOperatorType = implOperatorType; + this.symbolImpl = new SymbolImpl(implName, arity, implOperatorType); } public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType, int[] implParamOrder) { - this.name = name; - this.implName = implName; - this.arity = arity; - this.operatorType = operatorType; - this.implOperatorType = implOperatorType; - this.implParamOrder = implParamOrder; + this(name, arity, operatorType, implName, implOperatorType); + this.symbolImpl.setImplParamOrder(implParamOrder); } public Symbol(String name, int arity, Type operatorType, IImplGenerator generator) { - this.name = name; - this.implName = name; - this.arity = arity; - this.operatorType = operatorType; - this.generator = generator; - this.implOperatorType = Type.GENERATIVE; + this(name, arity, operatorType, name, Type.GENERATIVE); + this.symbolImpl.setGenerator(generator); } public Symbol(String name, int arity, Type operatorType, IImplGenerator generator, boolean bSideEffect) { - this.name = name; - this.implName = name; - this.arity = arity; - this.operatorType = operatorType; - this.generator = generator; - if (!bSideEffect) { - this.implOperatorType = Type.GENERATIVE; - } else { - this.implOperatorType = Type.GENERATIVE_WITH_SIDE_EFFECT; + this(name, arity, operatorType, name, Type.GENERATIVE); + this.symbolImpl.setGenerator(generator); + if (bSideEffect) { + this.symbolImpl.setImplOperatorType(Type.GENERATIVE_WITH_SIDE_EFFECT); } } public Symbol(String name, int arity, ICalculator calculator) { - this.name = name; - this.implName = name; - this.arity = arity; + this(name, arity); this.calculator = calculator; } public Symbol(String name, int arity, Type operatorType, ICalculator calculator) { - this.name = name; - this.implName = name; - this.arity = arity; - this.operatorType = operatorType; - this.implOperatorType = operatorType; + this(name, arity, operatorType, name, operatorType); this.calculator = calculator; } public Symbol(String name, int arity, Type operatorType, IImplGenerator generator, ICalculator calculator) { - this.name = name; - this.implName = name; - this.arity = arity; - this.operatorType = operatorType; - this.generator = generator; - this.implOperatorType = Type.GENERATIVE; + this(name, arity, operatorType, name, Type.GENERATIVE); this.calculator = calculator; + this.symbolImpl.setGenerator(generator); } public Symbol(String name, int arity, Type operatorType, String implName, Type implOperatorType, ICalculator calculator) { - this.name = name; - this.implName = implName; - this.arity = arity; - this.operatorType = operatorType; - this.implOperatorType = implOperatorType; + this(name, arity, operatorType, implName, implOperatorType); this.calculator = calculator; } @@ -120,7 +93,7 @@ public void changeName(String name) { this.name = name; - this.implName = name; + this.symbolImpl.setImplName(name); } public Type getOperatorType() { @@ -156,49 +129,49 @@ } public String getImplName() { - return implName; + return symbolImpl.getImplName(); } public void setImplName(String implName) { - this.implName = implName; + this.symbolImpl.setImplName(implName); } public Type getImplOperatorType() { - return implOperatorType; + return symbolImpl.getImplOperatorType(); } public boolean isImplInfix() { - return (implOperatorType == Type.INFIX); + return (symbolImpl.getImplOperatorType() == Type.INFIX); } public boolean isImplMethod() { - return (implOperatorType == Type.METHOD || implOperatorType == Type.METHOD_WITH_SIDE_EFFECT); + return (symbolImpl.getImplOperatorType() == Type.METHOD || symbolImpl.getImplOperatorType() == Type.METHOD_WITH_SIDE_EFFECT); } public boolean isImplLambda() { - return (implOperatorType == Type.LAMBDA || implOperatorType == Type.LAMBDA_WITH_SIDE_EFFECT); + return (symbolImpl.getImplOperatorType() == Type.LAMBDA || symbolImpl.getImplOperatorType() == Type.LAMBDA_WITH_SIDE_EFFECT); } public boolean isImplGenerative() { - return (implOperatorType == Type.GENERATIVE || implOperatorType == Type.GENERATIVE_WITH_SIDE_EFFECT); + return (symbolImpl.getImplOperatorType() == Type.GENERATIVE || symbolImpl.getImplOperatorType() == Type.GENERATIVE_WITH_SIDE_EFFECT); } public boolean isImplWithSideEffect() { - return (implOperatorType == Type.METHOD_WITH_SIDE_EFFECT - || implOperatorType == Type.LAMBDA_WITH_SIDE_EFFECT - || implOperatorType == Type.GENERATIVE_WITH_SIDE_EFFECT); + return (symbolImpl.getImplOperatorType() == Type.METHOD_WITH_SIDE_EFFECT + || symbolImpl.getImplOperatorType() == Type.LAMBDA_WITH_SIDE_EFFECT + || symbolImpl.getImplOperatorType() == Type.GENERATIVE_WITH_SIDE_EFFECT); } public void setImplOperatorType(Type implOperatorType) { - this.implOperatorType = implOperatorType; + this.symbolImpl.setImplOperatorType(implOperatorType); } public int[] getImplParamOrder() { - return implParamOrder; + return symbolImpl.getImplParamOrder(); } public void setGenerator(IImplGenerator generator) { - this.generator = generator; + this.symbolImpl.setGenerator(generator); } /** @@ -211,8 +184,8 @@ * @return the implementation */ public String generate(models.algebra.Type type, models.algebra.Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { - if (generator != null) { - return generator.generate(type, childrenTypes, childrenImpl, childrenSideEffects, sideEffect); + if (symbolImpl.getGenerator() != null) { + return symbolImpl.getGenerator().generate(type, childrenTypes, childrenImpl, childrenSideEffects, sideEffect); } return null; } @@ -243,7 +216,7 @@ } public String toImplementation() { - return implName; + return symbolImpl.getImplName(); } public enum Type { @@ -257,13 +230,78 @@ GENERATIVE_WITH_SIDE_EFFECT } + public static class SymbolImpl { + private String implName; + protected int implArity = 0; // -1: variable number + private Type implOperatorType; + private int[] implParamOrder; + private IImplGenerator generator; + + public SymbolImpl(String implName) { + this.implName = implName; + this.implArity = 0; + } + + public SymbolImpl(String implName, int implArity) { + this.implName = implName; + this.implArity = implArity; + } + + public SymbolImpl(String implName, int implArity, Type implOperatorType) { + this(implName, implArity); + this.implOperatorType = implOperatorType; + } + + public SymbolImpl(String implName, int implArity, Type implOperatorType, int[] implParamOrder) { + this(implName, implArity, implOperatorType); + this.implParamOrder = implParamOrder; + } + + public SymbolImpl(String implName, int implArity, Type implOperatorType, int[] implParamOrder, IImplGenerator generator) { + this(implName, implArity, implOperatorType, implParamOrder); + this.generator = generator; + } + + public String getImplName() { + return implName; + } + + public void setImplName(String implName) { + this.implName = implName; + } + + public Type getImplOperatorType() { + return implOperatorType; + } + + public void setImplOperatorType(Type implOperatorType) { + this.implOperatorType = implOperatorType; + } + + public int[] getImplParamOrder() { + return implParamOrder; + } + + public void setImplParamOrder(int[] implParamOrder) { + this.implParamOrder = implParamOrder; + } + + public IImplGenerator getGenerator() { + return generator; + } + + public void setGenerator(IImplGenerator generator) { + this.generator = generator; + } + } + public Memento createMemento() { - return new Memento(implName, implOperatorType); + return new Memento(symbolImpl.getImplName(), symbolImpl.getImplOperatorType()); } public void setMemento(Memento memento) { - this.implName = memento.implName; - this.implOperatorType = memento.implOperatorType; + this.symbolImpl.setImplName(memento.implName); + this.symbolImpl.setImplOperatorType(memento.implOperatorType); } public static class Memento { diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java index 9e3eecb..d2c1780 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Type.java @@ -5,33 +5,35 @@ public class Type { private String typeName; - private String implementationTypeName; - private String interfaceTypeName; +// private String implementationTypeName; +// private String interfaceTypeName; private List parentTypes = new ArrayList<>(); + private ITypeImpl implementationType; + private ITypeImpl interfaceType; - public Type(String typeName, String implementationTypeName) { + public Type(String typeName, ITypeImpl implementationType) { this.typeName = typeName; - this.implementationTypeName = implementationTypeName; - this.interfaceTypeName = implementationTypeName; + this.implementationType = implementationType; + this.interfaceType = implementationType; } - public Type(String typeName, String implementationTypeName, String interfaceTypeName) { + public Type(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType) { this.typeName = typeName; - this.implementationTypeName = implementationTypeName; - this.interfaceTypeName = interfaceTypeName; + this.implementationType = implementationType; + this.interfaceType = interfaceType; } - public Type(String typeName, String implementationTypeName, Type parentType) { + public Type(String typeName, ITypeImpl implementationType, Type parentType) { this.typeName = typeName; - this.implementationTypeName = implementationTypeName; - this.interfaceTypeName = implementationTypeName; + this.implementationType = implementationType; + this.interfaceType = implementationType; this.parentTypes.add(parentType); } - public Type(String typeName, String implementationTypeName, String interfaceTypeName, Type parentType) { + public Type(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentType) { this.typeName = typeName; - this.implementationTypeName = implementationTypeName; - this.interfaceTypeName = interfaceTypeName; + this.implementationType = implementationType; + this.interfaceType = interfaceType; this.parentTypes.add(parentType); } @@ -43,20 +45,20 @@ this.typeName = typeName; } - public String getImplementationTypeName() { - return implementationTypeName; + public ITypeImpl getImplementationType() { + return implementationType; } - public void setImplementationTypeName(String implementastionTypeName) { - this.implementationTypeName = implementastionTypeName; + public String getImplementationTypeName() { + return implementationType.toString(); + } + + public ITypeImpl getInterfaceType() { + return interfaceType; } public String getInterfaceTypeName() { - return interfaceTypeName; - } - - public void setInterfaceTypeName(String interfaceTypeName) { - this.interfaceTypeName = interfaceTypeName; + return interfaceType.toString(); } public List getParentTypes() { @@ -95,29 +97,32 @@ if (another == null) return false; if (!(another instanceof Type)) return false; if (!typeName.equals(((Type) another).typeName)) return false; - if (!implementationTypeName.equals(((Type) another).implementationTypeName)) return false; - if (!interfaceTypeName.equals(((Type) another).interfaceTypeName)) return false; + if (!implementationType.equals(((Type) another).implementationType)) return false; + if (!interfaceType.equals(((Type) another).interfaceType)) return false; return true; } + + public interface ITypeImpl { + } public Memento createMemento() { - return new Memento(implementationTypeName, interfaceTypeName, parentTypes); + return new Memento(implementationType, interfaceType, parentTypes); } public void setMemento(Memento memento) { - this.implementationTypeName = memento.implementationTypeName; - this.interfaceTypeName = memento.interfaceTypeName; + this.implementationType = memento.implementationType; + this.interfaceType = memento.interfaceType; this.parentTypes = memento.parentTypes; } public static class Memento { - private String implementationTypeName; - private String interfaceTypeName; + private ITypeImpl implementationType; + private ITypeImpl interfaceType; private List parentTypes; - public Memento(String implementationTypeName, String interfaceTypeName, List parentTypes) { - this.implementationTypeName = implementationTypeName; - this.interfaceTypeName = interfaceTypeName; + public Memento(ITypeImpl implementationType, ITypeImpl interfaceType, List parentTypes) { + this.implementationType = implementationType; + this.interfaceType = interfaceType; this.parentTypes = parentTypes; } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index 04685d9..33be5cc 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java @@ -10,6 +10,7 @@ import java.util.Map; import java.util.Stack; +import generators.JavaSpecific; import models.algebra.Constant; import models.algebra.Expression; import models.algebra.LambdaAbstraction; @@ -26,12 +27,12 @@ protected HashMap inputChannels = null; protected HashMap types = null; protected HashMap symbols = null; - public static final Type typeInt = new Type("Int", "int"); - public static final Type typeLong = new Type("Long", "long", typeInt); - public static final Type typeFloat = new Type("Float", "float", typeInt); - public static final Type typeDouble = new Type("Double", "double", typeFloat); - public static final Type typeBoolean = new Type("Bool", "boolean"); - public static final Type typeString = new Type("Str", "String") { + public static final Type typeInt = new Type("Int", new code.ast.PrimitiveType("int")); + public static final Type typeLong = new Type("Long", new code.ast.PrimitiveType("long"), typeInt); + public static final Type typeFloat = new Type("Float", new code.ast.PrimitiveType("float"), typeInt); + public static final Type typeDouble = new Type("Double", new code.ast.PrimitiveType("double"), typeFloat); + public static final Type typeBoolean = new Type("Bool", new code.ast.PrimitiveType("boolean")); + public static final Type typeString = new Type("Str", JavaSpecific.typeString) { public String valueToRepresentation(Object value) { if (value instanceof String) { return Parser.DOUBLE_QUOT + (String) value + Parser.DOUBLE_QUOT; @@ -45,16 +46,16 @@ return representation; } }; - public static final Type typeList = new Type("List", "ArrayList", "List"); - public static final Type typeListInt = new Type("List", "ArrayList<>", "List", typeList); - public static final Type typeListStr = new Type("List", "ArrayList<>", "List", typeList); - public static final Type typeTuple = new Type("Tuple", "AbstractMap.SimpleEntry", "Map.Entry"); - public static final Type typePair = new Type("Pair", "Pair", "Pair"); - public static final Type typePairInt = new Type("Pair", "Pair", "Pair", typePair); - public static final Type typePairStr = new Type("Pair", "Pair", "Pair", typePair); - public static final Type typePairDouble = new Type("Pair", "Pair", "Pair", typePair); - public static final Type typeMap = new Type("Map", "HashMap<>", "Map"); - public static final JsonType typeJson = new JsonType("Json", "HashMap<>", "Map"); + public static final Type typeList = new Type("List", JavaSpecific.typeArrayList, JavaSpecific.typeList); + public static final Type typeListInt = new Type("List", new code.ast.ParameterizedType(JavaSpecific.typeArrayList), new code.ast.ParameterizedType(JavaSpecific.typeList, List.of(JavaSpecific.typeInteger)), typeList); + public static final Type typeListStr = new Type("List", new code.ast.ParameterizedType(JavaSpecific.typeArrayList), new code.ast.ParameterizedType(JavaSpecific.typeList, List.of(JavaSpecific.typeString)), typeList); + public static final Type typeTuple = new Type("Tuple", new code.ast.SimpleType("AbstractMap.SimpleEntry"), new code.ast.SimpleType("Map.Entry")); + public static final Type typePair = new Type("Pair", new code.ast.SimpleType("Pair"), new code.ast.SimpleType("Pair")); + public static final Type typePairInt = new Type("Pair", new code.ast.ParameterizedType(JavaSpecific.typePair), new code.ast.ParameterizedType(JavaSpecific.typePair, List.of(JavaSpecific.typeInteger)), typePair); + public static final Type typePairStr = new Type("Pair", new code.ast.ParameterizedType(JavaSpecific.typePair), new code.ast.ParameterizedType(JavaSpecific.typePair, List.of(JavaSpecific.typeString)), typePair); + public static final Type typePairDouble = new Type("Pair", new code.ast.ParameterizedType(JavaSpecific.typePair), new code.ast.ParameterizedType(JavaSpecific.typePair, List.of(JavaSpecific.typeDouble)), typePair); + public static final Type typeMap = new Type("Map", new code.ast.ParameterizedType(JavaSpecific.typeHashMap), JavaSpecific.typeMap); + public static final JsonType typeJson = new JsonType("Json", new code.ast.ParameterizedType(JavaSpecific.typeHashMap), new code.ast.ParameterizedType(JavaSpecific.typeMap, List.of(JavaSpecific.typeString, JavaSpecific.typeObject))); public static final Symbol add = new Symbol(Parser.ADD, 2, Symbol.Type.INFIX, new Symbol.ICalculator() { @Override public Expression calculate(List args) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java index 9f9e835..0e098bc 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonType.java @@ -7,27 +7,25 @@ import models.algebra.Type; public class JsonType extends Type { - protected boolean isListOrMap = false; protected Map memberTypes = null; - protected Type listOrMapElementType = null; - public JsonType(String typeName, String implementationTypeName) { - super(typeName, implementationTypeName); + public JsonType(String typeName, ITypeImpl implementationType) { + super(typeName, implementationType); memberTypes = new HashMap<>(); } - public JsonType(String typeName, String implementationTypeName, String interfaceTypeName) { - super(typeName, implementationTypeName, interfaceTypeName); + public JsonType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType) { + super(typeName, implementationType, interfaceType); memberTypes = new HashMap<>(); } - public JsonType(String typeName, String implementationTypeName, Type parentType) { - super(typeName, implementationTypeName, parentType); + public JsonType(String typeName, ITypeImpl implementationType, Type parentType) { + super(typeName, implementationType, parentType); memberTypes = new HashMap<>(); } - public JsonType(String typeName, String implementationTypeName, String interfaceTypeName, Type parentType) { - super(typeName, implementationTypeName, interfaceTypeName, parentType); + public JsonType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentType) { + super(typeName, implementationType, interfaceType, parentType); memberTypes = new HashMap<>(); } @@ -46,20 +44,4 @@ public void addMemberType(String key, Type valueType) { memberTypes.put(key, valueType); } - -// public boolean isListOrMap() { -// return isListOrMap; -// } -// -// public void setListOrMap(boolean isListOrMap) { -// this.isListOrMap = isListOrMap; -// } - - public Type getElementType() { - return listOrMapElementType; - } - - public void setElementType(Type listElementType) { - this.listOrMapElementType = listElementType; - } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListType.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListType.java new file mode 100644 index 0000000..35e6589 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ListType.java @@ -0,0 +1,32 @@ +package models.dataConstraintModel; + +import models.algebra.Type; + +public class ListType extends Type { + protected Type elementType = null; + + public ListType(String typeName, ITypeImpl implementationType) { + super(typeName, implementationType); + } + + public ListType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType) { + super(typeName, implementationType, interfaceType); + } + + public ListType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentListType) { + super(typeName, implementationType, interfaceType, parentListType); + } + + public ListType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentListType, Type elementType) { + super(typeName, implementationType, interfaceType, parentListType); + this.elementType = elementType; + } + + public Type getElementType() { + return elementType; + } + + public void setElementType(Type listElementType) { + this.elementType = listElementType; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapType.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapType.java new file mode 100644 index 0000000..b9f3233 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/MapType.java @@ -0,0 +1,49 @@ +package models.dataConstraintModel; + +import models.algebra.Type; + +public class MapType extends Type { + protected Type keyType = null; + protected Type valueType = null; + + public MapType(String typeName, ITypeImpl implementationType) { + super(typeName, implementationType); + } + + public MapType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType) { + super(typeName, implementationType, interfaceType); + } + + public MapType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentMapType) { + super(typeName, implementationType, interfaceType, parentMapType); + } + + public MapType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type keyType, Type valueType) { + super(typeName, implementationType, interfaceType); + this.keyType = keyType; + this.valueType = valueType; + } + + public MapType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentMapType, Type keyType, Type valueType) { + super(typeName, implementationType, interfaceType, parentMapType); + this.keyType = keyType; + this.valueType = valueType; + } + + public Type getKeyType() { + return keyType; + } + + public void setKeyType(Type keyType) { + this.keyType = keyType; + } + + public Type getValueType() { + return valueType; + } + + public void setValueType(Type valueType) { + this.valueType = valueType; + } + +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/PairType.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/PairType.java new file mode 100644 index 0000000..5e79573 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/PairType.java @@ -0,0 +1,19 @@ +package models.dataConstraintModel; + +import models.algebra.Type; + +public class PairType extends Type { + protected Type componentType = null; + + public PairType(String typeName, ITypeImpl implementationType) { + super(typeName, implementationType); + } + + public Type getComponentType() { + return componentType; + } + + public void setComponentType(Type pairComponentType) { + this.componentType = pairComponentType; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/TupleType.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/TupleType.java new file mode 100644 index 0000000..a0ed0aa --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/TupleType.java @@ -0,0 +1,44 @@ +package models.dataConstraintModel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import models.algebra.Type; + +public class TupleType extends Type { + protected List componentTypes; + + public TupleType(String typeName, ITypeImpl implementationType) { + super(typeName, implementationType); + this.componentTypes = new ArrayList<>(); + } + + public TupleType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType) { + super(typeName, implementationType, interfaceType); + this.componentTypes = new ArrayList<>(); + } + + public TupleType(String typeName, ITypeImpl implementationType, ITypeImpl interfaceType, Type parentTupleType) { + super(typeName, implementationType, interfaceType, parentTupleType); + this.componentTypes = new ArrayList<>(); + } + + public TupleType(String typeName, code.ast.Type implementationType, code.ast.Type interfaceType, Type parentTupleType, List componentTypes) { + super(typeName, implementationType, interfaceType, parentTupleType); + this.componentTypes = componentTypes; + } + + public List getComponentTypes() { + return componentTypes; + } + + public Type getComponentType(int idx) { + return componentTypes.get(idx); + } + + public void addComponentType(Type componentType) { + componentTypes.add(componentType); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/parser/Parser.java b/AlgebraicDataflowArchitectureModel/src/parser/Parser.java index 951bcb0..8e2eb56 100644 --- a/AlgebraicDataflowArchitectureModel/src/parser/Parser.java +++ b/AlgebraicDataflowArchitectureModel/src/parser/Parser.java @@ -471,7 +471,7 @@ String typeName = stream.next(); Type type = model.getType(typeName); if (type == null) { - type = new Type(typeName, typeName); + type = new Type(typeName, new code.ast.SimpleType(typeName)); } term.setType(type); break; @@ -654,7 +654,7 @@ String typeName = stream.next(); Type type = model.getType(typeName); if (type == null) { - type = new Type(typeName, typeName); + type = new Type(typeName, new code.ast.SimpleType(typeName)); } var = new Variable(symbolName, type); } else { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java b/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java index 57015ee..74be013 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java @@ -26,9 +26,7 @@ )); methodBody.addStatement(variableDeclarationStatement); - models.algebra.Variable j = new models.algebra.Variable("j"); - models.algebra.Constant limit = new models.algebra.Constant("5"); - ForStatement forStatement = javaGen.getForStatementForList(j, limit); + ForStatement forStatement = javaGen.getForStatementForList("j", "list"); Block forBody = new Block(); forBody.addStatement(new ExpressionStatement( new InfixExpression(new Symbol("+=", 2, Symbol.Type.INFIX), new Variable("sum"), new Variable("j")) @@ -36,7 +34,7 @@ forStatement.setBody(forBody); methodBody.addStatement(forStatement); - EnhancedForStatement efStmt = javaGen.getForStatementForCollection("s", "String", "list"); + EnhancedForStatement efStmt = javaGen.getForStatementForCollection(new VariableDeclaration(DataConstraintModel.typeString, "s"), "list"); Block efBody = new Block(); efBody.addStatement("System.out.println(s);"); efStmt.setBody(efBody); diff --git a/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java b/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java index 0d0efe1..44c9b6c 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/InverseTest.java @@ -99,7 +99,7 @@ for (Position vPos: rhsVars4.keySet()) { Variable v = rhsVars4.get(vPos); if (x.getName().equals("x")) { - JsonType jsonType = new JsonType("Json", "HashMap<>", DataConstraintModel.typeJson); + JsonType jsonType = new JsonType("Json", new code.ast.ParameterizedType(new code.ast.SimpleType("HashMap")), DataConstraintModel.typeJson); jsonType.addMemberType("id", DataConstraintModel.typeInt); jsonType.addMemberType("name", DataConstraintModel.typeString); v.setType(jsonType); diff --git a/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java b/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java index b56b06d..556e065 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/JAXRSCodeGeneratorTest.java @@ -23,14 +23,12 @@ import code.ast.MethodDeclaration; import code.ast.TypeDeclaration; import code.ast.VariableDeclaration; +import generators.CodeGenerator; import generators.CodeGeneratorFromDataFlowGraph; import generators.DataTransferMethodAnalyzer; -import generators.JavaCodeGenerator; -import generators.JavaMethodBodyGenerator; import generators.JavaSpecific; -import generators.JerseyCodeGenerator; -import generators.JerseyMethodBodyGenerator; import generators.JerseySpecific; +import generators.TypeInference; import models.Edge; import models.dataFlowModel.*; import parser.*; @@ -455,7 +453,7 @@ Map.entry("postMessage", Map.entry(Set.of(), Map.entry("void", Map.entry(List.of("String","String"), - 6)))), + 2)))), Map.entry("Group", Map.entry(Set.of(), Map.entry("void", Map.entry(List.of("List","List"), @@ -758,7 +756,7 @@ Map.entry("battle", Map.entry(Set.of(), Map.entry("void", Map.entry(List.of("String","boolean"), - 6)))), + 2)))), Map.entry("Room", Map.entry(Set.of(), Map.entry("void", Map.entry(List.of("boolean"), @@ -1108,7 +1106,7 @@ Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), Map.entry("Map", Map.entry(List.of(), - 8)))))))); + 5)))))))); exprectedStructure.put("Account", Map.entry(Set.of(), Map.entry(Map.ofEntries(Map.entry("vote", "String")), Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), @@ -1282,10 +1280,12 @@ } } } - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(new JavaSpecific()); + typeInference.infer(model); DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); // ArrayList codetree = JerseyMethodBodyGenerator.doGenerate(graph, model, JerseyCodeGenerator.doGenerate(graph, model)); - ArrayList codetree = new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new JerseySpecific(), new JavaSpecific()); + CodeGenerator codeGenerator = new CodeGeneratorFromDataFlowGraph(new JerseySpecific(), new JavaSpecific()); + ArrayList codetree = codeGenerator.generateCode(model, graph); return codetree; } diff --git a/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java b/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java index 8128ce4..dd488ba 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/JavaCodeGeneratorTest.java @@ -20,12 +20,12 @@ import code.ast.MethodDeclaration; import code.ast.TypeDeclaration; import code.ast.VariableDeclaration; +import generators.CodeGenerator; import generators.CodeGeneratorFromDataFlowGraph; import generators.DataTransferMethodAnalyzer; -import generators.JavaCodeGenerator; -import generators.JavaMethodBodyGenerator; import generators.JavaSpecific; import generators.StandaloneSpecific; +import generators.TypeInference; import models.Edge; import models.dataFlowModel.*; import parser.*; @@ -467,7 +467,7 @@ 1))), Map.entry("postMessage", Map.entry("void", Map.entry(List.of("String","String"), - 6))), + 2))), Map.entry("addGroupMember", Map.entry("void", Map.entry(List.of("String","String"), 1))), @@ -974,7 +974,7 @@ 1))), Map.entry("battle", Map.entry("void", Map.entry(List.of("String","boolean"), - 6))), + 2))), Map.entry("Room", Map.entry("void", Map.entry(List.of("boolean","Accounts"), 2)))))); @@ -1272,7 +1272,7 @@ Map.entry("accounts", "Accounts")), Map.ofEntries(Map.entry("getValue", Map.entry("Map", Map.entry(List.of(), - 6))), + 5))), Map.entry("Counts", Map.entry("void", Map.entry(List.of("Accounts"), 1)))))); @@ -1436,10 +1436,12 @@ } } } - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(new JavaSpecific()); + typeInference.infer(model); DataTransferMethodAnalyzer.decideToStoreResourceStates(graph); // ArrayList codetree = JavaMethodBodyGenerator.doGenerate(graph, model, JavaCodeGenerator.doGenerate(graph, model)); - ArrayList codetree = new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new StandaloneSpecific(), new JavaSpecific()); + CodeGenerator codeGenerator = new CodeGeneratorFromDataFlowGraph(new StandaloneSpecific(), new JavaSpecific()); + ArrayList codetree = codeGenerator.generateCode(model, graph); return codetree; } diff --git a/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java b/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java index a91d089..63cda9e 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/NativeAccessTest.java @@ -2,7 +2,8 @@ import org.junit.Test; -import algorithms.TypeInference; +import generators.JavaSpecific; +import generators.TypeInference; import models.algebra.Expression; import models.algebra.InvalidMessage; import models.algebra.ParameterizedIdentifierIsFutureWork; @@ -68,7 +69,8 @@ textOut.getStateTransition().setNextStateExpression(nextStateOut); nativeOutputEventChannel.addChannelMemberAsInput(textOut); model.addChannel(nativeOutputEventChannel); - TypeInference.infer(model); + TypeInference typeInference = new TypeInference(new JavaSpecific()); + typeInference.infer(model); // Create simulator Simulator simulator = new Simulator(model);