diff --git a/AlgebraicDataflowArchitectureModel/models/Search.model b/AlgebraicDataflowArchitectureModel/models/Search.model new file mode 100644 index 0000000..e401c34 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Search.model @@ -0,0 +1,25 @@ +init { + accounts := {"001": {"name": "Alice", "age": 25, "address": "Kobe"}, + "002": {"name": "Bob", "age": 25, "address": "Osaka"}, + "003": {"name": "Carol", "age": 22, "address": "Kobe"}, + "004": {"name": "Dave", "age": 25, "address": "Kobe"} + } +} + +channel Signup { + out accounts(acDB:Map, signUp(aid:Str, name:Str, age:Int, address:Str)) = insert(acDB, aid, {"name": name, "age": age, "address": address}) +} + +channel ChangeName(aid:Str) { + out accounts.{aid}.name(n:Str, changeName(name:Str)) = name +} + +channel Query { + out query(q:Json, enterQuery(age:Int, address:Str)) = {"age": age, "address": address} +} + +channel SearchAccount { + in accounts(acDB:Map, searchAccount(acDB2, q2)) = acDB2 + in query(q:Json, searchAccount(acDB2, q2)) = q2 + out result(resultMap:Map, searchAccount(acDB2, q2)) = search(acDB2, q2) +} diff --git a/AlgebraicDataflowArchitectureModel/models/SimpleUI.model b/AlgebraicDataflowArchitectureModel/models/SimpleUI.model index 6d4cb43..b105544 100644 --- a/AlgebraicDataflowArchitectureModel/models/SimpleUI.model +++ b/AlgebraicDataflowArchitectureModel/models/SimpleUI.model @@ -2,15 +2,17 @@ screenTemplates := { "000": {"widgets": {"001": {"type": "textInput", "text": "", "state": 0, "visible": true}, "002": {"type": "button", "text": "Next", "state": 0, "visible": true}}, - "layout": true}, + "layout": true, + "screenId": "000"}, "001": {"widgets": {"003": {"type": "label", "text": "label", "state": 0, "visible": true}, "004": {"type": "button", "text": "Back", "state": 0, "visible": true}}, - "layout": true} + "layout": true, + "screenId": "001"} } } native channel ScreenUpdate { - in screen(curSc: Json, update(curSc, nextSc)) = nextSc + in screen(curSc: Json, screenUpdate(curSc, nextSc)) = nextSc } native channel SetLayout { 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/prototypes/JAX-RS/GroupChat/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Account.java index 5f97d07..4867382 100644 --- a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Account.java +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Account.java @@ -3,16 +3,16 @@ public class Account { private Map notifications; public Map getValue() { - Map temp_nil3 = new HashMap<>(); - temp_nil3.put("notifications",this.getNotifications()); - return temp_nil3; - } - public Map getNotifications() { - return notifications; + Map temp_nil1 = new HashMap<>(); + temp_nil1.put("notifications",this.getNotifications()); + return temp_nil1; } public void updateNotificationsFromMessages(String self, String gid, int mno, List messages, String member) { this.notifications.put(gid,true); } + public Map getNotifications() { + return this.notifications; + } public void hasRead(String aid, String gid) { this.notifications.remove(gid); } diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Accounts.java index c18d220..30519de 100644 --- a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Accounts.java +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Accounts.java @@ -1,7 +1,7 @@ import java.util.*; -import javax.ws.rs.*; -import javax.ws.rs.client.*; -import javax.ws.rs.core.*; +import jakarta.ws.rs.*; +import jakarta.ws.rs.client.*; +import jakarta.ws.rs.core.*; import org.springframework.stereotype.Component; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.core.JsonProcessingException; @@ -13,35 +13,35 @@ @Produces(MediaType.APPLICATION_JSON) @GET public Map getValue() { - return new HashMap<>(value); + return new HashMap<>(this.value); } public Account getAccount(String v1) { return this.value.get(v1); } - @Path("accounts/{v1}/notifications") - @POST - public void updateNotificationsFromMessages(@PathParam("v1") String v1, @FormParam("gid") String gid, @FormParam("mno") int mno, @FormParam("messages") List messages, @FormParam("member") String member) { - getAccount(v1).updateNotificationsFromMessages(v1, gid, mno, messages, member); - } @Path("/{v1}") @Produces(MediaType.APPLICATION_JSON) @GET public Map getAccountValue(@PathParam("v1") String v1) { return getAccount(v1).getValue(); } - @Path("/{aid}/notifications") + @Path("/{v1}/notifications") + @POST + public void updateNotificationsFromMessages(@PathParam("v1") String v1, @FormParam("gid") String gid, @FormParam("mno") int mno, @FormParam("messages") List messages, @FormParam("member") String member) { + getAccount(v1).updateNotificationsFromMessages(v1, gid, mno, messages, member); + } + @Path("/{v1}/notifications") @Produces(MediaType.APPLICATION_JSON) @GET - public Map getNotificationsValue(@PathParam("aid") String aid) { - return getAccount(aid).getNotifications(); - } - @POST - public void signUp(@FormParam("aid") String aid) { - this.value.put(aid,new Account(new HashMap<>())); + public Map getNotificationsValue(@PathParam("v1") String v1) { + return getAccount(v1).getNotifications(); } @Path("/{aid}/notifications") @DELETE public void hasRead(@PathParam("aid") String aid, @FormParam("gid") String gid) { getAccount(aid).hasRead(aid, gid); } + @POST + public void signUp(@FormParam("aid") String aid) { + this.value.put(aid,new Account(new HashMap<>())); + } } \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Group.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Group.java index bb06954..6d15fd7 100644 --- a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Group.java +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Group.java @@ -1,39 +1,38 @@ import java.util.*; -import javax.ws.rs.client.*; public class Group { - private List members; - private List messages; private Client client = ClientBuilder.newClient(); + private List messages; + private List members; public Map getValue() { - Map temp_nil2 = new HashMap<>(); - temp_nil2.put("members",this.getMembers()); - temp_nil2.put("messages",this.getMessages()); - return temp_nil2; - } - public List getMembers() { - return this.members; - } - public String getMember(int mno) { - return this.members.get(mno); + Map temp_nil0 = new HashMap<>(); + temp_nil0.put("members",this.getMembers()); + temp_nil0.put("messages",this.getMessages()); + return temp_nil0; } public List getMessages() { return this.messages; } - public void postMessage(String gid, String message) throws JsonProcessingException { + public void postMessage(String gid, String message) { + this.messages.add(message); for (int mno = 0; mno < members.size(); mno++) { String member = getMember(mno); Form form = new Form(); form.param("gid", gid.toString()); form.param("mno", Integer.toString(mno)); - for (String i: messages) { + for (String i: this.messages) { form.param("messages", i.toString()); } form.param("member", member.toString()); Entity
entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); String result = client.target("http://localhost:8080").path("/accounts/"+member+"/notifications").request().post(entity, String.class); } - this.messages.add(message); + } + public String getMember(int mno) { + return this.members.get(mno); + } + public List getMembers() { + return this.members; } public void addGroupMember(String gid, String aid) { this.members.add(aid); diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Groups.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Groups.java index 19b1f42..e6f2b90 100644 --- a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Groups.java +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/GroupChat/Groups.java @@ -1,7 +1,7 @@ import java.util.*; -import javax.ws.rs.*; -import javax.ws.rs.client.*; -import javax.ws.rs.core.*; +import jakarta.ws.rs.*; +import jakarta.ws.rs.client.*; +import jakarta.ws.rs.core.*; import org.springframework.stereotype.Component; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.core.JsonProcessingException; @@ -13,7 +13,7 @@ @Produces(MediaType.APPLICATION_JSON) @GET public Map getValue() { - return new HashMap<>(value); + return new HashMap<>(this.value); } public Group getGroup(String gid) { return this.value.get(gid); @@ -24,36 +24,36 @@ public Map getGroupValue(@PathParam("gid") String gid) { return getGroup(gid).getValue(); } - @Path("/{gid}/members") - @Produces(MediaType.APPLICATION_JSON) - @GET - public List getMembersValue(@PathParam("gid") String gid) { - return getGroup(gid).getMembers(); - } @Path("/{gid}/messages") @Produces(MediaType.APPLICATION_JSON) @GET public List getMessagesValue(@PathParam("gid") String gid) { return getGroup(gid).getMessages(); } + @Path("/{gid}/messages") + @POST + public void postMessage(@PathParam("gid") String gid, @FormParam("message") String message) { + getGroup(gid).postMessage(gid, message); + } @Path("/{gid}/members/{mno}") @Produces(MediaType.APPLICATION_JSON) @GET public String getMemberValue(@PathParam("gid") String gid, @PathParam("mno") int mno) { return getGroup(gid).getMember(mno); } + @POST + public void createGroup(@FormParam("gid") String gid) { + this.value.put(gid,new Group(new ArrayList<>(), new ArrayList<>())); + } + @Path("/{gid}/members") + @Produces(MediaType.APPLICATION_JSON) + @GET + public List getMembersValue(@PathParam("gid") String gid) { + return getGroup(gid).getMembers(); + } @Path("/{gid}/members") @POST public void addGroupMember(@PathParam("gid") String gid, @FormParam("aid") String aid) { getGroup(gid).addGroupMember(gid, aid); } - @Path("/{gid}/messages") - @POST - public void postMessage(@PathParam("gid") String gid, @FormParam("message") String message) throws JsonProcessingException { - getGroup(gid).postMessage(gid, message); - } - @POST - public void createGroup(@FormParam("gid") String gid) { - this.value.put(gid,new Group(new ArrayList<>(), new ArrayList<>())); - } } \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Account.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Account.java index 31bc4bd..ca1ca70 100644 --- a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Account.java +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Account.java @@ -1,19 +1,13 @@ import java.util.*; public class Account { - private String name; private int point; + private String name; public Map getValue() { - Map temp_nil5 = new HashMap<>(); - temp_nil5.put("point",this.getPoint()); - temp_nil5.put("name",this.getName()); - return temp_nil5; - } - public String getName() { - return this.name; - } - public int getPoint() { - return point; + Map temp_nil2 = new HashMap<>(); + temp_nil2.put("name",this.getName()); + temp_nil2.put("point",this.getPoint()); + return temp_nil2; } public void updatePointFromBattle(String self, String rid, int mno, boolean battle, String id) { int temp_if0; @@ -23,6 +17,12 @@ temp_if0 = this.point; }this.point = temp_if0; } + public int getPoint() { + return this.point; + } + public String getName() { + return this.name; + } public void changeName(String aid, String name) { this.name = name; } diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Accounts.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Accounts.java index fc4d20e..3575712 100644 --- a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Accounts.java +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Accounts.java @@ -1,7 +1,7 @@ import java.util.*; -import javax.ws.rs.*; -import javax.ws.rs.client.*; -import javax.ws.rs.core.*; +import jakarta.ws.rs.*; +import jakarta.ws.rs.client.*; +import jakarta.ws.rs.core.*; import org.springframework.stereotype.Component; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.core.JsonProcessingException; @@ -13,12 +13,22 @@ @Produces(MediaType.APPLICATION_JSON) @GET public Map getValue() { - return new HashMap<>(value); + return new HashMap<>(this.value); } public Account getAccount(String mid) { return this.value.get(mid); } - @Path("accounts/{mid}/point") + @POST + public void signUp(@FormParam("name") String name, @FormParam("aid") String aid) { + this.value.put(aid,new Account(name, 0)); + } + @Path("/{mid}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getAccountValue(@PathParam("mid") String mid) { + return getAccount(mid).getValue(); + } + @Path("/{mid}/point") @POST public void updatePointFromBattle(@PathParam("mid") String mid, @FormParam("rid") String rid, @FormParam("mno") int mno, @FormParam("battle") boolean battle, @FormParam("id") String id) { getAccount(mid).updatePointFromBattle(mid, rid, mno, battle, id); @@ -29,22 +39,12 @@ public int getPointValue(@PathParam("mid") String mid) { return getAccount(mid).getPoint(); } - @Path("/{mid}") - @Produces(MediaType.APPLICATION_JSON) - @GET - public Map getAccountValue(@PathParam("mid") String mid) { - return getAccount(mid).getValue(); - } @Path("/{mid}/name") @Produces(MediaType.APPLICATION_JSON) @GET public String getNameValue(@PathParam("mid") String mid) { return getAccount(mid).getName(); } - @POST - public void signUp(@FormParam("name") String name, @FormParam("aid") String aid) { - this.value.put(aid,new Account(name, 0)); - } @Path("/{aid}/name") @PUT public void changeName(@PathParam("aid") String aid, @FormParam("name") String name) { diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Member.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Member.java index d12c2cf..03ee021 100644 --- a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Member.java +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Member.java @@ -1,14 +1,13 @@ import java.util.*; -import javax.ws.rs.client.*; public class Member { private String id; private Client client = ClientBuilder.newClient(); public Map getValue() { - Map temp_nil6 = new HashMap<>(); - temp_nil6.put("id",this.getId()); - temp_nil6.put("name",this.getName()); - return temp_nil6; + Map temp_nil3 = new HashMap<>(); + temp_nil3.put("name",this.getName()); + temp_nil3.put("id",this.getId()); + return temp_nil3; } public String getId() { return this.id; diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Members.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Members.java index 0dd75c8..c1ef7ee 100644 --- a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Members.java +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Members.java @@ -3,7 +3,7 @@ public class Members { private List value = new ArrayList<>(); public List getValue() { - return new ArrayList<>(value); + return new ArrayList<>(this.value); } public Member getMember(int mno) { return this.value.get(mno); diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Room.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Room.java index edbdd93..3ccf47d 100644 --- a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Room.java +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Room.java @@ -1,14 +1,13 @@ import java.util.*; -import javax.ws.rs.client.*; public class Room { private Members members = new Members(); - private boolean battle; private Client client = ClientBuilder.newClient(); + private boolean battle; public Map getValue() { Map temp_nil4 = new HashMap<>(); - temp_nil4.put("battle",this.getBattle()); temp_nil4.put("members",this.members.getValue()); + temp_nil4.put("battle",this.getBattle()); return temp_nil4; } public Members getMembers() { @@ -17,18 +16,18 @@ public boolean getBattle() { return this.battle; } - public void battle(String rid, boolean hasWon) throws JsonProcessingException { + public void battle(String rid, boolean hasWon) { + this.battle = hasWon; for (int mno = 0; mno < members.getValue().size(); mno++) { String id = getMembers().getMember(mno).getId(); Form form = new Form(); form.param("rid", rid.toString()); form.param("mno", Integer.toString(mno)); - form.param("battle", Boolean.toString(battle)); + form.param("battle", Boolean.toString(this.battle)); form.param("id", id.toString()); Entity entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED); String result = client.target("http://localhost:8080").path("/accounts/"+id+"/point").request().post(entity, String.class); } - this.battle = hasWon; } public Room(boolean battle) { this.battle = battle; diff --git a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Rooms.java b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Rooms.java index 818eebd..c0b5e43 100644 --- a/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Rooms.java +++ b/AlgebraicDataflowArchitectureModel/prototypes/JAX-RS/OnlineBattleGame2/Rooms.java @@ -1,7 +1,7 @@ import java.util.*; -import javax.ws.rs.*; -import javax.ws.rs.client.*; -import javax.ws.rs.core.*; +import jakarta.ws.rs.*; +import jakarta.ws.rs.client.*; +import jakarta.ws.rs.core.*; import org.springframework.stereotype.Component; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.core.JsonProcessingException; @@ -13,16 +13,25 @@ @Produces(MediaType.APPLICATION_JSON) @GET public Map getValue() { - return new HashMap<>(value); + return new HashMap<>(this.value); } public Room getRoom(String rid) { return this.value.get(rid); } - @Path("/{rid}") + @Path("/{rid}/members") @Produces(MediaType.APPLICATION_JSON) @GET - public Map getRoomValue(@PathParam("rid") String rid) { - return getRoom(rid).getValue(); + public List getMembersValue(@PathParam("rid") String rid) { + return getRoom(rid).getMembers().getValue(); + } + @Path("/{rid}/members") + @POST + public void addRoomMember(@PathParam("rid") String rid, @FormParam("id") String id) { + getRoom(rid).getMembers().addRoomMember(rid, id); + } + @POST + public void createRoom(@FormParam("rid") String rid) { + this.value.put(rid,new Room(false)); } @Path("/{rid}/members/{mno}/id") @Produces(MediaType.APPLICATION_JSON) @@ -42,30 +51,21 @@ public boolean getBattleValue(@PathParam("rid") String rid) { return getRoom(rid).getBattle(); } + @Path("/{rid}/battle") + @PUT + public void battle(@PathParam("rid") String rid, @FormParam("hasWon") boolean hasWon) { + getRoom(rid).battle(rid, hasWon); + } + @Path("/{rid}") + @Produces(MediaType.APPLICATION_JSON) + @GET + public Map getRoomValue(@PathParam("rid") String rid) { + return getRoom(rid).getValue(); + } @Path("/{rid}/members/{mno}/name") @Produces(MediaType.APPLICATION_JSON) @GET public String getNameValue(@PathParam("rid") String rid, @PathParam("mno") int mno) { return getRoom(rid).getMembers().getMember(mno).getName(); } - @Path("/{rid}/members") - @Produces(MediaType.APPLICATION_JSON) - @GET - public List getMembersValue(@PathParam("rid") String rid) { - return getRoom(rid).getMembers().getValue(); - } - @POST - public void createRoom(@FormParam("rid") String rid) { - this.value.put(rid,new Room(false)); - } - @Path("/{rid}/battle") - @PUT - public void battle(@PathParam("rid") String rid, @FormParam("hasWon") boolean hasWon) throws JsonProcessingException { - getRoom(rid).battle(rid, hasWon); - } - @Path("/{rid}/members") - @POST - public void addRoomMember(@PathParam("rid") String rid, @FormParam("id") String id) { - getRoom(rid).getMembers().addRoomMember(rid, id); - } } \ No newline at end of file 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 27471b2..80aed93 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; @@ -339,7 +343,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/AnnotatableType.java b/AlgebraicDataflowArchitectureModel/src/code/ast/AnnotatableType.java new file mode 100644 index 0000000..6e87c83 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/AnnotatableType.java @@ -0,0 +1,26 @@ +package code.ast; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents an abstract base class for AST types that can have annotations. + * This class extends the functionality of {@link Type} by introducing support + * for attaching annotations to the type. + *

+ * Subclasses of this class represent specific kinds of types in the AST that + * allow annotations, such as primitive types or other specialized types. + * + * @author s-yamagiwa + */ +public abstract class AnnotatableType extends Type { + private final List annotations = new ArrayList<>(); + + public void addAnnotation(Annotation annotation) { + annotations.add(annotation); + } + + public List getAnnotations() { + return annotations; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Assignment.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Assignment.java new file mode 100644 index 0000000..a7a2fc9 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Assignment.java @@ -0,0 +1,37 @@ +package code.ast; + +/** + * Represents an assignment expression node in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class Assignment extends Expression { + private Expression left; + private Expression right; + + public Assignment(Expression left, Expression right) { + this.left = left; + this.right = right; + } + + public Expression getLeft() { + return left; + } + + public void setLeft(Expression left) { + this.left = left; + } + + public Expression getRight() { + return right; + } + + public void setRight(Expression right) { + this.right = right; + } + + @Override + public String toString() { + return left.toString() + " " + "+" + " " + right.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java index 2b4f654..a7a07d9 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Block.java @@ -2,31 +2,88 @@ import java.util.List; import java.util.ArrayList; +import java.util.stream.Collectors; -public class Block extends ASTNode { - private List statements = new ArrayList(); +public class Block extends Statement { + private List statements = new ArrayList(); - public List getStatements() { + public List getStatements2() { return statements; } - public void setStatements(List statements) { + public void setStatements(List statements) { this.statements = statements; } - public void addFirstStatement(String statement) { + public void addFirstStatement(Statement statement) { statements.add(0, statement); } - - public void addStatement(String statement) { + + public void addStatement(Statement statement) { statements.add(statement); } - - public String toString() { - String code = ""; - for (String statement: statements) { - code += (statement + "\n"); + + public void addFirstStatements(List statements) { + this.statements.addAll(0, statements); + } + + public void addStatements(List statements) { + this.statements.addAll(statements); + } + + //==================================================== + //TODO: CodeGenerator修正後削除 + + public List getStatements() { + List strings = new ArrayList<>(); + for (Statement stmt : statements) { + if (stmt != null) { + strings.add(stmt.toString()); + } } - return code; + return strings; + } + + public void addFirstStatement(String statement) { + if (statement != null) { + this.addFirstStatement(new Statement() { + @Override + public String toString() { + return statement; + } + }); + } + } + + public void addStatement(String statement) { + if (statement != null) { + this.addStatement(new PlainStatement(statement)); + } + } + + //==================================================== + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{\n"); + + for (Statement statement : statements) { + if (statement != null) { + String content = statement.toString(); + + // split statement + String[] lines = content.split("\n"); + + // Tab + for (String line : lines) { + sb.append("\t").append(line).append("\n"); + } + } + } + + sb.append("}"); + return sb.toString(); } } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ClassInstanceCreation.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ClassInstanceCreation.java new file mode 100644 index 0000000..fe20607 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ClassInstanceCreation.java @@ -0,0 +1,59 @@ +package code.ast; + +import java.util.List; + +public class ClassInstanceCreation extends Expression { + private Type type; + + private List arguments; + + public ClassInstanceCreation(Type type) { + this(type, List.of()); + } + + public ClassInstanceCreation(Type type, List arguments) { + this.type = type; + this.arguments = arguments; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public List getArguments() { + return arguments; + } + + public void setArguments(List arguments) { + this.arguments = arguments; + } + + public void addArgument(Expression expression) { + arguments.add(expression); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + + builder.append("new "); + builder.append(type.toString()); + builder.append("("); + for (int i = 0; i < arguments.size(); i++) { + Expression argument = arguments.get(i); + + builder.append(argument.toString()); + + if (i < arguments.size() - 1) { + builder.append(", "); + } + } + builder.append(")"); + + return builder.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Constant.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Constant.java new file mode 100644 index 0000000..f15c136 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Constant.java @@ -0,0 +1,27 @@ +package code.ast; + +/** + * Represents a constant in the AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class Constant extends Expression { + private String value; + + public Constant(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/EnhancedForStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/EnhancedForStatement.java new file mode 100644 index 0000000..77377f4 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/EnhancedForStatement.java @@ -0,0 +1,23 @@ +package code.ast; + +public class EnhancedForStatement extends Statement { + + private VariableDeclaration singleVariableDeclaration; + private Expression expression; + private Statement body; + + public VariableDeclaration getParameter() { return singleVariableDeclaration; } + public void setParameter(VariableDeclaration parameter) { this.singleVariableDeclaration = parameter; } + + public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { this.expression = expression; } + + public Statement getBody() { return body; } + public void setBody(Statement body) { this.body = body; } + + @Override + public String toString() { + String typeName = singleVariableDeclaration.getType().getImplementationTypeName(); + return "for (" + typeName + " " + singleVariableDeclaration.getName() + " : " + expression + ") " + body; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Expression.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Expression.java new file mode 100644 index 0000000..d492947 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Expression.java @@ -0,0 +1,9 @@ +package code.ast; + +/** + * Abstract base class for all expression nodes in the abstract syntax tree (AST). + * + * @author s-yamagiwa + */ +public abstract class Expression extends ASTNode { +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ExpressionStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ExpressionStatement.java new file mode 100644 index 0000000..f8fdf96 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ExpressionStatement.java @@ -0,0 +1,17 @@ +package code.ast; + +public class ExpressionStatement extends Statement{ + private Expression expression; + + public ExpressionStatement(Expression expression) { + this.expression = expression; + } + + public Expression getExpression() { return expression; } + public void setExpression(Expression expression) { this.expression = expression; } + + @Override + public String toString() { + return expression + ";"; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/FieldAccess.java b/AlgebraicDataflowArchitectureModel/src/code/ast/FieldAccess.java new file mode 100644 index 0000000..bfae25d --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/FieldAccess.java @@ -0,0 +1,45 @@ +package code.ast; + +/** + * Represents field accesses in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class FieldAccess extends Expression { + private Expression expression; + + private String fieldName; + + public FieldAccess(String fieldName) { + this(null, fieldName); + } + + public FieldAccess(Expression expression, String fieldName) { + this.expression = expression; + this.fieldName = fieldName; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public String getFieldName() { + return fieldName; + } + + public void setFieldName(String fieldName) { + this.fieldName = fieldName; + } + + @Override + public String toString() { + if (expression == null) { + return fieldName; + } + return expression + "." + fieldName; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/FieldDeclaration.java b/AlgebraicDataflowArchitectureModel/src/code/ast/FieldDeclaration.java index 0993b92..cedf1a4 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/FieldDeclaration.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/FieldDeclaration.java @@ -9,7 +9,8 @@ public class FieldDeclaration extends BodyDeclaration implements IAnnotatable { private Type type; private String fieldName; - private String initializer; + private String initializer = null; + private String initializationBlock = null; private Map annotations = new HashMap<>(); public FieldDeclaration(Type type, String fieldName) { @@ -47,6 +48,14 @@ this.initializer = initializer; } + public String getInitializationBlock() { + return initializationBlock; + } + + public void setInitializationBlock(String initializationBlock) { + this.initializationBlock = initializationBlock; + } + @Override public Annotation getAnnotation(String name) { return annotations.get(name); @@ -67,10 +76,14 @@ for (Annotation annotation: getAnnotations()) { code += annotation.toString() + "\n"; } - if (initializer == null) { - code += "private " + type.getInterfaceTypeName() + " " + fieldName + ";\n"; + if (initializationBlock != null) { + code += "private " + type.getInterfaceTypeName() + " " + fieldName + ";\n" + initializationBlock + "\n"; } else { - code += "private " + type.getInterfaceTypeName() + " " + fieldName + " = " + initializer + ";\n"; + if (initializer == null) { + code += "private " + type.getInterfaceTypeName() + " " + fieldName + ";\n"; + } else { + code += "private " + type.getInterfaceTypeName() + " " + fieldName + " = " + initializer + ";\n"; + } } return code; } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ForStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ForStatement.java new file mode 100644 index 0000000..3acee16 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ForStatement.java @@ -0,0 +1,70 @@ +package code.ast; + +import java.util.ArrayList; +import java.util.List; + +public class ForStatement extends Statement { + + private List initializers = new ArrayList<>(); + private Expression optionalConditionExpression; + private List updaters = new ArrayList<>(); + private Statement body; + + public List getInitializers() { + return initializers; + } + + public void setInitializers(List initializers) { + this.initializers = initializers; + } + + public Expression getExpression() { + return optionalConditionExpression; + } + + public void setExpression(Expression expression) { + this.optionalConditionExpression = expression; + } + + public List getUpdaters() { + return updaters; + } + + public void setUpdaters(List updaters) { + this.updaters = updaters; + } + + public Statement getBody() { + return body; + } + + public void setBody(Statement body) { + this.body = body; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("for ("); + + for (int i = 0; i < initializers.size(); i++) { + String init = initializers.get(i).toString(); + sb.append(init.endsWith(";") ? init.substring(0, init.length() - 1) : init); + if (i < initializers.size() - 1) sb.append(", "); + } + sb.append("; "); + + if (optionalConditionExpression != null) sb.append(optionalConditionExpression); + sb.append("; "); + + for (int i = 0; i < updaters.size(); i++) { + String update = updaters.get(i).toString(); + sb.append(update.endsWith(";") ? update.substring(0, update.length() - 1) : update); + if (i < updaters.size() - 1) sb.append(", "); + } + sb.append(") "); + + if (body != null) sb.append(body); + return sb.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/IfStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/IfStatement.java new file mode 100644 index 0000000..3ad4b77 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/IfStatement.java @@ -0,0 +1,43 @@ +package code.ast; + +public class IfStatement extends Statement { + + private Expression expression; + private Statement thenStatement; + private Statement elseStatement; + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public Statement getThenStatement() { + return thenStatement; + } + + public void setThenStatement(Statement thenStatement) { + this.thenStatement = thenStatement; + } + + public Statement getElseStatement() { + return elseStatement; + } + + public void setElseStatement(Statement elseStatement) { + this.elseStatement = elseStatement; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("if ").append(expression); + sb.append(thenStatement); + if (elseStatement != null) { + sb.append(" else ").append(elseStatement); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/InfixExpression.java b/AlgebraicDataflowArchitectureModel/src/code/ast/InfixExpression.java new file mode 100644 index 0000000..8aa90be --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/InfixExpression.java @@ -0,0 +1,50 @@ +package code.ast; + +import models.algebra.Symbol; + +/** + * Represents an infix expression in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class InfixExpression extends Expression { + private Symbol operator; + + private Expression leftOperand; + private Expression rightOperand; + + public InfixExpression(Symbol operator, Expression leftOperand, Expression rightOperand) { + this.operator = operator; + this.leftOperand = leftOperand; + this.rightOperand = rightOperand; + } + + public Symbol getOperator() { + return this.operator; + } + + public void setOperator(Symbol operator) { + this.operator = operator; + } + + public Expression getLeftOperand() { + return leftOperand; + } + + public void setLeftOperand(Expression expression) { + this.leftOperand = expression; + } + + public Expression getRightOperand() { + return rightOperand; + } + + public void setRightOperand(Expression expression) { + this.rightOperand = expression; + } + + @Override + public String toString() { + return leftOperand.toString() + " " + operator.toString() + " " + rightOperand.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Lexer.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Lexer.java new file mode 100644 index 0000000..cd2974c --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Lexer.java @@ -0,0 +1,55 @@ +package code.ast; + +/** + * The Lexer class provides functionalities for parsing and iterating through + * a source string of text character by character. + * + * @author s-yamagiwa; + */ +public class Lexer { + private final String source; + private int position; + + public Lexer(String source) { + this.source = source; + this.position = 0; + } + + /** + * Retrieves the next character without advancing the position. + * + * @return The next character. + */ + public char peek() { + if (position >= source.length()) { + return '\0'; // End of line + } + + return source.charAt(position); + } + + /** + * Retrieves the next character after advancing the position. + * + * @return The next character. + */ + public char peekNext() { + if (position + 1 >= source.length()) { + return '\0'; // End of line + } + + return source.charAt(position + 1); + } + + /** + * Advances the position by one character. + * + * @return The character that was previously at the current position. + */ + public char advance() { + char current = peek(); + position++; + + return current; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java b/AlgebraicDataflowArchitectureModel/src/code/ast/MethodDeclaration.java index 5f5aafc..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(); @@ -142,21 +159,18 @@ } code += (name + "("); if (parameters != null) { - String delimitar = ""; - for (VariableDeclaration parameter: parameters) { - code = code + delimitar + parameter.toString(); - delimitar = ", "; + for (int i = 0; i < parameters.size(); i++) { + code += parameters.get(i).toString(); + if (i < parameters.size() - 1) code += ", "; } } code += ") "; - if (thrws != null) { - code += thrws.toString() + " "; - } - code += "{\n"; + if (body != null) { - code += CodeUtil.insertTab(body.toString()); + code += body.toString(); + } else { + code += ";"; } - code += "}"; return code; } } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/MethodInvocation.java b/AlgebraicDataflowArchitectureModel/src/code/ast/MethodInvocation.java new file mode 100644 index 0000000..94c90e1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/MethodInvocation.java @@ -0,0 +1,91 @@ +package code.ast; + +import java.util.List; + +/** + * Represents a method invocation in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + * @apiNote Type arguments aren't supported because it isn't necessary in DTRAM code generator. + */ +public class MethodInvocation extends Expression { + /** + * The receiver expression of the invocation + * defaults to {@code null} + */ + private Expression receiver; + + /** + * The method name to be called by this invocation + */ + private String methodName; + + /** + * All arguments used in the called method + */ + private List arguments; + + public MethodInvocation(String methodName) { + this(null, methodName); + } + + public MethodInvocation(Expression receiver, String methodName) { + this(receiver, methodName, List.of()); + } + + public MethodInvocation(Expression receiver, String methodName, List arguments) { + this.receiver = receiver; + this.methodName = methodName; + this.arguments = arguments; + } + + public Expression getReceiver() { + return receiver; + } + + public void setReceiver(Expression receiver) { + this.receiver = receiver; + } + + public String getMethodName() { + return methodName; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + public List getArguments() { + return arguments; + } + + public void setArguments(List arguments) { + this.arguments = arguments; + } + + @Override + public String toString() { + if (receiver == null) { + StringBuilder builder = new StringBuilder(); + + builder.append(methodName).append("("); + + if (!arguments.isEmpty()) { + for (int i = 0; i < arguments.size(); i++) { + Expression argument = arguments.get(i); + + builder.append(argument.toString()); + + if (i < arguments.size() - 1) { + builder.append(", "); + } + } + } + + builder.append(");"); + + return builder.toString(); + } + return super.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ParameterizedType.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ParameterizedType.java new file mode 100644 index 0000000..ca7d269 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ParameterizedType.java @@ -0,0 +1,109 @@ +package code.ast; + +import java.util.List; + +/** + * Represents a parameterized type in an abstract syntax tree (AST). + * A parameterized type consists of a base type and a set of type arguments. + *

+ * For example, List<String> is a parameterized type where + * List is the base type and String is the type argument. + * + * @author s-yamagiwa + */ +public class ParameterizedType extends Type { + /** + * The base type of the parameterized type. + *

+ * For example, List in List<String> is a base type. + */ + private Type type; + + /** + * The type arguments of the parameterized type. + * Defaults to an empty list. + *

+ * For example, String in List<String> is a type argument. + */ + private List typeArguments; + + public ParameterizedType(Type type, List typeArguments) { + this.type = type; + this.typeArguments = typeArguments; + } + + public ParameterizedType(Type type) { + this(type, List.of()); + } + + /** + * Adds a type argument to the parameterized type. + * + * @param type The type argument to add. Only {@link SimpleType}s are allowed for now. + */ + public void addTypeArgument(Type type) { + typeArguments.add(type); + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + /** + * Returns the type arguments of the parameterized type. + * Only {@link SimpleType}s are allowed for now. + *

+ * It can be empty if it is the type of created instances like in the following example. + * new List<>() or new HashMap<>() + * + * @return The type arguments of the parameterized type. + */ + public List getTypeArguments() { + return typeArguments; + } + + public void setTypeArguments(List typeArguments) { + 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()) { + return type.toString(); + } + + StringBuilder builder = new StringBuilder(); + builder.append(type.toString()); + builder.append("<"); + for (int i = 0; i < typeArguments.size(); i++) { + builder.append(typeArguments.get(i).toString()); + if (i < typeArguments.size() - 1) { + builder.append(", "); + } + } + builder.append(">"); + + return builder.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ParenthesizedExpression.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ParenthesizedExpression.java new file mode 100644 index 0000000..a7b50cb --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ParenthesizedExpression.java @@ -0,0 +1,28 @@ +package code.ast; + +/** + * Represents a parenthesized expression in AST (Abstract Syntax Tree) + * This class is used to save the priority of each expression + * + * @author s-yamagiwa + */ +public class ParenthesizedExpression extends Expression { + private Expression expression; + + public ParenthesizedExpression(Expression expression) { + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public String toString() { + return "(" + expression.toString() + ")"; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/PlainStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/PlainStatement.java new file mode 100644 index 0000000..edc9ff5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/PlainStatement.java @@ -0,0 +1,18 @@ +package code.ast; + +//==================================================== +//TODO: CodeGenerator修正後削除 +//==================================================== + +public class PlainStatement extends Statement { + private String code; + + public PlainStatement(String code) { + this.code = code; + } + + @Override + public String toString() { + return code; + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/PostfixExpression.java b/AlgebraicDataflowArchitectureModel/src/code/ast/PostfixExpression.java new file mode 100644 index 0000000..bc520ac --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/PostfixExpression.java @@ -0,0 +1,53 @@ +package code.ast; + +/** + * Represents a postfix expression in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class PostfixExpression extends Expression { + public enum Operator { + INCREMENT("++"), DECREMENT("--"); + + Operator(String symbol) { + this.symbol = symbol; + } + + private final String symbol; + + @Override + public String toString() { + return symbol; + } + } + + private Expression operand; + + private Operator operator; + + public PostfixExpression(Expression operand, Operator operator) { + this.operand = operand; + this.operator = operator; + } + + public Expression getOperand() { + return operand; + } + + public void setOperand(Expression operand) { + this.operand = operand; + } + + public Operator getOperator() { + return operator; + } + + public void setOperator(Operator operator) { + this.operator = operator; + } + + @Override + public String toString() { + return operand.toString() + operator.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/PrefixExpression.java b/AlgebraicDataflowArchitectureModel/src/code/ast/PrefixExpression.java new file mode 100644 index 0000000..2e854b7 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/PrefixExpression.java @@ -0,0 +1,53 @@ +package code.ast; + +/** + * Represents a prefix expression in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class PrefixExpression extends Expression { + public enum Operator { + INCREMENT("++"), DECREMENT("--"), PLUS("+"), MINUS("-"), NOT("!"); + + Operator(String symbol) { + this.symbol = symbol; + } + + private final String symbol; + + @Override + public String toString() { + return symbol; + } + } + + private Expression operand; + + private Operator operator; + + public PrefixExpression(Expression operand, Operator operator) { + this.operand = operand; + this.operator = operator; + } + + public Expression getOperand() { + return operand; + } + + public void setOperand(Expression operand) { + this.operand = operand; + } + + public Operator getOperator() { + return operator; + } + + public void setOperator(Operator operator) { + this.operator = operator; + } + + @Override + public String toString() { + return operator.toString() + operand.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java b/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java new file mode 100644 index 0000000..3381022 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/PrimitiveType.java @@ -0,0 +1,34 @@ +package code.ast; + +/** + * Represents a primitive type in the abstract syntax tree (AST). + * This class extends the {@code AnnotatableType}, allowing annotations + * to be attached to primitive types. + *

+ * Primitive types are: {@code boolean}, {@code byte}, {@code char}, {@code short}, {@code int}, {@code long}, {@code float}, {@code double} and {@code void} + * + * @author s-yamagiwa + */ +public class PrimitiveType extends AnnotatableType { + private String typeName; + + public PrimitiveType(String typeName) { + this.typeName = typeName; + } + + @Override + public String toString() { + if (getAnnotations().isEmpty()) { + return typeName; + } + + StringBuilder builder = new StringBuilder(); + for (Annotation annotation : getAnnotations()) { + builder.append(annotation.toString()); + builder.append(" "); + } + builder.append(typeName); + + return builder.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ReturnStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ReturnStatement.java new file mode 100644 index 0000000..400de02 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ReturnStatement.java @@ -0,0 +1,21 @@ +package code.ast; + +public class ReturnStatement extends Statement{ + private Expression expression; + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public String toString() { + if (expression != null) { + return "return " + expression + ";"; + } + return "return;"; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/SimpleType.java b/AlgebraicDataflowArchitectureModel/src/code/ast/SimpleType.java new file mode 100644 index 0000000..3451ee3 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/SimpleType.java @@ -0,0 +1,39 @@ +package code.ast; + +/** + * Represents a simple type in the AST, which is a type with a single identifier. + * For example, String, List, Map or MyClass. + * + * @author s-yamagiwa + */ +public class SimpleType extends AnnotatableType { + private String name; + + public SimpleType(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + if (getAnnotations().isEmpty()) { + return name; + } + + StringBuilder builder = new StringBuilder(); + for (Annotation annotation : getAnnotations()) { + builder.append(annotation.toString()); + builder.append(" "); + } + builder.append(name); + + return builder.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Statement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Statement.java new file mode 100644 index 0000000..96d1af1 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Statement.java @@ -0,0 +1,7 @@ +package code.ast; + +public abstract class Statement extends ASTNode { + + @Override + public abstract String toString(); +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/SuperMethodInvocation.java b/AlgebraicDataflowArchitectureModel/src/code/ast/SuperMethodInvocation.java new file mode 100644 index 0000000..e7e3573 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/SuperMethodInvocation.java @@ -0,0 +1,62 @@ +package code.ast; + +import java.util.List; + +/** + * Represents a super method invocation in AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + * @apiNote Type arguments aren't supported because it isn't necessary in DTRAM code generator. + */ +public class SuperMethodInvocation extends Expression { + private String methodName; + private List arguments; + + public SuperMethodInvocation(String methodName) { + this(methodName, List.of()); + } + + public SuperMethodInvocation(String methodName, List arguments) { + this.methodName = methodName; + this.arguments = arguments; + } + + public String getMethodName() { + return methodName; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + public List getArguments() { + return arguments; + } + + public void setArguments(List arguments) { + this.arguments = arguments; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + + builder.append("super.").append(methodName).append("("); + + if (!arguments.isEmpty()) { + for (int i = 0; i < arguments.size(); i++) { + Expression argument = arguments.get(i); + + builder.append(argument.toString()); + + if (i < arguments.size() - 1) { + builder.append(", "); + } + } + } + + builder.append(");"); + + return builder.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/ThisExpression.java b/AlgebraicDataflowArchitectureModel/src/code/ast/ThisExpression.java new file mode 100644 index 0000000..aad8ee8 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/ThisExpression.java @@ -0,0 +1,4 @@ +package code.ast; + +public class ThisExpression extends Expression { +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java new file mode 100644 index 0000000..d5291e9 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Type.java @@ -0,0 +1,37 @@ +package code.ast; + +/** + * Represents an abstract base class for all types in an abstract syntax tree (AST). + * A type can represent various forms such as primitive types, simple types, + * parameterized types, or others as defined by subclasses. + * + * @author s-yamagiwa + */ +public abstract class Type extends ASTNode implements models.algebra.Type.ITypeImpl { + /** + * Returns whether this type is a primitive type or not. + * + * @return true if this type is a primitive type, false otherwise. + */ + public final boolean isPrimitiveType() { + return (this instanceof PrimitiveType); + } + + /** + * Returns whether this type is a simple type or not. + * + * @return true if this type is a simple type, false otherwise. + */ + public final boolean isSimpleType() { + return (this instanceof SimpleType); + } + + /** + * Returns whether this type is a parameterized type or not. + * + * @return true if this type is a parameterized type, false otherwise. + */ + public final boolean isParameterizedType() { + return (this instanceof ParameterizedType); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/TypeLiteral.java b/AlgebraicDataflowArchitectureModel/src/code/ast/TypeLiteral.java new file mode 100644 index 0000000..4163b7d --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/TypeLiteral.java @@ -0,0 +1,27 @@ +package code.ast; + +/** + * Represents a type literal expression in the AST. + * + * @author s-yamagiwa + */ +public class TypeLiteral extends Expression { + private Type type; + + public TypeLiteral(Type type) { + this.type = type; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + @Override + public String toString() { + return type.toString(); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/Variable.java b/AlgebraicDataflowArchitectureModel/src/code/ast/Variable.java new file mode 100644 index 0000000..6d3dc00 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/Variable.java @@ -0,0 +1,27 @@ +package code.ast; + +/** + * Represents a variable in the AST (Abstract Syntax Tree) + * + * @author s-yamagiwa + */ +public class Variable extends Expression { + private String name; + + public Variable(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclaration.java b/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclaration.java index 6a7b25b..b841603 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclaration.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclaration.java @@ -9,6 +9,7 @@ public class VariableDeclaration extends ASTNode implements IAnnotatable { private Type type; private String variableName; + private Expression optionalInitializer; private Map annotations = new HashMap<>(); public VariableDeclaration(Type type, String variableName) { @@ -16,6 +17,11 @@ this.variableName = variableName; } + public VariableDeclaration(Type type, String variableName, Expression initializer) { + this(type, variableName); + this.optionalInitializer = initializer; + } + public Type getType() { return type; } @@ -32,6 +38,10 @@ this.variableName = variableName; } + public Expression getInitializer() { return optionalInitializer; } + + public void setInitializer(Expression initializer) { this.optionalInitializer = initializer; } + @Override public Annotation getAnnotation(String name) { return annotations.get(name); @@ -46,13 +56,13 @@ public void addAnnotation(Annotation annotation) { annotations.put(annotation.getElementName(), annotation); } - + public String toString() { String code = ""; - for (Annotation annotation: getAnnotations()) { - code += annotation.toString() + " "; + code += variableName; + if (optionalInitializer != null) { + code += " = " + optionalInitializer; } - code += type.getInterfaceTypeName() + " " + variableName; return code; } } diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclarationStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclarationStatement.java new file mode 100644 index 0000000..a5f3c8a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/VariableDeclarationStatement.java @@ -0,0 +1,81 @@ +package code.ast; + +import java.util.ArrayList; +import java.util.List; +import models.algebra.Type; + +public class VariableDeclarationStatement extends Statement { + + private List modifiers = new ArrayList<>(); + private Type type = null; + private List fragments = new ArrayList<>(); + + public List getModifiers() { + return modifiers; + } + + public void setModifiers(List modifiers) { + this.modifiers = modifiers; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public List getFragments() { + return fragments; + } + + public void addFragment(VariableDeclaration fragment) { + if (fragment == null) return; + + if (this.type == null) { + this.type = fragment.getType(); + this.fragments.add(fragment); + } else { + if (this.type.equals(fragment.getType())) { + this.fragments.add(fragment); + } else { + System.err.println("Type mismatch: " + fragment); + } + } + } + + public void setFragments(List fragments) { + this.fragments = fragments; + + if (fragments != null && !fragments.isEmpty()) { + this.type = fragments.get(0).getType(); + } else { + this.type = null; + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + for (Integer mod : modifiers) { + if (mod == Modifier.PRIVATE) sb.append("private "); + else if (mod == Modifier.PUBLIC) sb.append("public "); + else if (mod == Modifier.PROTECTED) sb.append("protected "); + else if (mod == Modifier.STATIC) sb.append("static "); + } + + if (this.type != null) { + sb.append(this.type.getImplementationTypeName()).append(" "); + } + + for (int i = 0; i < fragments.size(); i++) { + sb.append(fragments.get(i).toString()); + if (i < fragments.size() - 1) sb.append(", "); + } + + sb.append(";"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/WhileStatement.java b/AlgebraicDataflowArchitectureModel/src/code/ast/WhileStatement.java new file mode 100644 index 0000000..6d22d84 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/WhileStatement.java @@ -0,0 +1,33 @@ +package code.ast; + +public class WhileStatement extends Statement { + + private Expression expression; + private Statement body; + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public Statement getBody() { + return body; + } + + public void setBody(Statement body) { + this.body = body; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("while (").append(expression).append(") "); + if (body != null) { + sb.append(body); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerationContext.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerationContext.java new file mode 100644 index 0000000..a14604e --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerationContext.java @@ -0,0 +1,134 @@ +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 (!CodeGenerator.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 (CodeGenerator.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 (CodeGenerator.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 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 (CodeGenerator.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 40caf08..fa3ad27 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; @@ -31,9 +25,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; @@ -59,68 +57,19 @@ public static final String updateMethodPrefix = "update"; 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", new code.ast.SimpleType("SwingPresenter")); private static String mainTypeName = null; - private static ILanguageSpecific langSpec = null; - private static IPlatformSpecific platformSpec = null; - - public static String getMainTypeName() { - return mainTypeName; - } - - public static void setMainTypeName(String mainTypeName) { - CodeGenerator.mainTypeName = mainTypeName; - } + protected CodeGenerationContext generationContext = null; + protected ILanguageSpecific langSpec = null; + protected IPlatformSpecific platformSpec = null; - public static void resetMainTypeName() { - CodeGenerator.mainTypeName = null; + public CodeGenerator(IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + this.langSpec = langSpec; + this.platformSpec = platformSpec; + this.generationContext = new CodeGenerationContext(langSpec, platformSpec); } - - 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"; - } - } - return langSpec.toComponentName(name); - } - - 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 static boolean generatesComponent(ResourceHierarchy res) { if (res.getParent() == null) return true; if (res.getChildren() == null || res.getChildren().size() == 0) return false; @@ -131,6 +80,26 @@ // return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0); } + public String getMainTypeName() { + return mainTypeName; + } + + public void setMainTypeName(String mainTypeName) { + CodeGenerator.mainTypeName = mainTypeName; + } + + public void resetMainTypeName() { + CodeGenerator.mainTypeName = null; + } + + public String getComponentName(ResourceHierarchy res, ILanguageSpecific langSpec) { + return generationContext.getComponentName(res, langSpec); + } + + public Type getImplStateType(ResourceHierarchy res, ILanguageSpecific langSpec) { + return generationContext.getImplStateType(res, langSpec); + } + /** * Generate source codes in specified language from data-flow/control-flow graph. * @@ -139,9 +108,7 @@ * @param langSpec specified language * @return source codes */ - public ArrayList generateCode(DataTransferModel model, IFlowGraph flowGraph, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { - CodeGenerator.langSpec = langSpec; - CodeGenerator.platformSpec = platformSpec; + public ArrayList generateCode(DataTransferModel model, IFlowGraph flowGraph) { ArrayList codes = new ArrayList<>(); Map> dependedRootComponentGraph = null; @@ -160,13 +127,12 @@ } // Generate the other components. - generateCodeFromFlowGraph(model, flowGraph, components, codes, dependedRootComponentGraph, platformSpec, langSpec); + generateCodeFromFlowGraph(model, flowGraph, components, codes, dependedRootComponentGraph); return codes; } - public abstract void generateCodeFromFlowGraph(DataTransferModel model, IFlowGraph flowGraph, Collection> components, ArrayList codes, - Map> dependedRootComponentGraph, IPlatformSpecific platformSpec, ILanguageSpecific langSpec); + public abstract void generateCodeFromFlowGraph(DataTransferModel model, IFlowGraph flowGraph, Collection> components, ArrayList codes, Map> dependedRootComponentGraph); private static Map> getDependedRootComponentGraph(DataTransferModel model) { Map> dependedComponentGraph = new HashMap<>(); @@ -290,8 +256,7 @@ orderedList.add(0, curNodeSet); } - protected void updateMainComponent(TypeDeclaration mainType, MethodDeclaration mainConstructor, Node componentNode, - MethodDeclaration constructor, final List depends, ILanguageSpecific langSpec) { + protected void updateMainComponent(TypeDeclaration mainType, MethodDeclaration mainConstructor, Node componentNode, MethodDeclaration constructor, final List depends) { // Declare the field to refer to each object in the main type. ResourceNode resNode = null; String nodeName = null; @@ -302,7 +267,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. @@ -335,31 +300,31 @@ 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; } - protected void fillStateGetterMethod(MethodDeclaration stateGetter, ResourceHierarchy resourceHierarchy, Type resStateType, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + 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) { @@ -372,7 +337,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; @@ -380,7 +345,7 @@ composerSub.setType(DataConstraintModel.typeMap); for (ResourceHierarchy child: resourceHierarchy.getChildren()) { String childTypeName = getComponentName(child, langSpec); - String fieldName = langSpec.toVariableName(childTypeName); + String fieldName = child.getResourceName(); Term childGetter = null; if (!generatesComponent(child)) { // the child is not a class @@ -402,9 +367,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)); } } } @@ -412,7 +377,7 @@ } protected void fillDescendantGetterMethod(MethodDeclaration descendantGetter, ResourceHierarchy descendant, - ResourceHierarchy child, ResourceHierarchy ancestor, TypeDeclaration ancestorComponent, ILanguageSpecific langSpec) { + ResourceHierarchy child, ResourceHierarchy ancestor, TypeDeclaration ancestorComponent) { // (#4) descendant getter method (the implementation must be kept consistent with #3) Expression selector; if (DataConstraintModel.typeList.isAncestorOf(ancestor.getResourceStateType())) { @@ -420,7 +385,7 @@ } else if (DataConstraintModel.typeMap.isAncestorOf(ancestor.getResourceStateType())) { selector = new Variable(langSpec.getFieldAccessor(fieldOfResourceState)); } else { - String fieldName = langSpec.toVariableName(getComponentName(child, langSpec)); + String fieldName = child.getResourceName(); selector = new Variable(langSpec.getFieldAccessor(fieldName)); } if (descendantGetter.getParameters() != null) { @@ -442,11 +407,11 @@ 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)); } } - protected void declareAccessorInMainComponent(TypeDeclaration mainComponent, ResourceNode accessRes, MethodDeclaration stateGetter, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + protected void declareAccessorInMainComponent(TypeDeclaration mainComponent, ResourceNode accessRes, MethodDeclaration stateGetter) { List mainGetterParams = new ArrayList<>(); int v = 1; for (Expression param: accessRes.getPrimaryResourcePath().getPathParams()) { @@ -472,22 +437,21 @@ } 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); } - protected void declareFieldsToReferenceResources(DataTransferModel model, ResourceNode resourceNode, TypeDeclaration component, MethodDeclaration constructor, - final List depends, ILanguageSpecific langSpec) { + protected void declareFieldsToReferenceResources(DataTransferModel model, ResourceNode resourceNode, TypeDeclaration component, MethodDeclaration constructor, final List depends) { Set refs = new HashSet<>(); for (Channel ch : model.getChannels()) { DataTransferChannel c = (DataTransferChannel) ch; @@ -496,8 +460,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()); } } @@ -505,6 +469,10 @@ } } + protected String getUpdateMethodName(ResourceHierarchy srcRes, ResourceHierarchy dstRes, DataTransferChannel ch) { + return generationContext.getOrPutUpdateMethodName(srcRes, ch, dstRes); + } + protected MethodDeclaration getConstructor(TypeDeclaration component) { for (MethodDeclaration m: component.getMethods()) { if (m.isConstructor()) return m; @@ -712,109 +680,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; @@ -828,27 +813,45 @@ } 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; } - - protected IResourceStateAccessor getPushAccessor(IPlatformSpecific platformSpec) { + + protected void setFieldInitializer(FieldDeclaration field, Type type, Expression initialValue) { + String initializer = null; + if (initialValue != null) { + String sideEffects[] = new String[]{""}; + initializer = initialValue.toImplementation(sideEffects); + if (sideEffects[0] == null || sideEffects[0].length() == 0) { + field.setInitializer(initializer); + } else { + field.setInitializationBlock("{\n" + sideEffects[0] + field.getName() + " = " + initializer + ";\n" + "}\n"); + } + } else if (type != null) { + initializer = DataConstraintModel.getDefaultValue(type); + field.setInitializer(initializer); + } + } + + public IResourceStateAccessor getPushAccessor(IPlatformSpecific platformSpec) { if (platformSpec.isMonolithic()) { return new IResourceStateAccessor() { @Override @@ -925,7 +928,7 @@ } } - protected IResourceStateAccessor getPullAccessor(IPlatformSpecific platformSpec) { + public IResourceStateAccessor getPullAccessor(IPlatformSpecific platformSpec) { if (platformSpec.isMonolithic()) { return new IResourceStateAccessor() { @Override @@ -1028,7 +1031,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) { @@ -1147,7 +1150,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) { @@ -1208,7 +1211,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 9808d10..36a2680 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; @@ -58,14 +49,20 @@ import models.dataFlowModel.ChannelNode; import models.dataFlowModel.StoreAttribute; import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; +import simulator.ResourceIdentifier; public class CodeGeneratorFromDataFlowGraph extends CodeGenerator { + protected Map> constructorParams; + + public CodeGeneratorFromDataFlowGraph(IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + super(platformSpec, langSpec); + } public void generateCodeFromFlowGraph(DataTransferModel model, IFlowGraph flowGraph, Collection> components, ArrayList codes, - Map> dependedRootComponentGraph, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { - Map resourceComponents = new HashMap<>(); + Map> dependedRootComponentGraph) { + constructorParams = new HashMap<>(); + Map resourceConstructors = new HashMap<>(); - Map> constructorParams = new HashMap<>(); List> constructorStatements = new ArrayList<>(); Map>> updateStatements = new HashMap<>(); Map> descendantGetters = new HashMap<>(); @@ -87,23 +84,24 @@ for (Set componentNodeSet: components) { Node componentNode = componentNodeSet.iterator().next(); ResourceNode resourceNode = (ResourceNode) componentNode; + ResourceHierarchy resourceHierarchy = resourceNode.getResourceHierarchy(); TypeDeclaration component = null; - if (generatesComponent(resourceNode.getResourceHierarchy())) { + if (generatesComponent(resourceHierarchy)) { // A component will be generated for this resource. - String resourceName = getComponentName(resourceNode.getResourceHierarchy(), langSpec); - Type resStateType = getImplStateType(resourceNode.getResourceHierarchy(), langSpec); - component = resourceComponents.get(resourceNode.getResourceHierarchy()); + String resourceName = getComponentName(resourceHierarchy, langSpec); + Type resStateType = getImplStateType(resourceHierarchy, langSpec); + component = generationContext.getComponent(resourceHierarchy); List depends = new ArrayList<>(); if (component == null) { // Add compilation unit for this component. component = langSpec.newTypeDeclaration(resourceName); - if (!platformSpec.isMonolithic() && resourceNode.getResourceHierarchy().getParent() == null) { + if (!platformSpec.isMonolithic() && resourceHierarchy.getParent() == null) { // For each root node, add component annotations. ((RestApiSpecific) platformSpec).addComponentAnnotations(component, resourceNode.getResourceName()); } - resourceComponents.put(resourceNode.getResourceHierarchy(), component); + generationContext.putComponent(resourceHierarchy, component); CompilationUnit cu = langSpec.newCompilationUnit(component); - if (!platformSpec.isMonolithic() && resourceNode.getResourceHierarchy().getParent() == null) { + if (!platformSpec.isMonolithic() && resourceHierarchy.getParent() == null) { // For each root node, add platform specific imports. ((RestApiSpecific) platformSpec).addPlatformSpecificImports(cu); } @@ -113,40 +111,43 @@ // For monolithic applications (components are tightly coupled and must be built together). // Declare the constructor. - MethodDeclaration constructor = declareConstructor(resourceNode, component, dependedRootComponentGraph, depends, langSpec); + MethodDeclaration constructor = declareConstructor(resourceNode, component, dependedRootComponentGraph, depends); - if (platformSpec.hasMain() && resourceNode.getResourceHierarchy().getParent() == null) { + if (platformSpec.hasMain() && resourceHierarchy.getParent() == null) { // For each root resource // Update the main component for this component. - updateMainComponent(mainComponent, mainConstructor, componentNode, constructor, depends, langSpec); + updateMainComponent(mainComponent, mainConstructor, componentNode, constructor, depends); } // Declare the fields to refer to reference resources. - declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends, langSpec); + declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends); if (constructor.getParameters() == null || constructor.getParameters().size() == 0) { component.removeMethod(constructor); } else { - resourceConstructors.put(resourceNode.getResourceHierarchy(), constructor); + resourceConstructors.put(resourceHierarchy, constructor); } } // Declare the field to store the state in this resource. if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { - declareStateField(resourceNode, resourceName, component, resStateType, constructorParams, langSpec); + declareStateField(resourceNode, resourceName, component, resStateType); } // Declare the getter method in this resource to obtain the state. - MethodDeclaration stateGetter = declareStateGetterMethod(resourceNode, component, resStateType, platformSpec, langSpec); + MethodDeclaration stateGetter = declareStateGetterMethod(resourceNode, component, resStateType); // Declare the accessor method in the main component to call the getter method. if (platformSpec.hasMain()) { - declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter, platformSpec, langSpec); + declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter); } } if (component != null) { + 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, langSpec); + declareDescendantGetterMethods(resourceNode, component, descendantGetters); } } } @@ -158,70 +159,76 @@ Node componentNode = componentNodeSet.iterator().next(); // Declare this resource. ResourceNode resourceNode = (ResourceNode) componentNode; - Type resStateType = getImplStateType(resourceNode.getResourceHierarchy(), langSpec); + ResourceHierarchy resourceHierarchy = resourceNode.getResourceHierarchy(); + Type resStateType = getImplStateType(resourceHierarchy, langSpec); + String resourceName = getComponentName(resourceHierarchy, langSpec); TypeDeclaration component = null; TypeDeclaration parentComponent = null; TypeDeclaration rootComponent = null; - if (generatesComponent(resourceNode.getResourceHierarchy())) { - component = resourceComponents.get(resourceNode.getResourceHierarchy()); + if (generatesComponent(resourceHierarchy)) { + component = generationContext.getComponent(resourceHierarchy); } - if (resourceNode.getResourceHierarchy().getParent() != null) { - parentComponent = resourceComponents.get(resourceNode.getResourceHierarchy().getParent()); + if (resourceHierarchy.getParent() != null) { + parentComponent = generationContext.getComponent(resourceHierarchy.getParent()); } - rootComponent = resourceComponents.get(resourceNode.getResourceHierarchy().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 - = declareCacheFieldsAndUpdateMethods(resourceNode, component, parentComponent, rootComponent, platformSpec, langSpec); + = declareCacheFieldsAndUpdateMethods(resourceNode, component, parentComponent, rootComponent); if (component == null) { // Constructor statements were not added to any component because no component had been generated. for (String statement: initStatementsAndUpdateUpdates.getKey()) { - constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), statement)); + constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceHierarchy.getParent(), statement)); } } for (Map.Entry>> entry: initStatementsAndUpdateUpdates.getValue().entrySet()) { - updateStatements.put(entry.getKey(), entry.getValue()); + Map.Entry> updateInfo = entry.getValue(); + updateStatements.put(entry.getKey(), updateInfo); +// extractConstructorParameterFromUpdateExpression(updateInfo, constructorParams, langSpec); } // Declare the fields to refer to other resources for push/pull transfer in the parent/this component, and the state field in the parent component. - declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(resourceNode, component, parentComponent, constructorParams, platformSpec, langSpec); + declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(resourceNode, component, parentComponent); // (#2) Declare the getter method to obtain the resource state in an ancestor resource. (complementary to #1) if (component == null) { - MethodDeclaration stateGetter = declareStateGetterMethodInAncestor(resourceNode, resourceComponents, resStateType, platformSpec, langSpec); + MethodDeclaration stateGetter = declareStateGetterMethodInAncestor(resourceNode, resStateType); if (stateGetter != null && platformSpec.hasMain()) { // Declare the accessor method in the main component to call the getter method. - declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter, platformSpec, langSpec); + declareAccessorInMainComponent(mainComponent, resourceNode, stateGetter); } } - if (!platformSpec.isMonolithic() && !generatedResources.contains(resourceNode.getResourceHierarchy())) { + if (!platformSpec.isMonolithic() && !generatedResources.contains(resourceHierarchy)) { // Declare the getter accessor in the root resource. - declareGetterAccessorInTheRootResource(resourceNode, rootComponent, platformSpec, langSpec); + declareGetterAccessorInTheRootResource(resourceNode, rootComponent); } // Declare input methods in this component and the main component. - if (!generatedResources.contains(resourceNode.getResourceHierarchy())) { + if (!generatedResources.contains(resourceHierarchy)) { Map.Entry, Map>>> initStatementsAndInputUpdates - = declareInputMethodsInThisAndMainComponents(resourceNode, component, parentComponent, mainComponent, rootComponent, model, priorMemberForInputChannel, platformSpec, langSpec); + = declareInputMethodsInThisAndMainComponents(resourceNode, component, parentComponent, mainComponent, rootComponent, model, priorMemberForInputChannel); if (component == null) { // Constructor statements were not added to any component because no component had been generated. for (String statement: initStatementsAndInputUpdates.getKey()) { - constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceNode.getResourceHierarchy().getParent(), statement)); + constructorStatements.add(new AbstractMap.SimpleEntry<>(resourceHierarchy.getParent(), statement)); } } for (Map.Entry>> entry: initStatementsAndInputUpdates.getValue().entrySet()) { - updateStatements.put(entry.getKey(), entry.getValue()); + Map.Entry> updateInfo = entry.getValue(); + updateStatements.put(entry.getKey(), updateInfo); +// extractConstructorParameterFromUpdateExpression(updateInfo, constructorParams, langSpec); } } - generatedResources.add(resourceNode.getResourceHierarchy()); + generatedResources.add(resourceHierarchy); } // Add constructor parameters to the ancestor components. for (ResourceNode root: ((DataFlowGraph) flowGraph).getRootResourceNodes()) { - addConstructorParameters(root.getResourceHierarchy(), resourceComponents, resourceConstructors, constructorParams, langSpec); + addConstructorParameters(root.getResourceHierarchy(), resourceConstructors); } // Add constructor statements. @@ -234,16 +241,48 @@ Expression updateExp = updateStatements.get(method).getKey(); ResourceHierarchy resource = updateStatements.get(method).getValue().getKey(); ResourceHierarchy descendantRes = updateStatements.get(method).getValue().getValue(); - TypeDeclaration descendantComponent = resourceComponents.get(descendantRes); - addUpdateStatementWithConstructorInvocationToMethod(method, updateExp, resource, descendantRes, descendantComponent, langSpec); + TypeDeclaration descendantComponent = generationContext.getComponent(descendantRes); + addUpdateStatementWithConstructorInvocationToMethod(method, updateExp, resource, descendantRes, descendantComponent); } } - private static List addConstructorParameters(ResourceHierarchy resource, Map resourceComponents, - Map resourceConstructors, Map> constructorParams, ILanguageSpecific langSpec) { + private void extractConstructorParameterFromUpdateExpression( + Map.Entry> updateInfo, + Map> constructorParams, ILanguageSpecific langSpec) { + Expression updateExp = updateInfo.getKey(); + ResourceHierarchy newResource = updateInfo.getValue().getValue(); + if (updateExp instanceof Term) { + Map subTerms = ((Term) updateExp).getSubTerms(Term.class); + for (Term term: subTerms.values()) { + if (term.getType() != null) { + if (term.getType().equals(newResource.getResourceStateType())) { + if (term instanceof JsonTerm) { + JsonTerm jsonTerm = (JsonTerm) term; + for (String key: jsonTerm.keySet()) { + Map params = constructorParams.getOrDefault(newResource, new HashMap<>()); + Expression member = jsonTerm.get(key); + if (member != null && member instanceof Term) { + if (!params.containsKey(key) && ((Term) member).getType() != null) { + params.put(key, new VariableDeclaration(((Term) member).getType(), key)); + } + } else if (member != null && member instanceof Variable) { + if (!params.containsKey(key) && ((Variable) member).getType() != null) { + params.put(key, langSpec.newVariableDeclaration(((Variable) member).getType(), key)); + } + } + constructorParams.put(newResource, params); + } + } + } + } + } + } + } + + private List addConstructorParameters(ResourceHierarchy resource, Map resourceConstructors) { List params = new ArrayList<>(); for (ResourceHierarchy child: resource.getChildren()) { - params.addAll(addConstructorParameters(child, resourceComponents, resourceConstructors, constructorParams, langSpec)); + params.addAll(addConstructorParameters(child, resourceConstructors)); } if (constructorParams.get(resource) != null) { for (VariableDeclaration param: constructorParams.get(resource).values()) { @@ -253,12 +292,12 @@ if (params.size() > 0) { MethodDeclaration constructor = resourceConstructors.get(resource); if (constructor == null) { - if (resourceComponents.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); - resourceComponents.get(resource).addMethod(constructor); + generationContext.getComponent(resource).addMethod(constructor); resourceConstructors.put(resource, constructor); } } @@ -276,6 +315,15 @@ if (!existsParam) { 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: generationContext.getComponent(resource).getFields()) { + if (field.getName().equals(param.getName())) { + existsField = true; + } + } + if (!existsField) { + generationContext.getComponent(resource).addField(langSpec.newFieldDeclaration(param.getType(), param.getName())); + } } } } @@ -284,18 +332,20 @@ return params; } - private void addUpdateStatementWithConstructorInvocationToMethod(MethodDeclaration method, Expression exp, ResourceHierarchy resource, ResourceHierarchy descendantRes, TypeDeclaration descendantComponent, ILanguageSpecific langSpec) { + private void addUpdateStatementWithConstructorInvocationToMethod(MethodDeclaration method, Expression exp, ResourceHierarchy resource, ResourceHierarchy descendantRes, TypeDeclaration descendantComponent) { // 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<>(); @@ -322,17 +372,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); } @@ -363,11 +420,10 @@ } else { updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); } - method.addFirstStatement(updateStatement); + method.addStatement(updateStatement); } - private MethodDeclaration declareConstructor(ResourceNode resourceNode, TypeDeclaration component, Map> dependedRootComponentGraph, - List depends, ILanguageSpecific langSpec) { + private MethodDeclaration declareConstructor(ResourceNode resourceNode, TypeDeclaration component, Map> dependedRootComponentGraph, List depends) { // Declare a constructor in each component. String resourceName = getComponentName(resourceNode.getResourceHierarchy(), langSpec); MethodDeclaration constructor = langSpec.newMethodDeclaration(resourceName, true, null, null); @@ -464,11 +520,12 @@ return constructor; } - private void declareStateField(ResourceNode resourceNode, String resourceName, TypeDeclaration component, Type resStateType, Map> constructorParams, ILanguageSpecific langSpec) { + private void declareStateField(ResourceNode resourceNode, String resourceName, TypeDeclaration component, Type resStateType) { Set children = resourceNode.getResourceHierarchy().getChildren(); if (children == null || children.size() == 0) { // leaf resource. - FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, resourceNode.getResourceHierarchy().getInitialValue())); + FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState); + setFieldInitializer(stateField, resStateType, resourceNode.getResourceHierarchy().getInitialValue()); component.addField(stateField); // Add a parameter to initialize the state field to the constructor. // Map nameToParam = constructorParams.get(resourceNode.getResourceHierarchy()); @@ -484,7 +541,8 @@ ResourceHierarchy child = children.iterator().next(); if (children.size() == 1 && child.getNumParameters() > 0) { // map or list. - FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, resourceNode.getResourceHierarchy().getInitialValue())); + FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState); + setFieldInitializer(stateField, resStateType, resourceNode.getResourceHierarchy().getInitialValue()); component.addField(stateField); } else { // class @@ -493,8 +551,8 @@ Type childType = null; if (generatesComponent(c)) { // The child has a component. - childType = new Type(childTypeName, childTypeName); - String fieldName = langSpec.toVariableName(childTypeName); + childType = generationContext.getOrCreateComponentType(childTypeName); + String fieldName = c.getResourceName(); FieldDeclaration stateField = langSpec.newFieldDeclaration(childType, fieldName, langSpec.getConstructorInvocation(childTypeName, new ArrayList<>())); component.addField(stateField); } @@ -503,8 +561,7 @@ } } - private void declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, - Map> constructorParams, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + private void declareFieldsToReferToOtherResourcesAndStateFieldInParentComponent(ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent) { // Declare reference fields for push data transfer. boolean noPullTransfer = true; for (Edge resToCh : resourceNode.getOutEdges()) { @@ -561,8 +618,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) @@ -609,7 +666,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); @@ -711,8 +768,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) @@ -760,7 +817,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); @@ -840,8 +897,7 @@ } - private MethodDeclaration declareStateGetterMethod(ResourceNode resourceNode, TypeDeclaration component, Type resStateType, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + private MethodDeclaration declareStateGetterMethod(ResourceNode resourceNode, TypeDeclaration component, Type resStateType) { // Declare the getter method of the resource state. MethodDeclaration stateGetter = langSpec.newMethodDeclaration(getterOfResourceState, resStateType); if (!platformSpec.isMonolithic() && resourceNode.getResourceHierarchy().getParent() == null) { @@ -852,10 +908,10 @@ boolean hasDescendantIn = hasDescendantInput(resourceNode); if (((StoreAttribute) resourceNode.getAttribute()).isStored() && !hasDescendantIn) { - fillStateGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resStateType, platformSpec, langSpec); + fillStateGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), resStateType); } else { // invocations to other getter methods when at least one incoming data-flow edges is PULL-style. - if (addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode, platformSpec, langSpec)) { + if (addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode)) { // Declare a client field to connect to the destination resource of push transfer. if (!((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); @@ -866,8 +922,7 @@ return stateGetter; } - private MethodDeclaration declareStateGetterMethodInAncestor(ResourceNode resourceNode, Map resourceComponents, Type resStateType, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + private MethodDeclaration declareStateGetterMethodInAncestor(ResourceNode resourceNode, Type resStateType) { // Search an ancestor in which the getter method is declared. ResourceNode ancestorNode = resourceNode; ResourceNode childNode = null; @@ -877,7 +932,7 @@ childNode = ancestorNode; ancestorNode = ancestorNode.getParent(); } while (!generatesComponent(ancestorNode.getResourceHierarchy())); - TypeDeclaration ancestorComponent = resourceComponents.get(ancestorNode.getResourceHierarchy()); + TypeDeclaration ancestorComponent = generationContext.getComponent(ancestorNode.getResourceHierarchy()); List getterParams = new ArrayList<>(); int v = 1; while (ancestors.size() > 0) { @@ -912,9 +967,9 @@ boolean hasDescendantIn = hasDescendantInput(resourceNode); if (((StoreAttribute) resourceNode.getAttribute()).isStored() && !hasDescendantIn) { - fillDescendantGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), childNode.getResourceHierarchy(), ancestorNode.getResourceHierarchy(), ancestorComponent, langSpec); + fillDescendantGetterMethod(stateGetter, resourceNode.getResourceHierarchy(), childNode.getResourceHierarchy(), ancestorNode.getResourceHierarchy(), ancestorComponent); } else { - if (addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode, platformSpec, langSpec)) { + if (addOtherGetterInvocationsToStateGatter(stateGetter, resourceNode)) { // Declare a client field to connect to the destination resource of push transfer. if (ancestorComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(ancestorComponent)) { ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(ancestorComponent); @@ -940,8 +995,7 @@ return hasDescendantIn; } - private boolean addOtherGetterInvocationsToStateGatter(MethodDeclaration stateGetter, ResourceNode resourceNode, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + private boolean addOtherGetterInvocationsToStateGatter(MethodDeclaration stateGetter, ResourceNode resourceNode) { boolean bDeclareClientField = false; try { // Data transfer on the same channel hierarchy. @@ -981,9 +1035,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; } } @@ -1016,9 +1070,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; } } @@ -1054,7 +1108,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; } } @@ -1080,12 +1134,12 @@ Type srcResType2 = src2.getResourceStateType(); 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) + String srcGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(src2, resourceNode.getInSideResource(curChannel)).toImplementation(new String[] {""}); + 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 { @@ -1097,12 +1151,12 @@ Type srcResType2 = src2.getResourceStateType(); 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) + String dependingGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(src2, resourceNode.getInSideResource(curChannel)).toImplementation(new String[] {""}); + 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; } } @@ -1151,10 +1205,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()) { @@ -1184,9 +1238,9 @@ Expression parentGetter = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, dstResPath); Term valueGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); valueGetter.addChild(parentGetter); - parent = valueGetter.toImplementation(new String[] {}); + parent = valueGetter.toImplementation(new String[] {""}); } else { - parent = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, dstResPath).toImplementation(new String[] {}); + parent = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, dstResPath).toImplementation(new String[] {""}); } } else { // for REST API @@ -1194,10 +1248,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 @@ -1206,18 +1266,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(); @@ -1229,7 +1287,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(); @@ -1237,7 +1295,7 @@ return bDeclareClientField; } - private void declareDescendantGetterMethods(ResourceNode resourceNode, TypeDeclaration component, Map> descendantGetters, ILanguageSpecific langSpec) { + private void declareDescendantGetterMethods(ResourceNode resourceNode, TypeDeclaration component, Map> descendantGetters) { // Declare the getter methods in this resource to obtain descendant resources. Set descendants = descendantGetters.get(resourceNode.getResourceHierarchy()); if (descendants == null) { @@ -1267,7 +1325,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); @@ -1275,7 +1333,7 @@ descendantGetter = langSpec.newMethodDeclaration(getterPrefix + descendantCompName, false, descendantType, params); } - fillDescendantGetterMethod(descendantGetter, descendant.getResourceHierarchy(), child.getResourceHierarchy(), resourceNode.getResourceHierarchy(), component, langSpec); + fillDescendantGetterMethod(descendantGetter, descendant.getResourceHierarchy(), child.getResourceHierarchy(), resourceNode.getResourceHierarchy(), component); component.addMethod(descendantGetter); } break; @@ -1285,10 +1343,9 @@ } } - private Map.Entry, Map>>> declareCacheFieldsAndUpdateMethods(ResourceNode resourceNode, - TypeDeclaration component, TypeDeclaration parentComponent, TypeDeclaration rootComponent, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + private Map.Entry, Map>>> declareCacheFieldsAndUpdateMethods( + ResourceNode resourceNode, TypeDeclaration component, TypeDeclaration parentComponent, TypeDeclaration rootComponent) { // Declare cash fields and update methods in the component. - String resComponentName = getComponentName(resourceNode.getResourceHierarchy(), langSpec); List constructorStatements = new ArrayList<>(); Map>> updateStatements = new HashMap<>(); for (Edge chToRes: resourceNode.getInEdges()) { @@ -1311,8 +1368,7 @@ ChannelNode indirectSrcChNode = (ChannelNode) re.getDestination(); DataTransferChannel indirectSrcCh = indirectSrcChNode.getChannel(); ResourcePath srcResPath = ((ResourceNode) re.getSource()).getOutSideResource(indirectSrcCh); - String srcResComponentName = getComponentName(srcResPath.getResourceHierarchy(), langSpec); - String srcResName = langSpec.toVariableName(srcResComponentName); + String srcResName = langSpec.toVariableName(getComponentName(srcResPath.getResourceHierarchy(), langSpec)); // Check if the input resource is outside of the channel scope. boolean outsideInputResource = false; for (ChannelMember cm: indirectSrcCh.getInputChannelMembers()) { @@ -1351,10 +1407,6 @@ && (outsideOutputResource || (resourceNode.getInSideResource(ch).getCommonPrefix(srcResPath) == null && platformSpec.isDifferentTreesAsDifferentServices()))) { // Inter-service hasRestAPI = true; - if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { - // Declare a client field to connect to the destination resource of push transfer. - ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); - } if (resourceNode.getParent() == null) { // A root resource isRestAPI = true; @@ -1383,28 +1435,9 @@ parameters.add(param); } } - MethodDeclaration update = null; - if (component != null) { - for (MethodDeclaration method: component.getMethods()) { - if (method.getName().equals(updateMethodPrefix + from + srcResComponentName)) { - update = method; - break; - } - } - if (update == null) { - update = langSpec.newMethodDeclaration(updateMethodPrefix + from + srcResComponentName, false, null, parameters); - } - } else if (parentComponent != null) { - for (MethodDeclaration method: parentComponent.getMethods()) { - if (method.getName().equals(updateMethodPrefix + resComponentName + from + srcResComponentName)) { - update = method; - break; - } - } - if (update == null) { - update = langSpec.newMethodDeclaration(updateMethodPrefix + resComponentName + from + srcResComponentName, false, null, parameters); - } - } + // Get or declare the update method. + MethodDeclaration update = getOrDeclareUpdateMethod(srcResPath.getResourceHierarchy(), resourceNode.getResourceHierarchy(), ch, parameters); + // Calculate in-degree (PUSH transfer) of the destination resource. int inDegree = 0; for (Edge resToCh2: inEdges) { @@ -1429,92 +1462,6 @@ if (isRestAPI) ((RestApiSpecific) platformSpec).addPathAnnotation(update, "/" + srcResName); } } - if (update != null) { - if (component != null) { - // A component is created for this resource. - component.addMethod(update); - } else if (parentComponent != null) { - // No component is created for this resource. - parentComponent.addMethod(update); - } - } - // For a post/put REST API. - if (hasRestAPI) { - if (!isRestAPI) { - // If not a root resource. - // Declare an update accessor method in the type of root resource. - declareUpdateAccessorInTheRootResource(resourceNode, update.getName(), ch, out, srcResPath, dstResPath, - rootComponent, inDegree, platformSpec, langSpec); - } - // to convert a json param to a tuple, pair or map object. - for (VariableDeclaration jsonParam: update.getParameters()) { - 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. - } - } else if (DataConstraintModel.typeTuple.isAncestorOf(paramType)) { - jsonParam.setType(DataConstraintModel.typeString); - jsonParam.setName(paramName + "_json"); - paramConverter += langSpec.getVariableDeclaration(paramTypeName, 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"; - 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.getOpeningScoreDelimiter() + "\n"; - String mapTypeName = convertFromEntryToMapType(paramType, langSpec); - paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapTypeName) + 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.getOpeningScoreDelimiter() + "\n"; - String mapTypeName = convertFromEntryToMapType(paramType, langSpec); - paramConverter += "\t" + ((RestApiSpecific) platformSpec).getConversionFromJsonString(paramName + "_json", "i", mapTypeName) + langSpec.getStatementDelimiter() + "\n"; - paramConverter += "\t" + getCodeForConversionFromMapToMap(paramType, "i", paramName, langSpec) + "\n"; - paramConverter += langSpec.getClosingScoreDelimiter(); - ((RestApiSpecific) platformSpec).addJsonException(update); - } - if (paramConverter.length() > 0 && !update.getBody().getStatements().contains(paramConverter)) { - update.addFirstStatement(paramConverter); - } - } - } // Add a statement to update the state field if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { @@ -1564,6 +1511,7 @@ do { descendantRes = children.iterator().next(); if (generatesComponent(descendantRes)) { + // If there exists at least one descendant resource whose component is not to be generated. updateStatements.put(update, new AbstractMap.SimpleEntry<>(updateExp, new AbstractMap.SimpleEntry<>(outRes, descendantRes))); updateExp = null; break; @@ -1571,105 +1519,110 @@ children = descendantRes.getChildren(); } while (children != null && children.size() == 1); } - // Replace the type of the state field. - Type fieldType = getImplStateType(outRes, langSpec); - if (updateExp instanceof Term) { - ((Term) updateExp).setType(fieldType); - for (Map.Entry varEnt: ((Term) updateExp).getVariables().entrySet()) { - if (varEnt.getValue().getName().equals(fieldOfResourceState)) { - varEnt.getValue().setType(fieldType); + // Add statements to the update method. + if (updateExp != null) { + // Replace the type of the state field. + Type fieldType = getImplStateType(outRes, langSpec); + if (updateExp instanceof Term) { + ((Term) updateExp).setType(fieldType); + for (Map.Entry varEnt: ((Term) updateExp).getVariables().entrySet()) { + if (varEnt.getValue().getName().equals(fieldOfResourceState)) { + 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++; } } - } 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 (generatesComponent(outRes)) { - if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { - updateStatement = sideEffects[0]; - if (updateStatement.endsWith("\n")) { - updateStatement = updateStatement.substring(0, updateStatement.length() - 1); + String updateStatement = ""; + if (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] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); // this.value = ... } } else { - updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); // this.value = ... - } - } else { - if (sideEffects[0] != null) { - updateStatement = sideEffects[0]; - String resourceName = langSpec.toVariableName(getComponentName(outRes, langSpec)); - updateStatement = updateStatement.replace(langSpec.getFieldAccessor(fieldOfResourceState), langSpec.getFieldAccessor(resourceName)); - if (updateStatement.endsWith("\n")) { - updateStatement = updateStatement.substring(0, updateStatement.length() - 1); + if (sideEffects[0] != null) { + updateStatement = sideEffects[0]; + String resourceName = langSpec.toVariableName(getComponentName(outRes, langSpec)); + updateStatement = updateStatement.replace(langSpec.getFieldAccessor(fieldOfResourceState), langSpec.getFieldAccessor(resourceName)); + if (updateStatement.endsWith("\n")) { + updateStatement = updateStatement.substring(0, updateStatement.length() - 1); + } + } + if (DataConstraintModel.typeList.isAncestorOf(resourceNode.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.set); + selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); + 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(resourceNode.getParent().getResourceStateType())) { + Term selector = new Term(DataConstraintModel.insert); + selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); + 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())) { + String resourceName = langSpec.toVariableName(getComponentName(outRes, langSpec)); + updateStatement += langSpec.getFieldAccessor(resourceName) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); } } - if (DataConstraintModel.typeList.isAncestorOf(resourceNode.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.set); - selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); - 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(resourceNode.getParent().getResourceStateType())) { - Term selector = new Term(DataConstraintModel.insert); - selector.addChild(new Constant(langSpec.getFieldAccessor(fieldOfResourceState))); - 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())) { - String resourceName = langSpec.toVariableName(getComponentName(outRes, langSpec)); - updateStatement += langSpec.getFieldAccessor(resourceName) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); - } - } - // add an update statement of the state of dst side resource. - if (numOfOutResourcesWithTheSameHierarchy == 1) { - update.addFirstStatement(updateStatement); - } else { - Term conditions = null; - int i = 1; - Map>> resourcePaths = ch.fillOutsideResourcePaths(out, getPushAccessor(platformSpec)); - 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; + // add an update statement of the state of dst side resource. + if (numOfOutResourcesWithTheSameHierarchy == 1) { + update.addFirstStatement(updateStatement); + } else { + Term conditions = null; + int i = 1; + Map>> resourcePaths = ch.fillOutsideResourcePaths(out, getPushAccessor(platformSpec)); + 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(i - 1); + } + Term condition = new Term(DataConstraintModel.eq, new Expression[] { + new Parameter("self" + (i > 1 ? i : ""), DataConstraintModel.typeString), + arg}); + if (conditions == null) { + conditions = condition; + } else { + conditions = new Term(DataConstraintModel.and, new Expression[] { + conditions, + condition}); + } } - if (arg == null) { - ResourcePath filledPath = resourcePaths.get(out).getKey(); - arg = filledPath.getPathParams().get(i - 1); - } - Term condition = new Term(DataConstraintModel.eq, new Expression[] { - new Parameter("self" + (i > 1 ? i : ""), DataConstraintModel.typeString), - arg}); - if (conditions == null) { - conditions = condition; - } else { - conditions = new Term(DataConstraintModel.and, new Expression[] { - conditions, - condition}); - } + i++; } - i++; + Block ifBlock = new Block(); + ifBlock.addStatement(updateStatement); + update.addFirstStatement(langSpec.getIfStatement(conditions, ifBlock)); } - update.addFirstStatement(langSpec.getIfStatement(conditions, updateStatement)); } } } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork @@ -1678,6 +1631,89 @@ } } + // For a post/put REST API. + if (hasRestAPI) { + if (!isRestAPI) { + // If not a root resource. + // Declare an update accessor method in the type of root resource. + declareUpdateAccessorInTheRootResource(resourceNode, update.getName(), ch, out, srcResPath, dstResPath, + rootComponent, inDegree, platformSpec, langSpec); + } + // to convert a json param to a tuple, pair or map object. + for (VariableDeclaration jsonParam: update.getParameters()) { + Type paramType = jsonParam.getType(); + String paramName = jsonParam.getName(); + String paramTypeName = paramType.getInterfaceTypeName(); + String paramConverter = ""; + if (DataConstraintModel.typeList.isAncestorOf(paramType) && paramType != DataConstraintModel.typeList) { + 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.newVariableDeclaration(paramType, paramName) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getOpeningScoreDelimiter() + "\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.newVariableDeclaration(paramType, paramName) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getOpeningScoreDelimiter() + "\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.newVariableDeclaration(paramType, paramName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(paramType.getImplementationTypeName(), null) + langSpec.getStatementDelimiter() + "\n"; + paramConverter += langSpec.getOpeningScoreDelimiter() + "\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); + } + if (paramConverter.length() > 0 && (update.getBody() == null || !update.getBody().getStatements().contains(paramConverter))) { + update.addFirstStatement(paramConverter); + } + } + } + // Declare the field to cache the state of the source resource in the type of the destination resource. if (inDegree > 1 || (ch.getInputChannelMembers().size() == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { @@ -1685,10 +1721,8 @@ if (langSpec.declareField()) { // Declare the cache field. String cacheFieldName = langSpec.toVariableName(getComponentName(srcResPath.getResourceHierarchy(), langSpec)); - FieldDeclaration cacheField = langSpec.newFieldDeclaration( - srcResPath.getResourceStateType(), - cacheFieldName, - langSpec.getFieldInitializer(srcResPath.getResourceStateType(), srcResPath.getResourceHierarchy().getInitialValue())); + FieldDeclaration cacheField = langSpec.newFieldDeclaration(srcResPath.getResourceStateType(), cacheFieldName); + setFieldInitializer(cacheField, srcResPath.getResourceStateType(), srcResPath.getResourceHierarchy().getInitialValue()); if (component != null) { component.addField(cacheField); } else if (parentComponent != null){ @@ -1820,8 +1854,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) { @@ -1829,7 +1862,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()) { @@ -1867,9 +1900,9 @@ Expression getter = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, resourceNode.getOutSideResource(directDstCh)); Term valueGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); valueGetter.addChild(getter); - parent = valueGetter.toImplementation(new String[] {}); + parent = valueGetter.toImplementation(new String[] {""}); } else { - parent = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, resourceNode.getOutSideResource(directDstCh)).toImplementation(new String[] {}); + parent = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, resourceNode.getOutSideResource(directDstCh)).toImplementation(new String[] {""}); } } else { // for REST API @@ -1877,12 +1910,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 @@ -1891,7 +1928,14 @@ 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); + } else if (parentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); + } } } } else if (selExp instanceof Term) { @@ -1925,12 +1969,19 @@ 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); + } else if (parentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); + } } else { 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()); } } @@ -1939,190 +1990,25 @@ refVarName))); } } - List>> pathParams = new ArrayList<>(); - if (platformSpec.isMonolithic()) { - // Update fields to refer to outside resources. - ResourcePath filledOutsideResourcePath = null; - try { - Map>> resourcePaths = ch2.fillOutsideResourcePaths(out1, getPullAccessor(platformSpec)); - if (resourcePaths != null && resourcePaths.size() > 0) { - for (ChannelMember outsideMember: resourcePaths.keySet()) { - ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); - if (out1.equals(outsideMember)) { - filledOutsideResourcePath = outsidePath; - } - if (!generatesComponent(outsidePath.getResourceHierarchy())) { - outsidePath = outsidePath.getParent(); - } - String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); - Expression outsideExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(outsidePath, null); - if (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); - update.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. - } - } - } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork - | InvalidMessage | UnificationFailed | ValueUndefined e) { - e.printStackTrace(); - } - // Values of path parameters to call the update method. - if (filledOutsideResourcePath == null) { - filledOutsideResourcePath = out1.getResource(); - } - for (Expression pathParam: filledOutsideResourcePath.getPathParams()) { - if (pathParam instanceof Variable) { - Variable pathVar = (Variable) pathParam; - pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), - new AbstractMap.SimpleEntry<>(pathVar.getName(), - pathVar.getName()))); - } else if (pathParam instanceof Constant) { - Constant pathVar = (Constant) pathParam; - pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), - new AbstractMap.SimpleEntry<>(pathVar.getSymbol().getName(), - pathVar.getSymbol().getName()))); - } - } - } else { - // Values of path parameters to call the update method. - for (Expression pathParam: out1.getResource().getPathParams()) { - if (pathParam instanceof Variable) { - Variable pathVar = (Variable) pathParam; - pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), - new AbstractMap.SimpleEntry<>(pathVar.getName(), - pathVar.getName()))); - } - } - } - // Values of channel parameters to call the update method. - List>> params = new ArrayList<>(); - for (Selector selector: ch2.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 to call the update method. - ResourceHierarchy srcRes2 = resourceNode.getResourceHierarchy(); - if (generatesComponent(srcRes2)) { - params.add(new AbstractMap.SimpleEntry<>(srcRes2.getResourceStateType(), - new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes2.getResourceName()), - langSpec.getFieldAccessor(fieldOfResourceState)))); - } else { - params.add(new AbstractMap.SimpleEntry<>(srcRes2.getResourceStateType(), - new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes2.getResourceName()), - langSpec.getFieldAccessor(langSpec.toVariableName(srcRes2.getResourceName()))))); - srcRes2 = srcRes2.getParent(); - } - params.addAll(refParams); - // Call the update method. - String updateMethodName = null; - ResourceHierarchy dstRes = dstNode.getResourceHierarchy(); - if (!generatesComponent(dstRes)) { - updateMethodName = updateMethodPrefix + getComponentName(dstRes, langSpec) + from + resComponentName; - dstRes = dstRes.getParent(); - } else { - updateMethodName = updateMethodPrefix + from + resComponentName; - } - String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); - if (outsideOutputResource2 - || (!platformSpec.isMonolithic() && in.getResource().getCommonPrefix(out1.getResource()) == null && platformSpec.isDifferentTreesAsDifferentServices())) { - // Inter-servces - if (!platformSpec.isMonolithic()) { - // REST API - RestApiSpecific restApiSpec = (RestApiSpecific) platformSpec; - String httpMethod = null; - if (out1.getStateTransition().isRightUnary()) { - httpMethod = "put"; - } else { - httpMethod = "post"; - } - String[] sideEffects = new String[] {""}; - List pathParamsUrl = new ArrayList<>(); - for (Expression pathExp: out1.getResource().getPathParams()) { - pathParamsUrl.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); - } - String resName = langSpec.toVariableName(resComponentName); - if (inDegree <= 1) { - resName = null; - } - Map>> filledPaths = null; - try { - filledPaths = ch2.fillOutsideResourcePaths(out1, getPushAccessor(platformSpec)); - } catch (ParameterizedIdentifierIsFutureWork - | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage - | UnificationFailed | ValueUndefined e) { - e.printStackTrace(); - } - String dstPath = null; - if (filledPaths != null && filledPaths.get(out1) != null) { - ResourcePath filledDstPath = filledPaths.get(out1).getKey(); - dstPath = filledDstPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - } else { - dstPath = dstRes.toResourcePath(pathParamsUrl); - } - // Call the update method. - if (!hasUpdateMethodinvoked) { - // The first call to an update method in this method - update.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes2.getResourceName(), params, true)); - update.addStatement(langSpec.getVariableDeclaration(DataConstraintModel.typeString.getInterfaceTypeName(), "result") - + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, resName, httpMethod)); - hasUpdateMethodinvoked = true; - } else { - // After the second time of call to update methods in this method - update.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes2.getResourceName(), params, false)); - update.addStatement("result" + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, resName, httpMethod)); - } - } else { - // Use the reference field to refer to outside destination resource. - List args = new ArrayList<>(); - for (Map.Entry> paramEnt: pathParams) { - args.add(paramEnt.getValue().getValue()); - } - for (Map.Entry> paramEnt: params) { - args.add(paramEnt.getValue().getValue()); - } - update.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) - + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); - } - } else { - // Intra-service - // The destination resource is not outside. - List args = new ArrayList<>(); - for (Map.Entry> paramEnt: pathParams) { - args.add(paramEnt.getValue().getValue()); - } - for (Map.Entry> paramEnt: params) { - args.add(paramEnt.getValue().getValue()); - } - if (srcRes2 != dstRes) { - update.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) - + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); - } else { - update.addStatement(langSpec.getMethodInvocation(updateMethodName, args) - + langSpec.getStatementDelimiter()); // this.updateDstFromSrc(value, refParams); - } - } - if (addForStatement) { - // Close the for loop - update.addStatement(langSpec.getEndForStatement(forVarName)); - } + // Add an update method invocation. + hasUpdateMethodinvoked = addUpdateMethodInvocation(resourceNode, dstNode, update, forLoopBlock, refParams, + ch2, in, out1, inDegree, outsideOutputResource2, hasUpdateMethodinvoked); } } + + // Add an invocation to output native event channel. + if (directDstCh.isNative() && platformSpec.isMonolithic()) { + addNativeMethodInvocation(resourceNode, presenter, update, ch, directDstCh, out, in); + if (component != null) { + component.addField(langSpec.newFieldDeclaration(presenterType, presenter)); + } else if (parentComponent != null) { + parentComponent.addField(langSpec.newFieldDeclaration(presenterType, presenter)); + } + Map nameToParam = constructorParams.getOrDefault(resourceNode.getResourceHierarchy(), new HashMap<>()); + nameToParam.put(presenter,langSpec.newVariableDeclaration(presenterType, presenter)); + constructorParams.put(resourceNode.getResourceHierarchy(), nameToParam); + } + if (outsideInputMembers2.size() > 0) { if (!generatesComponent(resourceNode.getResourceHierarchy())) { // srcRes2 does not have a component. @@ -2185,10 +2071,9 @@ } private Map.Entry, Map>>> declareInputMethodsInThisAndMainComponents(ResourceNode resourceNode, TypeDeclaration component, - TypeDeclaration parentComponent, TypeDeclaration mainComponent, TypeDeclaration rootComponent, DataTransferModel model, Map priorMemberForInputChannel, IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + TypeDeclaration parentComponent, TypeDeclaration mainComponent, TypeDeclaration rootComponent, DataTransferModel model, Map priorMemberForInputChannel) { // Declare input methods. String resName = resourceNode.getResourceName(); - String resComponentName = langSpec.toComponentName(resName); List constructorStatements = new ArrayList<>(); Map>> inputStatements = new HashMap<>(); for (Channel ch: model.getInputChannels()) { @@ -2214,6 +2099,7 @@ if (!platformSpec.isMonolithic()) { resourcePath = getInputMethodResourcePathAndPathParams(out.getResource(), rootInputParams, platformSpec, langSpec); // 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 = ""; @@ -2285,7 +2171,8 @@ } } if (platformSpec.isMonolithic() - || (resourceNode.getResourceHierarchy().getParent() != null && resourceNode.getResourceHierarchy().getParent().getParent() != null)) { + || (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(out.getResource().getResourceHierarchy(), langSpec); @@ -2447,6 +2334,7 @@ ArrayList rootInputParams = new ArrayList<>(); String resourcePath = getGetterResourcePathAndPathParams(out.getResource(), rootInputParams, platformSpec, langSpec); if (resourcePath.indexOf('/') > 0) { + // Remove the root resource from the path resourcePath = resourcePath.substring(resourcePath.indexOf('/')); } else { resourcePath = ""; @@ -2475,7 +2363,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,13 +2371,12 @@ Expression resExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(out.getResource(), null); List args = new ArrayList<>(); if (resExp instanceof Term) { - // to access the parent + // 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); } - String resourceAccess = resExp.toImplementation(new String[] {""}); // Values of channel parameters. for (Selector selector: ch.getAllSelectors()) { if (selector.getExpression() instanceof Variable) { @@ -2519,7 +2406,12 @@ } } } - mainInputAccessor.addStatement(langSpec.getMethodInvocation(resourceAccess, input.getName(), args) + langSpec.getStatementDelimiter()); + if (resExp != null) { + String resourceAccess = resExp.toImplementation(new String[] {""}); + mainInputAccessor.addStatement(langSpec.getMethodInvocation(resourceAccess, input.getName(), args) + langSpec.getStatementDelimiter()); + } else { + mainInputAccessor.addStatement(langSpec.getMethodInvocation(input.getName(), args) + langSpec.getStatementDelimiter()); + } } if (input != null) { @@ -2611,12 +2503,19 @@ 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); + } else if (parentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); + } } else { 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()); } } @@ -2634,13 +2533,12 @@ Expression resExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(outResPath, outResPath.getRoot()); List args = new ArrayList<>(); if (resExp instanceof Term) { - // to access the parent + // 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); } - String resourceAccess = resExp.toImplementation(new String[] {""}); // Values of channel parameters. for (Selector selector: ch.getAllSelectors()) { if (selector.getExpression() instanceof Variable) { @@ -2654,7 +2552,12 @@ args.add(mesVar.getName()); } } - rootInputAccessor.addStatement(langSpec.getMethodInvocation(resourceAccess, input.getName(), args) + langSpec.getStatementDelimiter()); + if (resExp != null) { + String resourceAccess = resExp.toImplementation(new String[] {""}); + rootInputAccessor.addStatement(langSpec.getMethodInvocation(resourceAccess, input.getName(), args) + langSpec.getStatementDelimiter()); + } else { + rootInputAccessor.addStatement(langSpec.getMethodInvocation(input.getName(), args) + langSpec.getStatementDelimiter()); + } if (input != null && input.getThrows() != null && ((RestApiSpecific) platformSpec).hasJsonException(input)) { ((RestApiSpecific) platformSpec).addJsonException(rootInputAccessor); } @@ -2696,6 +2599,22 @@ for (ChannelNode descendantDst: descendantDstChannels) { outEdges.addAll(descendantDst.getOutEdges()); } + // Calculate in-degree (PUSH transfer) of the destination resource. + Set inEdges = new HashSet<>(); + inEdges.addAll(directDstChNode.getInEdges()); + for (ChannelNode ancestorSrc: ancestorDstChannels) { + inEdges.addAll(ancestorSrc.getInEdges()); + } + for (ChannelNode descendantSrc: descendantDstChannels) { + inEdges.addAll(descendantSrc.getInEdges()); + } + int inDegree = 0; + for (Edge resToCh2: inEdges) { + DataFlowEdge df =(DataFlowEdge) resToCh2; + if (((PushPullAttribute) df.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { + inDegree++; + } + } for (Edge chToRes: outEdges) { // For each data transfer to dstNode:ResourceNode. ResourceNode dstNode = ((ResourceNode) chToRes.getDestination()); @@ -2722,25 +2641,7 @@ } if ((((PushPullAttribute) dOut.getAttribute()).getSelectedOption() == PushPullValue.PUSH && !outsideInputResource2) || outsideOutputResource2) { // PUSH transfer - - // Calculate in-degree (PUSH transfer) of the destination resource. - Set inEdges = new HashSet<>(); - inEdges.addAll(directDstChNode.getInEdges()); - for (ChannelNode ancestorSrc: ancestorDstChannels) { - inEdges.addAll(ancestorSrc.getInEdges()); - } - for (ChannelNode descendantSrc: descendantDstChannels) { - inEdges.addAll(descendantSrc.getInEdges()); - } - int inDegree = 0; - for (Edge resToCh2: inEdges) { - DataFlowEdge df =(DataFlowEdge) resToCh2; - if (((PushPullAttribute) df.getAttribute()).getSelectedOption() == PushPullValue.PUSH) { - inDegree++; - } - } - 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) { @@ -2748,7 +2649,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()) { @@ -2786,9 +2687,9 @@ Expression getter = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, resourceNode.getOutSideResource(directDstCh)); Term valueGetter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); valueGetter.addChild(getter); - parent = valueGetter.toImplementation(new String[] {}); + parent = valueGetter.toImplementation(new String[] {""}); } else { - parent = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, resourceNode.getOutSideResource(directDstCh)).toImplementation(new String[] {}); + parent = getPullAccessor(platformSpec).getDirectStateAccessorFor(insideResPath, resourceNode.getOutSideResource(directDstCh)).toImplementation(new String[] {""}); } } else { // for REST API @@ -2796,12 +2697,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 @@ -2810,7 +2715,14 @@ 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); + } else if (parentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(parentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(parentComponent); + } } } } else if (selExp instanceof Term) { @@ -2840,202 +2752,32 @@ 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, refVarName))); } } - List>> pathParams = new ArrayList<>(); - if (platformSpec.isMonolithic()) { - // Update fields to refer to outside resources. - ResourcePath filledOutsideResourcePath = null; - try { - Map>> resourcePaths = ch2.fillOutsideResourcePaths(out2, getPullAccessor(platformSpec)); - if (resourcePaths != null && resourcePaths.size() > 0) { - for (ChannelMember outsideMember: resourcePaths.keySet()) { - ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); - if (out2.equals(outsideMember)) { - filledOutsideResourcePath = outsidePath; - } - if (!generatesComponent(outsidePath.getResourceHierarchy())) { - outsidePath = outsidePath.getParent(); - } - String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); - Expression outsideExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(outsidePath, null); - if (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); - input.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. - } - } - } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork - | InvalidMessage | UnificationFailed | ValueUndefined e) { - e.printStackTrace(); - } - // Values of path parameters to call the update method. - if (filledOutsideResourcePath == null) { - filledOutsideResourcePath = out2.getResource(); - } - for (Expression pathParam: filledOutsideResourcePath.getPathParams()) { - if (pathParam instanceof Variable) { - Variable pathVar = (Variable) pathParam; - pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), - new AbstractMap.SimpleEntry<>(pathVar.getName(), - pathVar.getName()))); - } else if (pathParam instanceof Constant) { - Constant pathVar = (Constant) pathParam; - pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), - new AbstractMap.SimpleEntry<>(pathVar.getSymbol().getName(), - pathVar.getSymbol().getName()))); - } - } - } else { - // Values of path parameters to call the update method. - for (Expression pathParam: out2.getResource().getPathParams()) { - if (pathParam instanceof Variable) { - Variable pathVar = (Variable) pathParam; - pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), - new AbstractMap.SimpleEntry<>(pathVar.getName(), - pathVar.getName()))); - } - } - } - // Values of channel parameters to call the update method. - List>> params = new ArrayList<>(); - for (Selector selector: ch2.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 to call the update method. - ResourceHierarchy srcRes = resourceNode.getResourceHierarchy(); - if (generatesComponent(srcRes)) { - params.add(new AbstractMap.SimpleEntry<>(srcRes.getResourceStateType(), - new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes.getResourceName()), - langSpec.getFieldAccessor(fieldOfResourceState)))); - } else { - params.add(new AbstractMap.SimpleEntry<>(srcRes.getResourceStateType(), - new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes.getResourceName()), - langSpec.getFieldAccessor(langSpec.toVariableName(srcRes.getResourceName()))))); - srcRes = srcRes.getParent(); - } - params.addAll(refParams); - // Call the update method. - String updateMethodName = null; - ResourceHierarchy dstRes = dstNode.getResourceHierarchy(); - if (!generatesComponent(dstRes)) { - updateMethodName = updateMethodPrefix + getComponentName(dstRes, langSpec) + from + resComponentName; - dstRes = dstRes.getParent(); - } else { - updateMethodName = updateMethodPrefix + from + resComponentName; - } - String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); - if (outsideOutputResource2 - || (!platformSpec.isMonolithic() && in.getResource().getCommonPrefix(out2.getResource()) == null && platformSpec.isDifferentTreesAsDifferentServices())) { - // Inter-servces - if (!platformSpec.isMonolithic()) { - // REST API - RestApiSpecific restApiSpec = (RestApiSpecific) platformSpec; - String httpMethod = null; - if (out2.getStateTransition().isRightUnary()) { - httpMethod = "put"; - } else { - httpMethod = "post"; - } - String[] sideEffects = new String[] {""}; - List pathParamsUrl = new ArrayList<>(); - for (Expression pathExp: out2.getResource().getPathParams()) { - pathParamsUrl.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); - } - String resName2 = langSpec.toVariableName(resComponentName); - if (inDegree <= 1) { - resName2 = null; - } - Map>> filledPaths = null; - try { - filledPaths = ch2.fillOutsideResourcePaths(out2, getPushAccessor(platformSpec)); - } catch (ParameterizedIdentifierIsFutureWork - | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage - | UnificationFailed | ValueUndefined e) { - e.printStackTrace(); - } - String dstPath = null; - if (filledPaths != null && filledPaths.get(out2) != null) { - ResourcePath filledDstPath = filledPaths.get(out2).getKey(); - dstPath = filledDstPath.toResourcePath().replaceAll(":.*\\}","\\}").replaceAll("\\{", "\"+").replaceAll("\\}", "+\""); - } else { - dstPath = dstRes.toResourcePath(pathParamsUrl); - } - // Call the update method. - if (!hasUpdateMethodinvoked) { - // The first call to an update method in this method - input.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, true)); - input.addStatement(langSpec.getVariableDeclaration(DataConstraintModel.typeString.getInterfaceTypeName(), "result") - + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, resName2, httpMethod)); - hasUpdateMethodinvoked = true; - if (component != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(component)) { - // Declare a client field to connect to the destination resource of push transfer. - ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(component); - } - } else { - // After the second time of call to update methods in this method - input.addStatement(restApiSpec.getHttpMethodParamsConstructionStatement(srcRes.getResourceName(), params, false)); - input.addStatement("result" + langSpec.getAssignment() + restApiSpec.getHttpMethodCallStatement(restApiSpec.getBaseURL(), dstPath, resName2, httpMethod)); - } - } else { - // Use the reference field to refer to outside destination resource. - List args = new ArrayList<>(); - for (Map.Entry> paramEnt: pathParams) { - args.add(paramEnt.getValue().getValue()); - } - for (Map.Entry> paramEnt: params) { - args.add(paramEnt.getValue().getValue()); - } - input.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) - + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); - } - } else { - // Intra-service - // The destination resource is not outside. - List args = new ArrayList<>(); - for (Map.Entry> paramEnt: pathParams) { - args.add(paramEnt.getValue().getValue()); - } - for (Map.Entry> paramEnt: params) { - args.add(paramEnt.getValue().getValue()); - } - if (srcRes != dstRes) { - input.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) - + langSpec.getStatementDelimiter()); // this.dst.updateDstFromSrc(value, refParams); - } else { - input.addStatement(langSpec.getMethodInvocation(updateMethodName, args) - + langSpec.getStatementDelimiter()); // this.updateDstFromSrc(value, refParams); - } - } - if (addForStatement) { - // Close the for loop. - input.addStatement(langSpec.getEndForStatement(forVarName)); - } + // Add an update method invocation. + hasUpdateMethodinvoked = addUpdateMethodInvocation(resourceNode, dstNode, input, forLoopBlock, refParams, + ch2, in, out2, inDegree, outsideOutputResource2, hasUpdateMethodinvoked); } } + // Add an invocation to output native event channel. + if (directDstCh.isNative() && platformSpec.isMonolithic()) { + addNativeMethodInvocation(resourceNode, presenter, input, ((DataTransferChannel) ch), directDstCh, out, in); + if (component != null) { + component.addField(langSpec.newFieldDeclaration(presenterType, presenter)); + } else if (parentComponent != null) { + parentComponent.addField(langSpec.newFieldDeclaration(presenterType, presenter)); + } + Map nameToParam = constructorParams.getOrDefault(resourceNode.getResourceHierarchy(), new HashMap<>()); + nameToParam.put(presenter,langSpec.newVariableDeclaration(presenterType, presenter)); + constructorParams.put(resourceNode.getResourceHierarchy(), nameToParam); + } + // Update and initialize a field to refer to an outside input resource for PULL transfer. if (platformSpec.isMonolithic()) { // For a monolithic application. @@ -3096,14 +2838,368 @@ return new AbstractMap.SimpleEntry<>(constructorStatements, inputStatements); } - protected void declareGetterAccessorInTheRootResource(ResourceNode resourceNode, TypeDeclaration rootComponent, - IPlatformSpecific platformSpec, ILanguageSpecific langSpec) { + private boolean addUpdateMethodInvocation(ResourceNode srcNode, ResourceNode dstNode, + 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; + try { + Map>> resourcePaths = ch.fillOutsideResourcePaths(out, getPullAccessor(platformSpec)); + if (resourcePaths != null && resourcePaths.size() > 0) { + for (ChannelMember outsideMember: resourcePaths.keySet()) { + ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); + if (out.equals(outsideMember)) { + filledOutsideResourcePath = outsidePath; + } + if (!generatesComponent(outsidePath.getResourceHierarchy())) { + outsidePath = outsidePath.getParent(); + } + String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); + Expression outsideExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(outsidePath, null); + if (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); + callerBlock.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. + } + } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + // Values of path parameters to call the update method. + if (filledOutsideResourcePath == null) { + filledOutsideResourcePath = out.getResource(); + } + for (Expression pathParam: filledOutsideResourcePath.getPathParams()) { + if (pathParam instanceof Variable) { + Variable pathVar = (Variable) pathParam; + pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), + new AbstractMap.SimpleEntry<>(pathVar.getName(), + pathVar.getName()))); + } else if (pathParam instanceof Constant) { + Constant pathVar = (Constant) pathParam; + pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), + new AbstractMap.SimpleEntry<>(pathVar.getSymbol().getName(), + pathVar.getSymbol().getName()))); + } + } + } else { + // Values of path parameters to call the update method. + for (Expression pathParam: out.getResource().getPathParams()) { + if (pathParam instanceof Variable) { + Variable pathVar = (Variable) pathParam; + pathParams.add(new AbstractMap.SimpleEntry<>(pathVar.getType(), + new AbstractMap.SimpleEntry<>(pathVar.getName(), + pathVar.getName()))); + } + } + } + // Values of channel parameters to call the update method. + List>> params = new ArrayList<>(); + 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 to call the update method. + ResourceHierarchy srcRes = srcNode.getResourceHierarchy(); + if (generatesComponent(srcRes)) { + params.add(new AbstractMap.SimpleEntry<>(srcRes.getResourceStateType(), + new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes.getResourceName()), + langSpec.getFieldAccessor(fieldOfResourceState)))); + } else { + params.add(new AbstractMap.SimpleEntry<>(srcRes.getResourceStateType(), + new AbstractMap.SimpleEntry<>(langSpec.toVariableName(srcRes.getResourceName()), + langSpec.getFieldAccessor(langSpec.toVariableName(srcRes.getResourceName()))))); + srcRes = srcRes.getParent(); + } + params.addAll(refParams); + + // Create a guard condition. + Term guardCondition = null; + for (Map.Entry paramEnt: in.getResource().getPathParamsAndConstraints()) { + if (paramEnt.getValue() != null) { + Term newCondition = new Term(DataConstraintModel.eq); + newCondition.addChild(paramEnt.getKey(), true); + newCondition.addChild(paramEnt.getValue(), true); + if (guardCondition == null) { + guardCondition = newCondition; + } else { + Term composedCondition = new Term(DataConstraintModel.and); + composedCondition.addChild(guardCondition, true); + composedCondition.addChild(newCondition, true); + guardCondition = composedCondition; + } + } + } + + // Call the update method. + ResourceHierarchy dstRes = dstNode.getResourceHierarchy(); + String updateMethodName = getUpdateMethodName(srcNode.getResourceHierarchy(), dstRes, ch); // Get the method name. + if (!generatesComponent(dstRes)) { + dstRes = dstRes.getParent(); + } + String dstCompName = langSpec.toVariableName(getComponentName(dstRes, langSpec)); + if (outsideOutputResource + || (!platformSpec.isMonolithic() && in.getResource().getCommonPrefix(out.getResource()) == null && platformSpec.isDifferentTreesAsDifferentServices())) { + // Inter-servces + if (!platformSpec.isMonolithic()) { + // REST API + RestApiSpecific restApiSpec = (RestApiSpecific) platformSpec; + String httpMethod = null; + if (out.getStateTransition().isRightUnary()) { + httpMethod = "put"; + } else { + httpMethod = "post"; + } + String[] sideEffects = new String[] {""}; + List pathParamsUrl = new ArrayList<>(); + for (Expression pathExp: out.getResource().getPathParams()) { + pathParamsUrl.add("\" + " + pathExp.toImplementation(sideEffects) + " + \""); + } + String srcResName = langSpec.toVariableName(getComponentName(srcNode.getResourceHierarchy(), langSpec)); + if (inDegree <= 1) { + srcResName = null; + } + Map>> filledPaths = null; + try { + filledPaths = ch.fillOutsideResourcePaths(out, getPushAccessor(platformSpec)); + } catch (ParameterizedIdentifierIsFutureWork + | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage + | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + 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.toResourcePath(pathParamsUrl); + } + // Call the update method. + TypeDeclaration srcComponent = null; + TypeDeclaration srcParentComponent = null; + if (generatesComponent(srcRes)) { + srcComponent = generationContext.getComponent(srcRes); + } else if (srcRes.getParent() != null) { + srcParentComponent = generationContext.getComponent(srcRes.getParent()); + } + if (!hasUpdateMethodinvoked) { + // The first call to an update method in this method + 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. + callerBlock.addStatement(httpMethodCall); + } else { + // Conditional http method call by a guarded state transition. + 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. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcComponent); + } else if (srcParentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcParentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcParentComponent); + } + if (!((RestApiSpecific) platformSpec).hasJsonException(callerMethod)) { + ((RestApiSpecific) platformSpec).addJsonException(callerMethod); + } + hasUpdateMethodinvoked = true; + } else { + // After the second time of call to update methods in this method + 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. + callerBlock.addStatement(httpMethodCall); + } else { + // Conditional http method call by a guarded state transition. + 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. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcComponent); + } else if (srcParentComponent != null && !((RestApiSpecific) platformSpec).hasHttpClientFieldDeclaration(srcParentComponent)) { + // Declare a client field to connect to the destination resource of push transfer. + ((RestApiSpecific) platformSpec).addHttpClientFieldDeclaration(srcParentComponent); + } + if (!((RestApiSpecific) platformSpec).hasJsonException(callerMethod)) { + ((RestApiSpecific) platformSpec).addJsonException(callerMethod); + } + } + } else { + // Use the reference field to refer to outside destination resource. + List args = new ArrayList<>(); + for (Map.Entry> paramEnt: pathParams) { + args.add(paramEnt.getValue().getValue()); + } + for (Map.Entry> paramEnt: params) { + args.add(paramEnt.getValue().getValue()); + } + String methodInvocation = null; + methodInvocation = langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) + + langSpec.getStatementDelimiter(); // this.dst.updateDstFromSrc(value, refParams); + if (guardCondition == null) { + // Non-conditional invocation. + callerBlock.addStatement(methodInvocation); + } else { + // Conditional invocation by a guarded state transition. + Block ifBlock = new Block(); + ifBlock.addStatement(methodInvocation); + callerBlock.addStatement(langSpec.getIfStatement(guardCondition, ifBlock)); + } + } + } else { + // Intra-service + // The destination resource is not outside. + List args = new ArrayList<>(); + for (Map.Entry> paramEnt: pathParams) { + args.add(paramEnt.getValue().getValue()); + } + for (Map.Entry> paramEnt: params) { + args.add(paramEnt.getValue().getValue()); + } + String methodInvocation = null; + if (srcRes != dstRes) { + methodInvocation = langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstCompName), updateMethodName, args) + + langSpec.getStatementDelimiter(); // this.dst.updateDstFromSrc(value, refParams); + } else { + methodInvocation = langSpec.getMethodInvocation(updateMethodName, args) + + langSpec.getStatementDelimiter(); // this.updateDstFromSrc(value, refParams); + } + if (guardCondition == null) { + // Non-conditional invocation. + callerBlock.addStatement(methodInvocation); + } else { + // Conditional invocation by a guarded state transition. + Block ifBlock = new Block(); + ifBlock.addStatement(methodInvocation); + callerBlock.addStatement(langSpec.getIfStatement(guardCondition, ifBlock)); + } + } + return hasUpdateMethodinvoked; + } + + private void addNativeMethodInvocation(ResourceNode srcNode, String receiverName, MethodDeclaration callerMethod, + DataTransferChannel inCh, DataTransferChannel ch, ChannelMember out, ChannelMember in) { + // Values of channel parameters to call the update method. + List>> params = new ArrayList<>(); + 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()))); + } + } + // Call the native method. + try { + List args = new ArrayList<>(); + for (Map.Entry> paramEnt: params) { + args.add(paramEnt.getValue().getValue()); + } + IResourceStateAccessor resouceStateAccessor = new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(ChannelMember target, ChannelMember from) { + return getPushAccessor(platformSpec).getCurrentStateAccessorFor(out, out); + } + + @Override + public Expression getNextStateAccessorFor(ChannelMember target, ChannelMember from) { + try { + return inCh.deriveUpdateExpressionOf(out, getPushAccessor(platformSpec)).getKey(); + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + return getPushAccessor(platformSpec).getNextStateAccessorFor(out, out); + } + } + + @Override + public Expression getDirectStateAccessorFor(ResourcePath target, ResourcePath from) { + return getPushAccessor(platformSpec).getDirectStateAccessorFor(target, from); + } + }; + Map> substitutedPositionsInMessageFromChannels = new HashMap<>(); + Expression message = ch.calcMessageConstraintForInputMember(in, in, resouceStateAccessor, null, substitutedPositionsInMessageFromChannels); + if (message instanceof Term) { + String updateMethodName = ((Term) message).getSymbol().getName(); + for (Expression messageArg: ((Term) message).getChildren()) { + args.add(messageArg.toImplementation(new String[] {null})); + } + callerMethod.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(receiverName), updateMethodName, args) + + langSpec.getStatementDelimiter()); + } + } catch (ResolvingMultipleDefinitionIsFutureWork | InvalidMessage e) { + } + } + + protected MethodDeclaration getOrDeclareUpdateMethod(ResourceHierarchy srcRes, ResourceHierarchy dstRes, DataTransferChannel ch, ArrayList parameters) { + MethodDeclaration update = null; + String updateMethodName = getUpdateMethodName(srcRes, dstRes, ch); + if (generatesComponent(dstRes)) { + // A component is created for this resource. + TypeDeclaration dstComponent = generationContext.getComponent(dstRes); + for (MethodDeclaration method: dstComponent.getMethods()) { + if (method.getName().equals(updateMethodName)) { + update = method; + break; + } + } + if (update == null) { + update = langSpec.newMethodDeclaration(updateMethodName, false, null, parameters); + dstComponent.addMethod(update); + } + } else if (dstRes.getParent() != null) { + // No component is created for this resource. + TypeDeclaration dstParentComponent = generationContext.getComponent(dstRes.getParent()); + for (MethodDeclaration method: dstParentComponent.getMethods()) { + if (method.getName().equals(updateMethodName)) { + update = method; + break; + } + } + if (update == null) { + update = langSpec.newMethodDeclaration(updateMethodName, false, null, parameters); + dstParentComponent.addMethod(update); + } + } + return update; + } + + protected void declareGetterAccessorInTheRootResource(ResourceNode resourceNode, TypeDeclaration rootComponent) { if (resourceNode.getResourceHierarchy().getParent() != null) { // For a non-root resource MethodDeclaration getterAccessor = null; List mainGetterParams = new ArrayList<>(); String resourcePath = getGetterResourcePathAndPathParams(resourceNode.getPrimaryResourcePath(), mainGetterParams, platformSpec, langSpec); if (resourcePath.indexOf('/') > 0) { + // Remove the root resource from the path resourcePath = resourcePath.substring(resourcePath.indexOf('/')); } else { resourcePath = ""; @@ -3124,7 +3220,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) { @@ -3142,6 +3238,12 @@ VariableDeclaration param; parameters = new ArrayList<>(); String resourcePath = getUpdateResourcePathAndPathParams(dstResPath, parameters, true, platformSpec, langSpec); // 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 = ""; + } ResourcePath resPath = new ResourcePath(dstResPath); for (int i = 0; i < parameters.size(); i++) { Parameter pathParam = new Parameter(parameters.get(i).getName()); @@ -3194,17 +3296,21 @@ Expression resExp = getPullAccessor(platformSpec).getDirectStateAccessorFor(resPath, resPath.getRoot()); List args = new ArrayList<>(); if (resExp instanceof Term) { - // to access the parent + // 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.add(((Variable)((Term) resExp).getChild(1)).getName()); } resExp = ((Term) resExp).getChild(0); } - String resourceAccess = resExp.toImplementation(new String[] {""}); for (VariableDeclaration var: updateAccessor.getParameters()) { args.add(var.getName()); } - updateAccessor.addStatement(langSpec.getMethodInvocation(resourceAccess, updateMethodName, args) + langSpec.getStatementDelimiter()); + if (resExp != null) { + String resourceAccess = resExp.toImplementation(new String[] {""}); + updateAccessor.addStatement(langSpec.getMethodInvocation(resourceAccess, updateMethodName, args) + langSpec.getStatementDelimiter()); + } else { + updateAccessor.addStatement(langSpec.getMethodInvocation(updateMethodName, args) + langSpec.getStatementDelimiter()); + } rootComponent.addMethod(updateAccessor); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java index 5e5ea4a..2dfe533 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java @@ -1,17 +1,14 @@ package generators; -import java.util.ArrayList; import java.util.List; -import code.ast.CompilationUnit; -import code.ast.FieldDeclaration; -import code.ast.MethodDeclaration; -import code.ast.TypeDeclaration; -import code.ast.VariableDeclaration; -import models.algebra.Expression; +import code.ast.*; import models.algebra.Term; import models.algebra.Type; -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); @@ -21,11 +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); - String getVariableDeclaration(String typeName, String varName); - String getFieldInitializer(Type type, Expression initialValue); + 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); @@ -34,13 +36,11 @@ String getMethodInvocation(String receiverName, String methodName); String getMethodInvocation(String receiverName, String methodName, List parameters); String getConstructorInvocation(String componentName, List parameters); - String getReturnStatement(String returnValue); - String getIfStatement(Term condition, String block); - String getForStatementForList(String varName, String list); - String getForStatementForCollection(String varName, String varType, String collection); - String getForStatementForMap(String varName, String varType, String map); - String getEndForStatement(); - String getEndForStatement(String varName); + ReturnStatement getReturnStatement(String returnValue); + IfStatement getIfStatement(Term condition, Statement block); + 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(); @@ -57,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/JavaImplementationVisitor.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaImplementationVisitor.java new file mode 100644 index 0000000..3b1d8ce --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaImplementationVisitor.java @@ -0,0 +1,193 @@ +package generators; + +import models.algebra.*; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.JsonAccessor; +import models.dataConstraintModel.JsonTerm; + +/** + * This class is a Java implementation of {@link IExpressionVisitor} + * which holds and manages the actual method of implementation code generation + * + * @author s-yamagiwa + */ +public class JavaImplementationVisitor implements IExpressionVisitor { + private static int jsonCount = 0; + + @Override + public String visit(Term term, String[] sideEffects) { + int[] implParamOrder = term.getSymbol().getImplParamOrder(); + if (term.getSymbol().isImplLambda()) { + String[] components = term.getSymbol().getImplName().split("->"); + String component0 = components[0].replace("(", "").replace(")", ""); + String[] params = component0.split(","); + String exp = components[1]; + String receiver = ""; + if (implParamOrder == null) { + receiver = term.getChildren().get(0).accept(this, sideEffects); + exp = exp.replace(params[0], receiver); + for (int i = 1; i < params.length; i++) { + exp = exp.replace(params[i], term.getChildren().get(i).accept(this, sideEffects)); + } + } else { + receiver = term.getChildren().get(implParamOrder[0]).accept(this, sideEffects); + exp = exp.replace(params[0], receiver); + for (int i = 1; i < params.length; i++) { + exp = exp.replace(params[i], term.getChildren().get(implParamOrder[i]).accept(this, sideEffects)); + } + } + if (term.getSymbol().isImplWithSideEffect()) { + sideEffects[0] = sideEffects[0] + exp + ";\n"; + exp = receiver; + } + return exp; + } + if (term.getSymbol().isImplGenerative()) { + Type[] childrenTypes = new Type[term.getChildren().size()]; + String[] childrenImpl = new String[term.getChildren().size()]; + String[] childrenSideEffects = new String[term.getChildren().size()]; + if (implParamOrder == null) { + for (int i = 0; i < term.getChildren().size(); i++) { + Expression child = term.getChildren().get(i); + if (child instanceof Variable) { + childrenTypes[i] = ((Variable) child).getType(); + } else if (child instanceof Term) { + childrenTypes[i] = ((Term) child).getType(); + } + String[] childSideEffect = new String[]{""}; + childrenImpl[i] = child.accept(this, childSideEffect); + childrenSideEffects[i] = childSideEffect[0]; + } + String exp = term.getSymbol().generate(term.getType(), childrenTypes, childrenImpl, childrenSideEffects, sideEffects); + if (term.getSymbol().isImplWithSideEffect()) { + sideEffects[0] = sideEffects[0] + exp; + exp = childrenImpl[0]; // the value of this term + } + return exp; + } else { + for (int i = 0; i < term.getChildren().size(); i++) { + Expression child = term.getChildren().get(implParamOrder[i]); + if (child instanceof Variable) { + childrenTypes[i] = ((Variable) child).getType(); + } else if (child instanceof Term) { + childrenTypes[i] = ((Term) child).getType(); + } + String[] childSideEffect = new String[]{""}; + childrenImpl[i] = child.accept(this, childSideEffect); + childrenSideEffects[i] = childSideEffect[0]; + } + String exp = term.getSymbol().generate(term.getType(), childrenTypes, childrenImpl, childrenSideEffects, sideEffects); + if (term.getSymbol().isImplWithSideEffect()) { + sideEffects[0] = sideEffects[0] + exp; + exp = childrenImpl[0]; // the value of this term + } + return exp; + } + } + if (term.getArity() == 2 && term.getSymbol().isImplInfix()) { + if (implParamOrder == null) { + return "(" + term.getChildren().get(0).accept(this, sideEffects) + term.getSymbol().toImplementation() + term.getChildren().get(1).accept(this, sideEffects) + ")"; + } else { + return "(" + term.getChildren().get(implParamOrder[0]).accept(this, sideEffects) + term.getSymbol().toImplementation() + term.getChildren().get(implParamOrder[1]).accept(this, sideEffects) + ")"; + } + } + if ((term.getArity() >= 1 || term.getArity() == -1) && term.getSymbol().isImplMethod()) { + if (implParamOrder == null) { + String exp = null; + String receiver = ""; + if (term.getChildren().size() > 0 && term.getChildren().get(0) != null) { + receiver = term.getChildren().get(0).accept(this, sideEffects); + exp = receiver + "." + term.getSymbol().toImplementation() + "("; + } else { + exp = term.getSymbol().toImplementation() + "("; + } + String delimiter = ""; + for (int i = 1; i < term.getChildren().size(); i++) { + Expression e = term.getChildren().get(i); + exp += (delimiter + e.accept(this, sideEffects)); + delimiter = ","; + } + exp += ")"; + if (term.getSymbol().isImplWithSideEffect()) { + sideEffects[0] = sideEffects[0] + exp + ";\n"; + exp = receiver; + } + return exp; + } else { + String receiver = term.getChildren().get(implParamOrder[0]).accept(this, sideEffects); + String exp = receiver + "." + term.getSymbol().toImplementation() + "("; + String delimiter = ""; + for (int i = 1; i < term.getChildren().size(); i++) { + Expression e = term.getChildren().get(implParamOrder[i]); + exp += (delimiter + e.accept(this, sideEffects)); + delimiter = ","; + } + exp += ")"; + if (term.getSymbol().isImplWithSideEffect()) { + sideEffects[0] = sideEffects[0] + exp + ";\n"; + exp = receiver; + } + return exp; + } + } else { + if (implParamOrder == null) { + String exp = term.getSymbol().toImplementation() + "("; + String delimiter = ""; + for (Expression e : term.getChildren()) { + exp += (delimiter + e.accept(this, sideEffects)); + delimiter = ","; + } + return exp + ")"; + } else { + String exp = term.getSymbol().toImplementation() + "("; + String delimiter = ""; + for (int i = 0; i < term.getChildren().size(); i++) { + Expression e = term.getChildren().get(implParamOrder[i]); + exp += (delimiter + e.accept(this, sideEffects)); + delimiter = ","; + } + return exp + ")"; + } + } + } + + @Override + public String visit(Field field, String[] sideEffects) { + return "this." + visit((Constant) field, sideEffects); + } + + @Override + public String visit(Constant constant, String[] sideEffects) { + if (constant.getSymbol().isImplGenerative()) { + String exp = constant.getSymbol().generate(constant.getType(), new Type[]{}, new String[]{}, new String[]{}, sideEffects); + return exp; + } + return constant.getSymbol().getImplName(); + } + + @Override + public String visit(Variable variable, String[] sideEffects) { + return variable.getName(); + } + + @Override + public String visit(JsonTerm jsonTerm, String[] sideEffects) { + String temp = "temp_json" + jsonCount; + jsonCount++; + String impl = ""; + impl += "Map " + temp + " = new HashMap<>();\n"; + for (String key : jsonTerm.keySet()) { + impl += temp + ".put(\"" + key + "\", " + jsonTerm.get(key).accept(this, sideEffects) + ");\n"; + } + sideEffects[0] += impl; + return temp; + } + + @Override + public String visit(JsonAccessor jsonAccessor, String[] sideEffects) { + if (jsonAccessor.getSymbol().equals(DataConstraintModel.dotParam)) { + return jsonAccessor.getChildren().get(0).accept(this, sideEffects) + "." + jsonAccessor.getSymbol().toImplementation() + "(" + jsonAccessor.getChildren().get(1).accept(this, sideEffects) + ")"; + } + return visit((Term) jsonAccessor, sideEffects); + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java deleted file mode 100644 index f220abd..0000000 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ /dev/null @@ -1,1468 +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 - 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); - } - String resourceAccess = resExp.toImplementation(new String[] {null}); - // 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 = ", "; - } - inputAccessor.addStatement(resourceAccess + "." + 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 58357f2..6548d62 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java @@ -1,23 +1,35 @@ package generators; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -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.algebra.Expression; -import models.algebra.Parameter; -import models.algebra.Term; +import code.ast.*; +import code.ast.Expression; +import code.ast.Variable; +import models.algebra.*; import models.algebra.Type; -import models.algebra.Variable; 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 @@ -64,51 +76,93 @@ } @Override - public Type newListType(String compTypeName) { - return new Type("List", "ArrayList<>", "List<" + compTypeName + ">", DataConstraintModel.typeList); + public ListType newListType(Type compType) { + return newListType(compType, DataConstraintModel.typeList); + } + + @Override + 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 Type newMapType(Type keyType, String valueTypeName) { - return new Type("Map", "HashMap<>", "Map<" + keyType.getImplementationTypeName() + ", " + valueTypeName + ">", DataConstraintModel.typeMap); + 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 Type newTupleType(List componentTypes) { - String implTypeName = "AbstractMap.SimpleEntry<>"; - String interfaceTypeName = "Map.Entry<$x>"; + 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) { - 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>"); + Type compType = componentTypes.get(componentTypes.size() - 1); + if (isValueType(compType)) { + interfaceType = (code.ast.Type) getWrapperType(compType).getInterfaceType(); + } else { + interfaceType = (code.ast.Type) compType.getInterfaceType(); } - implTypeName = implTypeName.replace("$x", - ", " + getImplementationTypeName(componentTypes.get(componentTypes.size() - 1))); - interfaceTypeName = interfaceTypeName.replace("$x", - ", " + getInterfaceTypeName(componentTypes.get(componentTypes.size() - 1))); + 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); + } } - Type newTupleType = new Type("Tuple", implTypeName, interfaceTypeName, DataConstraintModel.typeTuple); - return newTupleType; + 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 String getVariableDeclaration(String typeName, String varName) { - return typeName + " " + varName; - } - - @Override - public String getFieldInitializer(Type type, Expression initialValue) { - String initializer = null; - if (initialValue != null) { - initializer = initialValue.toImplementation(new String[] {""}); - } else if (type != null) { - initializer = DataConstraintModel.getDefaultValue(type); - } - return initializer; + public JsonType newJsonType(Type parentJsonType) { + JsonType jsonType = newJsonType(); + jsonType.addParentType(parentJsonType); + return jsonType; } @Override @@ -187,38 +241,62 @@ } @Override - public String getReturnStatement(String returnValue) { - return "return " + returnValue; + public ReturnStatement getReturnStatement(String returnValue) { + ReturnStatement returnStatement = new ReturnStatement(); + returnStatement.setExpression(new code.ast.Variable(returnValue) { + }); + return returnStatement; } @Override - public String getIfStatement(Term condition, String block) { - return "if (" + condition.toImplementation(new String[] {})+ ") {\n" + "\t" + block.replace("\n", "\n\t") + "\n}"; + public IfStatement getIfStatement(Term condition, Statement block) { + IfStatement ifStatement = new IfStatement(); + String conditionSource = condition.toImplementation(new String[]{""}); + ifStatement.setExpression(new code.ast.Variable(conditionSource)); + ifStatement.setThenStatement(block); + return ifStatement; } @Override - public String getForStatementForList(String varName, String list) { - return "for (int " + varName + getAssignment() + "0; " + varName + " < " + list + ".size(); " + varName + "++) {"; + 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(varDecStmt); + InfixExpression condition = new InfixExpression( + new Symbol("<", 2, Symbol.Type.INFIX), + new code.ast.Variable(varName), + new code.ast.Variable(list + ".size()") + ); + forStatement.setExpression(condition); + PostfixExpression increment = new PostfixExpression( + new code.ast.Variable(varName), + PostfixExpression.Operator.INCREMENT + ); + forStatement.setUpdaters(Arrays.asList(new ExpressionStatement(increment))); + return forStatement; } @Override - public String getForStatementForCollection(String varName, String varType, String collection) { - return "for (" + varType + " " + varName + ": " + collection + ") {"; + public EnhancedForStatement getForStatementForCollection(VariableDeclaration varDeclaration, String collection) { + EnhancedForStatement enhancedForStatement = new EnhancedForStatement(); + + enhancedForStatement.setParameter(varDeclaration); + enhancedForStatement.setExpression(new code.ast.Variable(collection)); + + return enhancedForStatement; } @Override - public String getForStatementForMap(String varName, String varType, String map) { - return "for (" + varType + " " + varName + ": " + map + ".keySet()) {"; - } + public EnhancedForStatement getForStatementForMap(String varName, String map) { + VariableDeclaration varDeclaration = new VariableDeclaration(DataConstraintModel.typeString, varName); + EnhancedForStatement enhancedForStatement = new EnhancedForStatement(); + + enhancedForStatement.setParameter(varDeclaration); + enhancedForStatement.setExpression(new code.ast.Variable(map + ".keySet()")); - @Override - public String getEndForStatement() { - return "}"; - } - - @Override - public String getEndForStatement(String varName) { - return "}"; + return enhancedForStatement; } @Override @@ -305,9 +383,9 @@ @Override public String getTupleGet(String tupleExp, int idx, int length) { - Expression t = new Variable(tupleExp, DataConstraintModel.typeTuple); + models.algebra.Expression t = new models.algebra.Variable(tupleExp); for (int i = 0; i < idx; i++) { - Term next = new Term(DataConstraintModel.snd); + Term next = new Term(DataConstraintModel.snd); next.addChild(t); t = next; } @@ -316,17 +394,17 @@ last.addChild(t); t = last; } - return t.toImplementation(new String[]{}); + return t.toImplementation(new String[]{""}); } @Override public String getDecomposedTuple(String tupleExp, VariableDeclaration tupleVar, List vars) { String statements = ""; - statements += getVariableDeclaration(tupleVar.getType().getInterfaceTypeName(), 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().getInterfaceTypeName(), var.getName()) + statements += "\n" + newVariableDeclaration(var.getType(), var.getName()) + getAssignment() + getTupleGet(tupleVar.getName(), i, vars.size()) + getStatementDelimiter(); @@ -354,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 b744713..0000000 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ /dev/null @@ -1,1594 +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) { - 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. - 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) { - 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 && resourceNode.getResourceHierarchy().getParent().getParent() != null) { - 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) { - 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 fdfd502..0000000 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ /dev/null @@ -1,1728 +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 - 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); - } - String resourceAccess = resExp.toImplementation(new String[] {""}); - 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++; - } - update.addStatement(resourceAccess + "." + 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().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)); - 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)); - } - 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)); - 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)); - } - 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 - 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); - } - String resourceAccess = resExp.toImplementation(new String[] {""}); - // 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 = ", "; - } - } - inputAccessor.addStatement(resourceAccess + "." + 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/Constant.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Constant.java index 50207b6..2b0e579 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Constant.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Constant.java @@ -1,16 +1,18 @@ package models.algebra; +import generators.JavaImplementationVisitor; + import java.util.ArrayList; public class Constant extends Term { - + public Constant(String value) { super(new Symbol(value, 0), new ArrayList()); } public Constant(String value, Type type) { - super(new Symbol((type == null ? value: type.valueToRepresentation(value)), 0), new ArrayList()); - symbol.setSignature(new Type[] {type}); + super(new Symbol((type == null ? value : type.valueToRepresentation(value)), 0), new ArrayList()); + symbol.setSignature(new Type[]{type}); } public Constant(Symbol symbol) { @@ -25,7 +27,7 @@ @Override public Object clone() { - Constant c = new Constant(symbol); + Constant c = new Constant(symbol); c.setType(type); return c; } @@ -42,10 +44,11 @@ } public String toImplementation(String[] sideEffects) { - if (symbol.isImplGenerative()) { - String exp = symbol.generate(getType(), new Type[] {}, new String[] {}, new String[] {}, sideEffects); - return exp; - } - return symbol.getImplName(); + return accept(new JavaImplementationVisitor(), sideEffects); + } + + @Override + public String accept(IExpressionVisitor visitor, String[] sideEffects) { + return visitor.visit(this, sideEffects); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Expression.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Expression.java index 7695979..65345a1 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Expression.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Expression.java @@ -4,29 +4,39 @@ public abstract class Expression implements Cloneable { public abstract Expression getSubTerm(Position pos); + /** * Get the unification between this expression and another expression. + * * @param another another expression * @return unified expression */ public abstract Expression unify(Expression another); + /** * Get the inverse map to obtain a sub-term of a given output value back from the output value itself. + * * @param outputValue an output value (usually a term) - * @param targetPos a position in outputValue + * @param targetPos a position in outputValue * @return inverse map */ public abstract Expression getInverseMap(Expression outputValue, Position targetPos); + public abstract boolean contains(Expression exp); + public abstract Object clone(); + public abstract HashMap getSubTerms(Class clazz); public HashMap getVariables() { return getSubTerms(Variable.class); } + public abstract String accept(IExpressionVisitor visitor, String[] sideEffects); + /** * Get the implementation of this expression. + * * @param sideEffects an array with an optional implementation that should be written before the evaluation of this expression * @return the implementation to represent the value of this expression */ diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java index 6702d3f..93076df 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Field.java @@ -1,21 +1,22 @@ package models.algebra; -import java.util.ArrayList; +import generators.JavaImplementationVisitor; /** * A field in the implementation (regarded as a constant in the algebraic system) + * * @author Nitta * */ public class Field extends Constant { - + public Field(String name) { super(name); } public Field(String name, Type type) { super(name); - symbol.setSignature(new Type[] {type}); + symbol.setSignature(new Type[]{type}); } public Field(Symbol symbol) { @@ -28,7 +29,7 @@ } return null; } - + @Override public boolean equals(Object another) { if (!(another instanceof Field)) return false; @@ -41,6 +42,11 @@ } public String toImplementation(String[] sideEffects) { - return "this." + super.toImplementation(sideEffects); + return accept(new JavaImplementationVisitor(), sideEffects); + } + + @Override + public String accept(IExpressionVisitor visitor, String[] sideEffects) { + return visitor.visit(this, sideEffects); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/IExpressionVisitor.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/IExpressionVisitor.java new file mode 100644 index 0000000..a8a88f5 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/IExpressionVisitor.java @@ -0,0 +1,18 @@ +package models.algebra; + +import models.dataConstraintModel.JsonAccessor; +import models.dataConstraintModel.JsonTerm; + +public interface IExpressionVisitor { + String visit(Term term, String[] sideEffects); + + String visit(Field field, String[] sideEffects); + + String visit(Constant constant, String[] sideEffects); + + String visit(Variable variable, String[] sideEffects); + + String visit(JsonTerm jsonTerm, String[] sideEffects); + + String visit(JsonAccessor jsonAccessor, String[] sideEffects); +} 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/Term.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java index 9cc7de2..72f71a8 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Term.java @@ -1,5 +1,7 @@ package models.algebra; +import generators.JavaImplementationVisitor; + import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -15,19 +17,19 @@ super(); this.symbol = symbol; } - + public Term(Symbol symbol, List children) { super(); this.symbol = symbol; this.children = children; } - + public Term(Symbol symbol, Expression[] children) { super(); this.symbol = symbol; this.children = new ArrayList<>(Arrays.asList(children)); } - + public Symbol getSymbol() { return symbol; } @@ -40,14 +42,14 @@ this.type = type; } - public Type getType() { + public Type getType() { if (type == null) { if (symbol.getSignature() == null) return null; return symbol.getSignature()[0]; } return type; } - + public boolean addChild(Expression child) { if (getArity() != -1 && children.size() >= getArity()) return false; children.add(child); @@ -59,7 +61,7 @@ children.set(n, child); return true; } - + public void addChild(Expression child, boolean bForced) { if (!bForced && getArity() != -1 && children.size() >= getArity()) return; children.add(child); @@ -91,7 +93,7 @@ for (int i = 0; i < children.size(); i++) { if (children.get(i) != null) { HashMap terms = children.get(i).getSubTerms(clazz); - for (Entry term: terms.entrySet()) { + for (Entry term : terms.entrySet()) { Position pos = term.getKey(); pos.addHeadOrder(i); subTerms.put(pos, term.getValue()); @@ -106,13 +108,14 @@ pos = (Position) pos.clone(); int i = pos.removeHeadOrder(); if (i >= children.size()) return null; + if (children.get(i) == null) return null; return children.get(i).getSubTerm(pos); } public Term substitute(Variable variable, Expression value) { Term newTerm = (Term) this.clone(); HashMap variables = getVariables(); - for (Entry varEnt: variables.entrySet()) { + for (Entry varEnt : variables.entrySet()) { if (varEnt.getValue().equals(variable)) { newTerm.replaceSubTerm(varEnt.getKey(), value); } @@ -143,12 +146,16 @@ if (children.size() != anotherTerm.children.size()) return null; Term unifiedTerm = new Term(symbol); for (int i = 0; i < children.size(); i++) { - unifiedTerm.addChild(children.get(i).unify(anotherTerm.children.get(i))); + if (children.get(i) != null) { + unifiedTerm.addChild(children.get(i).unify(anotherTerm.children.get(i))); + } else { + unifiedTerm.addChild(anotherTerm.children.get(i)); + } } return unifiedTerm; } else { return null; - } + } } public Expression reduce() { @@ -171,7 +178,7 @@ } } else if (symbol.isCalculatable()) { List newChildren = new ArrayList<>(); - for (Expression child: children) { + for (Expression child : children) { if (child instanceof Term) { child = ((Term) child).reduce(); } @@ -184,7 +191,7 @@ // Calculate inverse map List newChildren = new ArrayList<>(); boolean bReduced = false; - for (Expression child: children) { + for (Expression child : children) { if (child instanceof Term && !(child instanceof Constant)) { Expression newChild = ((Term) (child)).reduce(); if (newChild != child) { @@ -234,7 +241,7 @@ @Override public boolean contains(Expression exp) { if (equals(exp)) return true; - for (Expression e: children) { + for (Expression e : children) { if (e.contains(exp)) return true; } return false; @@ -265,7 +272,7 @@ @Override public Object clone() { Term newTerm = new Term(symbol); - for (Expression e: children) { + for (Expression e : children) { if (e != null) { newTerm.addChild((Expression) e.clone()); } else { @@ -292,7 +299,7 @@ } else { String exp = symbol.toString() + "("; String delimiter = ""; - for (Expression e: children) { + for (Expression e : children) { if (e != null) { exp += (delimiter + e.toString()); } else { @@ -303,141 +310,13 @@ return exp + ")"; } } - public String toImplementation(String[] sideEffects) { - int[] implParamOrder = symbol.getImplParamOrder(); - if (symbol.isImplLambda()) { - String[] components = symbol.getImplName().split("->"); - String component0 = components[0].replace("(", "").replace(")", ""); - String[] params = component0.split(","); - String exp = components[1]; - String receiver = ""; - if (implParamOrder == null) { - receiver = children.get(0).toImplementation(sideEffects); - exp = exp.replace(params[0], receiver); - for (int i = 1; i < params.length; i++) { - exp = exp.replace(params[i], children.get(i).toImplementation(sideEffects)); - } - } else { - receiver = children.get(implParamOrder[0]).toImplementation(sideEffects); - exp = exp.replace(params[0], receiver); - for (int i = 1; i < params.length; i++) { - exp = exp.replace(params[i], children.get(implParamOrder[i]).toImplementation(sideEffects)); - } - } - if (symbol.isImplWithSideEffect()) { - sideEffects[0] = sideEffects[0] + exp + ";\n"; - exp = receiver; - } - return exp; - } - if (symbol.isImplGenerative()) { - Type childrenTypes[] = new Type[children.size()]; - String childrenImpl[] = new String[children.size()]; - String childrenSideEffects[] = new String[children.size()]; - if (implParamOrder == null) { - for (int i = 0; i < children.size(); i++) { - Expression child = children.get(i); - if (child instanceof Variable) { - childrenTypes[i] = ((Variable) child).getType(); - } else if (child instanceof Term) { - childrenTypes[i] = ((Term) child).getType(); - } - String childSideEffect[] = new String[] {""}; - childrenImpl[i] = child.toImplementation(childSideEffect); - childrenSideEffects[i] = childSideEffect[0]; - } - String exp = symbol.generate(getType(), childrenTypes, childrenImpl, childrenSideEffects, sideEffects); - if (symbol.isImplWithSideEffect()) { - sideEffects[0] = sideEffects[0] + exp; - exp = childrenImpl[0]; // the value of this term - } - return exp; - } else { - for (int i = 0; i < children.size(); i++) { - Expression child = children.get(implParamOrder[i]); - if (child instanceof Variable) { - childrenTypes[i] = ((Variable) child).getType(); - } else if (child instanceof Term) { - childrenTypes[i] = ((Term) child).getType(); - } - String childSideEffect[] = new String[] {""}; - childrenImpl[i] = child.toImplementation(childSideEffect); - childrenSideEffects[i] = childSideEffect[0]; - } - String exp = symbol.generate(getType(), childrenTypes, childrenImpl, childrenSideEffects, sideEffects); - if (symbol.isImplWithSideEffect()) { - sideEffects[0] = sideEffects[0] + exp; - exp = childrenImpl[0]; // the value of this term - } - return exp; - } - } - if (getArity() == 2 && symbol.isImplInfix()) { - if (implParamOrder == null) { - return "(" + children.get(0).toImplementation(sideEffects) + symbol.toImplementation() + children.get(1).toImplementation(sideEffects) + ")"; - } else { - return "(" + children.get(implParamOrder[0]).toImplementation(sideEffects) + symbol.toImplementation() + children.get(implParamOrder[1]).toImplementation(sideEffects) + ")"; - } - } - if ((getArity() >= 1 || getArity() == -1) && symbol.isImplMethod()) { - if (implParamOrder == null) { - String exp = null; - String receiver = ""; - if (children.get(0) != null) { - receiver = children.get(0).toImplementation(sideEffects); - exp = receiver + "." + symbol.toImplementation() + "("; - } else { - exp = symbol.toImplementation() + "("; - } - String delimiter = ""; - for (int i = 1; i < children.size(); i++) { - Expression e = children.get(i); - exp += (delimiter + e.toImplementation(sideEffects)); - delimiter = ","; - } - exp += ")"; - if (symbol.isImplWithSideEffect()) { - sideEffects[0] = sideEffects[0] + exp + ";\n"; - exp = receiver; - } - return exp; - } else { - String receiver = children.get(implParamOrder[0]).toImplementation(sideEffects); - String exp = receiver + "." + symbol.toImplementation() + "("; - String delimiter = ""; - for (int i = 1; i < children.size(); i++) { - Expression e = children.get(implParamOrder[i]); - exp += (delimiter + e.toImplementation(sideEffects)); - delimiter = ","; - } - exp += ")"; - if (symbol.isImplWithSideEffect()) { - sideEffects[0] = sideEffects[0] + exp + ";\n"; - exp = receiver; - } - return exp; - } - } else { - if (implParamOrder == null) { - String exp = symbol.toImplementation() + "("; - String delimiter = ""; - for (Expression e: children) { - exp += (delimiter + e.toImplementation(sideEffects)); - delimiter = ","; - } - return exp + ")"; - } else { - String exp = symbol.toImplementation() + "("; - String delimiter = ""; - for (int i = 0; i < children.size(); i++) { - Expression e = children.get(implParamOrder[i]); - exp += (delimiter + e.toImplementation(sideEffects)); - delimiter = ","; - } - return exp + ")"; - } - } + return accept(new JavaImplementationVisitor(), sideEffects); + } + + @Override + public String accept(IExpressionVisitor visitor, String[] sideEffects) { + return visitor.visit(this, sideEffects); } } 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/algebra/Variable.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Variable.java index fa0095b..336a87f 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Variable.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Variable.java @@ -1,5 +1,7 @@ package models.algebra; +import generators.JavaImplementationVisitor; + import java.util.HashMap; public class Variable extends Expression { @@ -10,13 +12,13 @@ super(); this.name = name; } - + public Variable(String name, Type type) { super(); this.name = name; this.type = type; } - + public String getName() { return name; } @@ -24,11 +26,11 @@ public Type getType() { return type; } - + public void setType(Type type) { this.type = type; } - + @Override public HashMap getSubTerms(Class clazz) { HashMap subTerms = new HashMap<>(); @@ -48,18 +50,18 @@ public Expression unify(Expression another) { return (Expression) another.clone(); } - + @Override public Expression getInverseMap(Expression outputValue, Position targetPos) { if (targetPos.isEmpty()) return outputValue; return null; } - + @Override public boolean contains(Expression exp) { return equals(exp); } - + @Override public boolean equals(Object another) { if (!(another instanceof Variable)) return false; @@ -82,6 +84,11 @@ } public String toImplementation(String[] sideEffects) { - return name; + return accept(new JavaImplementationVisitor(), sideEffects); + } + + @Override + public String accept(IExpressionVisitor visitor, String[] sideEffects) { + return visitor.visit(this, sideEffects); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index 4a498b1..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) { @@ -772,6 +773,90 @@ return null; } }); + public static final Symbol search = new Symbol("search", 2, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { + final int count[] = {0}; + @Override + public String generate(Type type, Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { + for (String s: childrenSideEffects) { + sideEffect[0] += s; + } + String temp = "temp_search" + count[0]; + String impl = ""; + impl += "Map " + temp + " = new HashMap<>();\n"; + impl += "for (String key: " + childrenImpl[0] + ".keySet()) {\n"; + impl += "\tboolean isMatch = true;\n"; + impl += "\tfor (String qKey: " + childrenImpl[1] + ".keySet()) {\n"; + impl += "\t\tMap value = " + childrenImpl[0] + ".get(key).getValue();\n"; + impl += "\t\tfor (String valKey: value.keySet()) {\n"; + impl += "\t\t\tif (valKey.equals(qKey)) {\n"; + impl += "\t\t\t\tif (value.get(valKey).equals(" + childrenImpl[1] + ".get(qKey))) {\n"; + impl += "\t\t\t\t\tisMatch = false;\n"; + impl += "\t\t\t\t}\n"; + impl += "\t\t\t\tbreak;\n"; + impl += "\t\t\t}\n"; + impl += "\t\t}\n"; + impl += "\t\tif (!isMatch) break;\n"; + impl += "\t}\n"; + impl += "\tif (isMatch) {\n"; + impl += "\t\t" + temp + ".put(key, " + childrenImpl[0] + ".get(key));\n"; + impl += "\t}\n"; + impl += "}\n"; + sideEffect[0] += impl; + + count[0]++; + return temp; + } + }, new Symbol.ICalculator() { + @Override + public Expression calculate(List args) { + if (args.size() != 2) + return null; + + Expression arg0 = args.get(0); + if (!(arg0 instanceof MapTerm)) { + return null; + } + MapTerm searchFrom = (MapTerm) arg0; + + Expression arg1 = args.get(1); + if (arg1 instanceof JsonTerm) { + JsonTerm queryTerm = (JsonTerm) arg1; + MapTerm result = new MapTerm(); + + for (String key: searchFrom.keySet()) { + boolean isMatch = true; + if (searchFrom.get(key) instanceof JsonTerm) { + JsonTerm value = (JsonTerm) searchFrom.get(key); + for (String qKey: queryTerm.keySet()) { + for (String valKey: value.keySet()) { + if (value.get(valKey) instanceof Constant) { + Constant valVal = (Constant) value.get(valKey); + if (!(valKey.equals(qKey))) { + continue; + } + if (queryTerm.get(qKey) instanceof Constant) { + Constant qVal = (Constant) queryTerm.get(qKey); + if (!(valVal.getValue().equals(qVal.getValue()))) { + isMatch = false; + } + } + break; + } + } + if (!isMatch) break; + } + if (isMatch) { + result.insert(key, value); + } + } else if (searchFrom.get(key) instanceof MapTerm) { + } else if (searchFrom.get(key) instanceof ListTerm) { + } + } + return result; + } + return null; + } + }); public static final Symbol nil = new Symbol("nil", 0, Symbol.Type.PREFIX, new Symbol.IImplGenerator() { final int count[] = {0}; @Override @@ -797,7 +882,7 @@ count[0]++; return temp; } - } + } return "new ArrayList<" + compType + ">()"; } }, true); @@ -809,7 +894,7 @@ @Override public String generate(Type type, Type[] childrenTypes, String[] childrenImpl, String[] childrenSideEffects, String[] sideEffect) { String temp = "temp_if" + count[0]; - String impl = ""; + String impl = ""; impl += type.getInterfaceTypeName() + " " + temp + ";\n"; if (childrenSideEffects[0] != null && childrenSideEffects[0].length() > 0) impl += childrenSideEffects[0]; @@ -871,7 +956,8 @@ public static final Symbol lookup = new Symbol("lookup", 2, Symbol.Type.PREFIX, "get", Symbol.Type.METHOD, new Symbol.ICalculator() { @Override public Expression calculate(List args) { - if (args.get(1).getClass() == Constant.class && ((Constant) args.get(1)).getType().equals(typeString)) { + if (args.get(1).getClass() == Constant.class && + ((Constant) args.get(1)).getType() != null && ((Constant) args.get(1)).getType().equals(typeString)) { String key = (String) ((Constant) args.get(1)).getValue(); if (args.get(0) instanceof Term) { Term term = (Term) args.get(0); @@ -888,8 +974,8 @@ if (term instanceof MapTerm) { MapTerm mapTerm = (MapTerm) term.clone(); for (Map.Entry childEnt: appendedChldren) { - if (childEnt.getKey().getClass() == Constant.class) - mapTerm.insert((String) ((Constant) childEnt.getKey()).getValue(), childEnt.getValue()); + if (childEnt.getKey().getClass() == Constant.class) + mapTerm.insert((String) ((Constant) childEnt.getKey()).getValue(), childEnt.getValue()); } return mapTerm.get(key); } @@ -934,7 +1020,7 @@ public static final Symbol exp = new Symbol("exp", 1, Symbol.Type.PREFIX, "Math.exp", Symbol.Type.PREFIX); public static final Symbol log = new Symbol("log", 1, Symbol.Type.PREFIX, "Math.log", Symbol.Type.PREFIX); public static final Symbol abs = new Symbol("abs", 1, Symbol.Type.PREFIX, "Math.abs", Symbol.Type.PREFIX); - + static { add.setInverses(new Symbol[] {sub, sub}); mul.setInverses(new Symbol[] {div, div}); @@ -959,13 +1045,14 @@ tail.setSignature(new Type[] {typeList, typeList}); contains.setSignature(new Type[] {typeBoolean, null, null}); indexOf.setSignature(new Type[] {typeInt, typeList, null}); + search.setSignature(new Type[] {typeMap, typeMap, typeJson}); length.setSignature(new Type[] {typeInt, null}); get.setSignature(new Type[] {null, typeList, typeInt}); set.setSignature(new Type[] {typeList, typeList, typeInt, null}); null_.setSignature(new Type[] {null}); true_.setSignature(new Type[] {typeBoolean}); false_.setSignature(new Type[] {typeBoolean}); - pair.setSignature(new Type[] {typePair,null,null}); + pair.setSignature(new Type[] {typePair, null, null}); pair.setInverses(new Symbol[] {left, right}); left.setSignature(new Type[] {null, typePair}); right.setSignature(new Type[] {null, typePair}); @@ -1041,6 +1128,7 @@ addSymbol(tail); addSymbol(length); addSymbol(contains); + addSymbol(search); addSymbol(indexOf); addSymbol(get); addSymbol(set); @@ -1104,7 +1192,7 @@ do { hierarchy = resourcePath.getResourceHierarchy(); if (hierarchy != null && resourceHierarchies.get(hierarchy.toString()) == null) { - resourceHierarchies.put(hierarchy.toString(), hierarchy); + resourceHierarchies.put(hierarchy.toString(), hierarchy); } else { hierarchy = resourceHierarchies.get(hierarchy.toString()); resourcePath.setResourceHierarchy(hierarchy); @@ -1147,7 +1235,7 @@ public Collection getChannels() { return channels.values(); } - + public Channel getChannel(String channelName) { return channels.get(channelName); } @@ -1216,7 +1304,7 @@ } public boolean isPrimitiveType(Type type) { - if (type == typeInt + if (type == typeInt || type == typeLong || type == typeFloat || type == typeDouble diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java index 43e428c..1cf0c22 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonAccessor.java @@ -1,22 +1,15 @@ package models.dataConstraintModel; +import generators.JavaImplementationVisitor; +import models.algebra.*; + import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; -import models.algebra.Constant; -import models.algebra.Expression; -import models.algebra.LambdaAbstraction; -import models.algebra.Position; -import models.algebra.Symbol; -import models.algebra.Term; -import models.algebra.Type; -import models.algebra.Variable; - public class JsonAccessor extends Term { - + public JsonAccessor(Symbol symbol) { super(symbol); } @@ -61,10 +54,10 @@ } return value; } - if (json.getChild(0) == null - || (json.getChild(0) instanceof Term && - (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) - || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil))) return null; + if (json.getChild(0) == null + || (json.getChild(0) instanceof Term && + (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) + || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil))) return null; return getValue((Term) json.getChild(0), key); } } @@ -83,10 +76,10 @@ } return value; } - if (json.getChild(0) == null - || (json.getChild(0) instanceof Term && - (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) - || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil))) return null; + if (json.getChild(0) == null + || (json.getChild(0) instanceof Term && + (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) + || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil))) return null; return getValue((Term) json.getChild(0), key); } if (json.getSymbol().equals(DataConstraintModel.insert)) { @@ -97,15 +90,15 @@ } return value; } - if (json.getChild(0) == null - || (json.getChild(0) instanceof Term && - (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) - || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil))) return null; + if (json.getChild(0) == null + || (json.getChild(0) instanceof Term && + (((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.null_)) + || ((Term) json.getChild(0)).getSymbol().equals(DataConstraintModel.nil))) return null; return getValue((Term) json.getChild(0), key); } return new Constant(DataConstraintModel.null_); } - + @Override public Expression getInverseMap(Expression outputValue, Position targetPos) { if (targetPos.isEmpty()) return outputValue; @@ -139,8 +132,8 @@ keySet.add(keyName); } } - for (String key: keySet) { - Term addMemberTerm = new Term(DataConstraintModel.addMember); // addMember(jsonTerm, key, v) + for (String key : keySet) { + Term addMemberTerm = new Term(DataConstraintModel.addMember); // addMember(jsonTerm, key, v) addMemberTerm.addChild(jsonTerm); addMemberTerm.addChild(new Constant(key, DataConstraintModel.typeString)); Variable var = new Variable("v" + v); @@ -150,8 +143,8 @@ v++; } Variable var = vars.get(keyName); - LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, jsonTerm); // v -> addMember(jsonTerm, key, v) - inverseSymbols = new Symbol[] { lambdaAbstraction }; + LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, jsonTerm); // v -> addMember(jsonTerm, key, v) + inverseSymbols = new Symbol[]{lambdaAbstraction}; } } else if (symbol == DataConstraintModel.dotParam && getChildren().size() >= 2) { // this term is `json.{param}`. @@ -169,23 +162,23 @@ } else if (expKey instanceof Term) { keyType = ((Term) expKey).getType(); } - if (jsonType != null && keyType != null) { + if (jsonType != null && keyType != null) { if (DataConstraintModel.typeList.isAncestorOf(jsonType) || keyType.equals(DataConstraintModel.typeInt)) { - Term setElementTerm = new Term(DataConstraintModel.set); // set(list, idx, v) + Term setElementTerm = new Term(DataConstraintModel.set); // set(list, idx, v) setElementTerm.addChild(new Constant(DataConstraintModel.nil)); setElementTerm.addChild(expKey); Variable var = new Variable("v"); setElementTerm.addChild(var); - LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, setElementTerm); // v -> set(list, idx, v) - inverseSymbols = new Symbol[] { lambdaAbstraction }; + LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, setElementTerm); // v -> set(list, idx, v) + inverseSymbols = new Symbol[]{lambdaAbstraction}; } else if (DataConstraintModel.typeMap.isAncestorOf(jsonType) || keyType.equals(DataConstraintModel.typeString)) { - Term insertEntryTerm = new Term(DataConstraintModel.insert); // insert(map, key, v) + Term insertEntryTerm = new Term(DataConstraintModel.insert); // insert(map, key, v) insertEntryTerm.addChild(new Constant(DataConstraintModel.nil)); insertEntryTerm.addChild(expKey); Variable var = new Variable("v"); insertEntryTerm.addChild(var); - LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, insertEntryTerm); // v -> insert(map, key, v) - inverseSymbols = new Symbol[] { lambdaAbstraction }; + LambdaAbstraction lambdaAbstraction = new LambdaAbstraction(var, insertEntryTerm); // v -> insert(map, key, v) + inverseSymbols = new Symbol[]{lambdaAbstraction}; } } } @@ -212,16 +205,18 @@ } public String toImplementation(String[] sideEffects) { - if (symbol.equals(DataConstraintModel.dotParam)) { - return children.get(0).toImplementation(sideEffects) + "." + symbol.toImplementation() + "(" + children.get(1).toImplementation(sideEffects) + ")"; - } - return super.toImplementation(sideEffects); + return accept(new JavaImplementationVisitor(), sideEffects); + } + + @Override + public String accept(IExpressionVisitor visitor, String[] sideEffects) { + return visitor.visit(this, sideEffects); } @Override public Object clone() { JsonAccessor newTerm = new JsonAccessor(symbol); - for (Expression e: children) { + for (Expression e : children) { newTerm.addChild((Expression) e.clone()); } newTerm.type = type; diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java index 3998afa..608a27e 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/JsonTerm.java @@ -1,20 +1,18 @@ package models.dataConstraintModel; +import generators.JavaImplementationVisitor; +import models.algebra.*; +import parser.Parser; + import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import models.algebra.Constant; -import models.algebra.Expression; -import models.algebra.Symbol; -import models.algebra.Term; -import models.algebra.Variable; -import parser.Parser; - public class JsonTerm extends Term { private Map keyToIndex = new HashMap<>(); - + private static int count = 0; + public JsonTerm() { super(new Symbol("json", -1)); setType(DataConstraintModel.typeJson); @@ -32,17 +30,17 @@ public Set keySet() { return keyToIndex.keySet(); } - + public Expression get(String key) { if (keyToIndex.get(key) == null) return null; return getChild(keyToIndex.get(key)); } - + public Expression get(Constant key) { if (keyToIndex.get(key.getValue()) == null) return null; return getChild(keyToIndex.get(key.getValue())); } - + public Expression get(Variable key) { if (keyToIndex.get(key.getName()) == null) return null; return getChild(keyToIndex.get(key.getName())); @@ -55,8 +53,8 @@ JsonTerm unifiedTerm = new JsonTerm(); Set keySet = new HashSet<>(); keySet.addAll(this.keySet()); - keySet.addAll(anotherTerm.keySet()); - for (String key: keySet) { + keySet.addAll(anotherTerm.keySet()); + for (String key : keySet) { if (this.keySet().contains(key)) { if (anotherTerm.keySet().contains(key)) { unifiedTerm.addMember(key, this.get(key).unify(anotherTerm.get(key))); @@ -75,7 +73,7 @@ @Override public Object clone() { JsonTerm newTerm = new JsonTerm(); - for (Expression e: children) { + for (Expression e : children) { newTerm.addChild((Expression) e.clone()); } newTerm.keyToIndex = new HashMap(keyToIndex); @@ -85,10 +83,19 @@ public String toString() { String jsonStr = "{"; String delim = ""; - for (String key: keyToIndex.keySet()) { + for (String key : keyToIndex.keySet()) { jsonStr += delim + Parser.DOUBLE_QUOT + key + Parser.DOUBLE_QUOT + ": " + getChild(keyToIndex.get(key)).toString(); delim = ", "; } return jsonStr + "}"; } + + public String toImplementation(String[] sideEffects) { + return accept(new JavaImplementationVisitor(), sideEffects); + } + + @Override + public String accept(IExpressionVisitor visitor, String[] sideEffects) { + return visitor.visit(this, sideEffects); + } } 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 new file mode 100644 index 0000000..784fab2 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/tests/ASTTest.java @@ -0,0 +1,74 @@ +package tests; + +import code.ast.*; +import generators.JavaSpecific; +import models.algebra.Symbol; +import models.algebra.Term; +import models.dataConstraintModel.DataConstraintModel; +import org.junit.Test; + +import java.util.List; + +public class ASTTest { + @Test + public void test() { + + JavaSpecific javaGen = new JavaSpecific(); + MethodDeclaration methodDeclaration = javaGen.newMethodDeclaration("Test", DataConstraintModel.typeInt); + Block methodBody = new Block(); + + VariableDeclarationStatement variableDeclarationStatement = new VariableDeclarationStatement(); + VariableDeclaration varX = javaGen.newVariableDeclaration(DataConstraintModel.typeInt, "x"); + varX.setInitializer(new Constant("20")); + VariableDeclaration varSum = javaGen.newVariableDeclaration(DataConstraintModel.typeInt, "sum"); + varSum.setInitializer(new Constant("0")); + variableDeclarationStatement.addFragment(varX); + variableDeclarationStatement.addFragment(varSum); + methodBody.addStatement(variableDeclarationStatement); + + 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")) + )); + forStatement.setBody(forBody); + methodBody.addStatement(forStatement); + + VariableDeclaration stringVarDec = javaGen.newVariableDeclaration(DataConstraintModel.typeString, "s"); + EnhancedForStatement enhancedForStatement = javaGen.getForStatementForCollection(stringVarDec, "list"); + + Block efBody = new Block(); + efBody.addStatement("System.out.println(s);"); + enhancedForStatement.setBody(efBody); + methodBody.addStatement(enhancedForStatement); + + Term moduloTerm = new Term(new Symbol("%", 2, Symbol.Type.INFIX)); + moduloTerm.addChild(new models.algebra.Variable("sum")); + moduloTerm.addChild(new models.algebra.Constant("2")); + + Term ifCondTerm = new Term(new Symbol("==", 2, Symbol.Type.INFIX)); + ifCondTerm.addChild(moduloTerm); + ifCondTerm.addChild(new models.algebra.Constant("0"));Block thenBlock = new Block(); + thenBlock.addStatement(new ExpressionStatement(new InfixExpression(new Symbol("+=", 2, Symbol.Type.INFIX), new Variable("sum"), new Constant("10")))); + + IfStatement ifStmt = javaGen.getIfStatement(ifCondTerm, thenBlock); + Block elseB = new Block(); + elseB.addStatement(new ExpressionStatement(new InfixExpression(new Symbol("+=", 2, Symbol.Type.INFIX), new Variable("sum"), new Constant("5")))); + ifStmt.setElseStatement(elseB); + Block whileBody = new Block(); + whileBody.addStatement(ifStmt); + WhileStatement whileStmt = new WhileStatement(); + whileStmt.setExpression(new InfixExpression(new Symbol("<", 2, Symbol.Type.INFIX), new Variable("sum"), new Constant("100"))); + whileStmt.setBody(whileBody); + methodBody.addStatement(whileStmt); + + methodBody.addStatement(javaGen.getReturnStatement("sum")); + + methodDeclaration.setBody(methodBody); + System.out.println("--- Generated Code ---"); + System.out.println(methodDeclaration.toString()); + + } +} \ No newline at end of file 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 9df8290..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.*; @@ -376,90 +374,6 @@ Entry, // arg types Integer>>>>>>> // lines of code exprectedStructure = new HashMap<>(); - exprectedStructure.put("Groups", Map.entry(Set.of("@Path(\"/groups\")","@Component"), - Map.entry(Map.ofEntries(Map.entry("value", "Map")), - Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("Map", - Map.entry(List.of(), - 1)))), - Map.entry("getGroup", Map.entry(Set.of(), - Map.entry("Group", - Map.entry(List.of("String"), - 1)))), - Map.entry("getMembersValue", Map.entry(Set.of("@Path(\"/{gid}/members\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("List", - Map.entry(List.of("String"), - 1)))), - Map.entry("getMessagesValue", Map.entry(Set.of("@Path(\"/{gid}/messages\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("List", - Map.entry(List.of("String"), - 1)))), - Map.entry("getGroupValue", Map.entry(Set.of("@Path(\"/{gid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("Map", - Map.entry(List.of("String"), - 1)))), - Map.entry("addGroupMember", Map.entry(Set.of("@Path(\"/{gid}/members\")","@POST"), - Map.entry("void", - Map.entry(List.of("String","String"), - 1)))), - Map.entry("postMessage", Map.entry(Set.of("@Path(\"/{gid}/messages\")","@POST"), - Map.entry("void", - Map.entry(List.of("String","String"), - 1)))), - Map.entry("createGroup", Map.entry(Set.of("@POST"), - Map.entry("void", - Map.entry(List.of("String"), - 1)))))))); - exprectedStructure.put("Account", Map.entry(Set.of(), - Map.entry(Map.ofEntries(Map.entry("notifications", "Map")), - Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), - Map.entry("Map", - Map.entry(List.of(), - 1)))), - Map.entry("getNotifications", Map.entry(Set.of(), - Map.entry("Map", - Map.entry(List.of(), - 1)))), - Map.entry("updateNotificationsFromMessages", Map.entry(Set.of(), - Map.entry("void", - Map.entry(List.of("String","String","int","List","String"), - 1)))), - Map.entry("hasRead", Map.entry(Set.of(), - Map.entry("void", - Map.entry(List.of("String","String"), - 1)))), - Map.entry("Account", Map.entry(Set.of(), - Map.entry("void", - Map.entry(List.of("Map"), - 1)))))))); - exprectedStructure.put("Group", Map.entry(Set.of(), - Map.entry(Map.ofEntries(Map.entry("messages", "List"), - Map.entry("client", "Client"), - Map.entry("members", "List")), - Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), - Map.entry("Map", - Map.entry(List.of(), - 1)))), - Map.entry("getMessages", Map.entry(Set.of(), - Map.entry("List", - Map.entry(List.of(), - 1)))), - Map.entry("getMembers", Map.entry(Set.of(), - Map.entry("List", - Map.entry(List.of(), - 1)))), - Map.entry("postMessage", Map.entry(Set.of(), - Map.entry("void", - Map.entry(List.of("String","String"), - 6)))), - Map.entry("addGroupMember", Map.entry(Set.of(), - Map.entry("void", - Map.entry(List.of("String","String"), - 1)))), - Map.entry("Group", Map.entry(Set.of(), - Map.entry("void", - Map.entry(List.of("List","List"), - 2)))))))); exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"), Map.entry(Map.ofEntries(Map.entry("value", "Map")), Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), @@ -470,7 +384,15 @@ Map.entry("Account", Map.entry(List.of("String"), 1)))), - Map.entry("updateNotificationsFromMessages", Map.entry(Set.of("@Path(\"accounts/{v1}/notifications\")","@POST"), + Map.entry("signUp", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String"), + 1)))), + Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{v1}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("updateNotificationsFromMessages", Map.entry(Set.of("@Path(\"/{v1}/notifications\")","@POST"), Map.entry("void", Map.entry(List.of("String","String","int","List","String"), 1)))), @@ -478,18 +400,102 @@ Map.entry("Map", Map.entry(List.of("String"), 1)))), - Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{v1}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("Map", - Map.entry(List.of("String"), - 1)))), Map.entry("hasRead", Map.entry(Set.of("@Path(\"/{aid}/notifications\")","@DELETE"), Map.entry("void", Map.entry(List.of("String","String"), + 1)))))))); + exprectedStructure.put("Account", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("notifications", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), 1)))), - Map.entry("signUp", Map.entry(Set.of("@POST"), + Map.entry("updateNotificationsFromMessages", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String","int","List","String"), + 1)))), + Map.entry("getNotifications", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("hasRead", Map.entry(Set.of(), Map.entry("void", - Map.entry(List.of("String"), + Map.entry(List.of("String","String"), + 1)))), + Map.entry("Account", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("Map"), 1)))))))); + exprectedStructure.put("Group", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("members", "List"), + Map.entry("client", "Client"), + Map.entry("messages", "List")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getMember", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of("int"), + 1)))), + Map.entry("getMembers", Map.entry(Set.of(), + Map.entry("List", + Map.entry(List.of(), + 1)))), + Map.entry("addGroupMember", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("getMessages", Map.entry(Set.of(), + Map.entry("List", + Map.entry(List.of(), + 1)))), + Map.entry("postMessage", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), + 2)))), + Map.entry("Group", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("List","List"), + 2)))))))); + exprectedStructure.put("Groups", Map.entry(Set.of("@Path(\"/groups\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getGroup", Map.entry(Set.of(), + Map.entry("Group", + Map.entry(List.of("String"), + 1)))), + Map.entry("getMemberValue", Map.entry(Set.of("@Path(\"/{gid}/members/{mno}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String","int"), + 1)))), + Map.entry("getMembersValue", Map.entry(Set.of("@Path(\"/{gid}/members\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("List", + Map.entry(List.of("String"), + 1)))), + Map.entry("addGroupMember", Map.entry(Set.of("@Path(\"/{gid}/members\")","@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("getGroupValue", Map.entry(Set.of("@Path(\"/{gid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("createGroup", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String"), + 1)))), + Map.entry("getMessagesValue", Map.entry(Set.of("@Path(\"/{gid}/messages\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("List", + Map.entry(List.of("String"), + 1)))), + Map.entry("postMessage", Map.entry(Set.of("@Path(\"/{gid}/messages\")","@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))))); checkStructure(generatedCode, exprectedStructure); // generateCheckCode(generatedCode); @@ -731,52 +737,57 @@ Entry, // arg types Integer>>>>>>> // lines of code exprectedStructure = new HashMap<>(); - exprectedStructure.put("Rooms", Map.entry(Set.of("@Path(\"/rooms\")","@Component"), - Map.entry(Map.ofEntries(Map.entry("value", "Map")), - Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("Map", + exprectedStructure.put("Room", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("members", "Members"), + Map.entry("client", "Client"), + Map.entry("battle", "boolean")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getMembers", Map.entry(Set.of(), + Map.entry("Members", + Map.entry(List.of(), + 1)))), + Map.entry("getBattle", Map.entry(Set.of(), + Map.entry("boolean", Map.entry(List.of(), 1)))), - Map.entry("getRoom", Map.entry(Set.of(), - Map.entry("Room", - Map.entry(List.of("String"), - 1)))), - Map.entry("getIdValue", Map.entry(Set.of("@Path(\"/{rid}/members/{mno}/id\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("String", - Map.entry(List.of("String","int"), + Map.entry("battle", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","boolean"), + 2)))), + Map.entry("Room", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("boolean"), + 1)))))))); + exprectedStructure.put("Account", Map.entry(Set.of(), + Map.entry(Map.ofEntries(Map.entry("name", "String"), + Map.entry("point", "int")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), + Map.entry("Map", + Map.entry(List.of(), 1)))), - Map.entry("getBattleValue", Map.entry(Set.of("@Path(\"/{rid}/battle\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("boolean", - Map.entry(List.of("String"), - 1)))), - Map.entry("getRoomValue", Map.entry(Set.of("@Path(\"/{rid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("Map", - Map.entry(List.of("String"), + Map.entry("getName", Map.entry(Set.of(), + Map.entry("String", + Map.entry(List.of(), + 1)))), + Map.entry("changeName", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String"), 1)))), - Map.entry("getMemberValue", Map.entry(Set.of("@Path(\"/{rid}/members/{mno}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("Map", - Map.entry(List.of("String","int"), - 1)))), - Map.entry("getMembersValue", Map.entry(Set.of("@Path(\"/{rid}/members\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("List", - Map.entry(List.of("String"), - 1)))), - Map.entry("getNameValue", Map.entry(Set.of("@Path(\"/{rid}/members/{mno}/name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("String", - Map.entry(List.of("String","int"), - 1)))), - Map.entry("battle", Map.entry(Set.of("@Path(\"/{rid}/battle\")","@PUT"), - Map.entry("void", - Map.entry(List.of("String","boolean"), - 1)))), - Map.entry("addRoomMember", Map.entry(Set.of("@Path(\"/{rid}/members\")","@POST"), - Map.entry("void", - Map.entry(List.of("String","String"), - 1)))), - Map.entry("createRoom", Map.entry(Set.of("@POST"), - Map.entry("void", - Map.entry(List.of("String"), - 1)))))))); + Map.entry("updatePointFromBattle", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","String","int","boolean","String"), + 1)))), + Map.entry("getPoint", Map.entry(Set.of(), + Map.entry("int", + Map.entry(List.of(), + 1)))), + Map.entry("Account", Map.entry(Set.of(), + Map.entry("void", + Map.entry(List.of("String","int"), + 2)))))))); exprectedStructure.put("Member", Map.entry(Set.of(), Map.entry(Map.ofEntries(Map.entry("id", "String"), Map.entry("client", "Client")), @@ -796,91 +807,6 @@ Map.entry("void", Map.entry(List.of("String"), 1)))))))); - exprectedStructure.put("Account", Map.entry(Set.of(), - Map.entry(Map.ofEntries(Map.entry("name", "String"), - Map.entry("point", "int")), - Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), - Map.entry("Map", - Map.entry(List.of(), - 1)))), - Map.entry("getName", Map.entry(Set.of(), - Map.entry("String", - Map.entry(List.of(), - 1)))), - Map.entry("getPoint", Map.entry(Set.of(), - Map.entry("int", - Map.entry(List.of(), - 1)))), - Map.entry("updatePointFromBattle", Map.entry(Set.of(), - Map.entry("void", - Map.entry(List.of("String","String","int","boolean","String"), - 1)))), - Map.entry("changeName", Map.entry(Set.of(), - Map.entry("void", - Map.entry(List.of("String","String"), - 1)))), - Map.entry("Account", Map.entry(Set.of(), - Map.entry("void", - Map.entry(List.of("String","int"), - 2)))))))); - exprectedStructure.put("Room", Map.entry(Set.of(), - Map.entry(Map.ofEntries(Map.entry("members", "Members"), - Map.entry("battle", "boolean"), - Map.entry("client", "Client")), - Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), - Map.entry("Map", - Map.entry(List.of(), - 1)))), - Map.entry("getMembers", Map.entry(Set.of(), - Map.entry("Members", - Map.entry(List.of(), - 1)))), - Map.entry("getBattle", Map.entry(Set.of(), - Map.entry("boolean", - Map.entry(List.of(), - 1)))), - Map.entry("battle", Map.entry(Set.of(), - Map.entry("void", - Map.entry(List.of("String","boolean"), - 6)))), - Map.entry("Room", Map.entry(Set.of(), - Map.entry("void", - Map.entry(List.of("boolean"), - 1)))))))); - exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"), - Map.entry(Map.ofEntries(Map.entry("value", "Map")), - Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("Map", - Map.entry(List.of(), - 1)))), - Map.entry("getAccount", Map.entry(Set.of(), - Map.entry("Account", - Map.entry(List.of("String"), - 1)))), - Map.entry("updatePointFromBattle", Map.entry(Set.of("@Path(\"accounts/{mid}/point\")","@POST"), - Map.entry("void", - Map.entry(List.of("String","String","int","boolean","String"), - 1)))), - Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{mid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("Map", - Map.entry(List.of("String"), - 1)))), - Map.entry("getNameValue", Map.entry(Set.of("@Path(\"/{mid}/name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("String", - Map.entry(List.of("String"), - 1)))), - Map.entry("getPointValue", Map.entry(Set.of("@Path(\"/{mid}/point\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), - Map.entry("int", - Map.entry(List.of("String"), - 1)))), - Map.entry("signUp", Map.entry(Set.of("@POST"), - Map.entry("void", - Map.entry(List.of("String","String"), - 1)))), - Map.entry("changeName", Map.entry(Set.of("@Path(\"/{aid}/name\")","@PUT"), - Map.entry("void", - Map.entry(List.of("String","String"), - 1)))))))); exprectedStructure.put("Members", Map.entry(Set.of(), Map.entry(Map.ofEntries(Map.entry("value", "List")), Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(), @@ -895,8 +821,88 @@ Map.entry("void", Map.entry(List.of("String","String"), 1)))))))); + exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getAccount", Map.entry(Set.of(), + Map.entry("Account", + Map.entry(List.of("String"), + 1)))), + Map.entry("getNameValue", Map.entry(Set.of("@Path(\"/{mid}/name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String"), + 1)))), + Map.entry("changeName", Map.entry(Set.of("@Path(\"/{aid}/name\")","@PUT"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{mid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("updatePointFromBattle", Map.entry(Set.of("@Path(\"/{mid}/point\")","@POST"), + Map.entry("void", + Map.entry(List.of("String","String","int","boolean","String"), + 1)))), + Map.entry("getPointValue", Map.entry(Set.of("@Path(\"/{mid}/point\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("int", + Map.entry(List.of("String"), + 1)))), + Map.entry("signUp", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))))))); + exprectedStructure.put("Rooms", Map.entry(Set.of("@Path(\"/rooms\")","@Component"), + Map.entry(Map.ofEntries(Map.entry("value", "Map")), + Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of(), + 1)))), + Map.entry("getRoom", Map.entry(Set.of(), + Map.entry("Room", + Map.entry(List.of("String"), + 1)))), + Map.entry("getRoomValue", Map.entry(Set.of("@Path(\"/{rid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String"), + 1)))), + Map.entry("getBattleValue", Map.entry(Set.of("@Path(\"/{rid}/battle\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("boolean", + Map.entry(List.of("String"), + 1)))), + Map.entry("battle", Map.entry(Set.of("@Path(\"/{rid}/battle\")","@PUT"), + Map.entry("void", + Map.entry(List.of("String","boolean"), + 1)))), + Map.entry("getIdValue", Map.entry(Set.of("@Path(\"/{rid}/members/{mno}/id\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String","int"), + 1)))), + Map.entry("getNameValue", Map.entry(Set.of("@Path(\"/{rid}/members/{mno}/name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("String", + Map.entry(List.of("String","int"), + 1)))), + Map.entry("getMemberValue", Map.entry(Set.of("@Path(\"/{rid}/members/{mno}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("Map", + Map.entry(List.of("String","int"), + 1)))), + Map.entry("getMembersValue", Map.entry(Set.of("@Path(\"/{rid}/members\")","@Produces(MediaType.APPLICATION_JSON)","@GET"), + Map.entry("List", + Map.entry(List.of("String"), + 1)))), + Map.entry("addRoomMember", Map.entry(Set.of("@Path(\"/{rid}/members\")","@POST"), + Map.entry("void", + Map.entry(List.of("String","String"), + 1)))), + Map.entry("createRoom", Map.entry(Set.of("@POST"), + Map.entry("void", + Map.entry(List.of("String"), + 1)))))))); - checkStructure(generatedCode, exprectedStructure); + checkStructure(generatedCode, exprectedStructure); // generateCheckCode(generatedCode); } catch (FileNotFoundException | ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword @@ -1100,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(), @@ -1274,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()); +// ArrayList codetree = JerseyMethodBodyGenerator.doGenerate(graph, model, JerseyCodeGenerator.doGenerate(graph, model)); + 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 b9a5dc0..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()); +// ArrayList codetree = JavaMethodBodyGenerator.doGenerate(graph, model, JavaCodeGenerator.doGenerate(graph, model)); + 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);