diff --git a/solve/build.gradle b/solve/build.gradle index ee359bd29b2f25e963b1da7223a364a8623118d4..70bdcd6bc8b7843bf5f6c405598368923de6bd6c 100644 --- a/solve/build.gradle +++ b/solve/build.gradle @@ -40,6 +40,20 @@ task testMain(type: JavaExec, dependsOn: assemble) { main = 'de.tudresden.inf.st.ttc18live.Main' } +task preprocess(type: JavaExec) { + group = 'Build' + main = "-jar" + args = [ + "libs/relast-compiler.jar", + "./src/main/jastadd/SocialNetwork.relast", + "--listClass=RefList", + "--file" + ] + + inputs.files file("./src/main/jastadd/SocialNetwork.relast") + outputs.files file("./src/main/jastadd/SocialNetworkGen.ast"), file("./src/main/jastadd/SocialNetworkGen.jadd") +} + task jastadd(type: JavaExec) { group = 'Build' main = "-jar" @@ -53,7 +67,7 @@ task jastadd(type: JavaExec) { "--package=de.tudresden.inf.st.ttc18live.jastadd.model", "--o=src/gen/java", "--tracing", - ] + fileTree("./src/main/jastadd/") + ] + fileTree("./src/main/jastadd/").matching {exclude "*.relast"} doFirst { print("Calling jastadd2.jar " + fileTree("./src/main/jastadd/") + '\n') @@ -76,6 +90,8 @@ sourceSets { // always run tests test.outputs.upToDateWhen {false} +// Comment this in to regenerate the generated AST +//jastadd.dependsOn preprocess compileJava.dependsOn jastadd // always run jastadd diff --git a/solve/libs/relast-compiler.jar b/solve/libs/relast-compiler.jar new file mode 100644 index 0000000000000000000000000000000000000000..2be3103df77d31dd78987c3988a8925d9316ab12 Binary files /dev/null and b/solve/libs/relast-compiler.jar differ diff --git a/solve/src/main/jastadd/ApplyChanges.jadd b/solve/src/main/jastadd/ApplyChanges.jadd index 4255a3a7566a357d03efc9ff58235ac24ed0f1ea..d449578d85ff0d18d4f4d2a821c7fc73e685f851 100644 --- a/solve/src/main/jastadd/ApplyChanges.jadd +++ b/solve/src/main/jastadd/ApplyChanges.jadd @@ -25,19 +25,19 @@ aspect ApplyChanges { java.util.Objects.requireNonNull(getAddedElement(), () -> "Added Element was null in " + this); Submission submission = java.util.Objects.requireNonNull(getAddedElement().asSubmission(), () -> "Was no submission, instead " + getAddedElement()); - user.addSubmission(submission.createSubmissionRef()); + user.addToSubmissions(submission); return; case "friends": java.util.Objects.requireNonNull(getAddedElement(), () -> "Added Element was null in " + this); User friend = java.util.Objects.requireNonNull(getAddedElement().asUser(), () -> "Was no user, instead " + getAddedElement()); - user.addFriend(friend.createUserRef()); + user.addToFriends(friend); return; case "likes": java.util.Objects.requireNonNull(getAddedElement(), () -> "Added Element was null in " + this); Comment like = java.util.Objects.requireNonNull(getAddedElement().asComment(), () -> "Was no comment, instead " + getAddedElement()); - user.addLike(like.createCommentRef()); + user.addToLikes(like); return; } } diff --git a/solve/src/main/jastadd/Checking.jrag b/solve/src/main/jastadd/Checking.jrag index f6bdc03043582c05e6d89a6124b71bf619cea08f..a485b1eb144613c19d9340bc2ee4831fdcf44c92 100644 --- a/solve/src/main/jastadd/Checking.jrag +++ b/solve/src/main/jastadd/Checking.jrag @@ -1,6 +1,6 @@ aspect Checking { - boolean ModelElement.checkGeneralListValid(List<? extends ASTNode> listToCheck, String nonterminalName) { + boolean ModelElement.checkGeneralListValid(java.util.List<? extends ASTNode> listToCheck, String nonterminalName) { boolean valid = true; for (ASTNode node : listToCheck) { if (node == null) { @@ -40,9 +40,9 @@ aspect Checking { } eq User.isValid() { - return checkGeneralListValid(getFriendList(), "Friend") && - checkGeneralListValid(getSubmissionList(), "Submission") && - checkGeneralListValid(getLikeList(), "Like") && checkThat(getName() != null, "User" + getId() + ".Name == null"); + return checkGeneralListValid(friends(), "Friend") && + checkGeneralListValid(submissions(), "Submission") && + checkGeneralListValid(likes(), "Like") && checkThat(getName() != null, "User" + getId() + ".Name == null"); } eq Submission.isValid() { diff --git a/solve/src/main/jastadd/ModelNavigation.jrag b/solve/src/main/jastadd/ModelNavigation.jrag index 91d4ebae3170796fd7b30bd2126752e76084c4d6..9cc5ed4da66b47b82f8ac900e35338e4a912c7db 100644 --- a/solve/src/main/jastadd/ModelNavigation.jrag +++ b/solve/src/main/jastadd/ModelNavigation.jrag @@ -56,25 +56,6 @@ aspect ModelNavigation { return posts; } - // =================================================================================================================== - // relations replica - // =================================================================================================================== - - syn java.util.List<User> Comment.getLikedBy() = socialNetwork().getLikedByMap().get(this); - - syn Map<Comment, java.util.List<User>> SocialNetwork.getLikedByMap() { - Map<Comment, java.util.List<User>> result = new HashMap(); - for (Comment comment : comments()) { - result.put(comment, new java.util.ArrayList<>()); - } - for (User user : getUserList()) { - for (CommentRef commentRef : user.getLikes()) { - result.get(commentRef.getComment()).add(user); - } - } - return result; - } - // =================================================================================================================== // root access // =================================================================================================================== diff --git a/solve/src/main/jastadd/RefList.jadd b/solve/src/main/jastadd/RefList.jadd new file mode 100644 index 0000000000000000000000000000000000000000..a0566565528518a7d4fe5fa35b57aa4f9a32062b --- /dev/null +++ b/solve/src/main/jastadd/RefList.jadd @@ -0,0 +1,3 @@ +aspect RefList { + public class RefList<T extends ASTNode> extends java.util.ArrayList<T> {} +} diff --git a/solve/src/main/jastadd/SocialNetwork.relast b/solve/src/main/jastadd/SocialNetwork.relast new file mode 100644 index 0000000000000000000000000000000000000000..929751f19b3336b21a456ccb2c52bad74b864742 --- /dev/null +++ b/solve/src/main/jastadd/SocialNetwork.relast @@ -0,0 +1,13 @@ +abstract ModelElement ::= <Id:Long> ; +SocialNetwork : ModelElement ::= User* Post* ; + +User:ModelElement ::= <Name:String> ; + +abstract Submission : ModelElement ::= <Timestamp:Long> <Content:String> Comment* ; +// Comment : Submission ::= /<Post:Post>/ ; +Comment : Submission ::= <Post:Post> ; +Post : Submission ::= ; + +rel User.friends* -> User ; +rel User.submissions* -> Submission ; +rel User.likes* <-> Comment.likedBy* ; diff --git a/solve/src/main/jastadd/SocialNetworkGen.ast b/solve/src/main/jastadd/SocialNetworkGen.ast new file mode 100644 index 0000000000000000000000000000000000000000..8a3d32f824591f4a6484b427b86bc04ddc7181ba --- /dev/null +++ b/solve/src/main/jastadd/SocialNetworkGen.ast @@ -0,0 +1,6 @@ +abstract ModelElement ::= <Id:Long>; +SocialNetwork : ModelElement ::= User* Post*; +User : ModelElement ::= <Name:String> <_impl_friends:RefList<User>> <_impl_submissions:RefList<Submission>> <_impl_likes:RefList<Comment>>; +abstract Submission : ModelElement ::= <Timestamp:Long> <Content:String> Comment*; +Comment : Submission ::= /<Post:Post>/ <_impl_likedBy:RefList<User>>; +Post : Submission; diff --git a/solve/src/main/jastadd/SocialNetworkGen.jadd b/solve/src/main/jastadd/SocialNetworkGen.jadd new file mode 100644 index 0000000000000000000000000000000000000000..0400cf4dcfefc74080e08b57a13e58ce0fa9e704 --- /dev/null +++ b/solve/src/main/jastadd/SocialNetworkGen.jadd @@ -0,0 +1,157 @@ +import java.util.ArrayList; +import java.util.Collections; +aspect RelAstAPI { + public User.User(Long Id, String Name) { + setId(Id); + setName(Name); + } + public Comment.Comment(Long Id, Long Timestamp, String Content, List<Comment> Comment) { + setId(Id); + setTimestamp(Timestamp); + setContent(Content); + setCommentList(Comment); + } + // rel User.friends* -> User + public java.util.List<User> User.friends() { + RefList<User> l = get_impl_friends(); + return l != null ? Collections.unmodifiableList(l) : Collections.emptyList(); + } + public void User.addToFriends(User o) { + assertNotNull(o); + RefList<User> list = get_impl_friends(); + if (list == null) { + list = new RefList<>(); + } + list.add(o); + set_impl_friends(list); + } + public void User.removeFromFriends(User o) { + assertNotNull(o); + RefList<User> list = get_impl_friends(); + if (list != null && list.remove(o)) { + set_impl_friends(list); + } + } + + // rel User.submissions* -> Submission + public java.util.List<Submission> User.submissions() { + RefList<Submission> l = get_impl_submissions(); + return l != null ? Collections.unmodifiableList(l) : Collections.emptyList(); + } + public void User.addToSubmissions(Submission o) { + assertNotNull(o); + RefList<Submission> list = get_impl_submissions(); + if (list == null) { + list = new RefList<>(); + } + list.add(o); + set_impl_submissions(list); + } + public void User.removeFromSubmissions(Submission o) { + assertNotNull(o); + RefList<Submission> list = get_impl_submissions(); + if (list != null && list.remove(o)) { + set_impl_submissions(list); + } + } + + // rel User.likes* <-> Comment.likedBy* + public java.util.List<Comment> User.likes() { + RefList<Comment> l = get_impl_likes(); + return l != null ? Collections.unmodifiableList(l) : Collections.emptyList(); + } + public void User.addToLikes(Comment o) { + assertNotNull(o); + RefList<Comment> list = get_impl_likes(); + if (list == null) { + list = new RefList<>(); + } + RefList<User> list2 = o.get_impl_likedBy(); + if (list2 == null) { + list2 = new RefList<>(); + } + list.add(o); + list2.add(this); + set_impl_likes(list); + o.set_impl_likedBy(list2); + } + public void User.removeFromLikes(Comment o) { + assertNotNull(o); + RefList<Comment> list = get_impl_likes(); + if (list != null && list.remove(o)) { + RefList<User> list2 = o.get_impl_likedBy(); + if (list2 != null) list2.remove(this); + set_impl_likes(list); + o.set_impl_likedBy(list2); + } + } + public java.util.List<User> Comment.likedBy() { + RefList<User> l = get_impl_likedBy(); + return l != null ? Collections.unmodifiableList(l) : Collections.emptyList(); + } + public void Comment.addToLikedBy(User o) { + assertNotNull(o); + RefList<User> list = get_impl_likedBy(); + if (list == null) { + list = new RefList<>(); + } + RefList<Comment> list2 = o.get_impl_likes(); + if (list2 == null) { + list2 = new RefList<>(); + } + list.add(o); + list2.add(this); + set_impl_likedBy(list); + o.set_impl_likes(list2); + } + public void Comment.removeFromLikedBy(User o) { + assertNotNull(o); + RefList<User> list = get_impl_likedBy(); + if (list != null && list.remove(o)) { + RefList<Comment> list2 = o.get_impl_likes(); + if (list2 != null) list2.remove(this); + set_impl_likedBy(list); + o.set_impl_likes(list2); + } + } + + public boolean ASTNode.violateLowerBounds() { + return !getLowerBoundsViolations().isEmpty(); + } + public java.util.List<Pair<ASTNode, String>> ASTNode.getLowerBoundsViolations() { + ArrayList<Pair<ASTNode, String>> list = new ArrayList<>(); + computeLowerBoundsViolations(list); + return list; + } + public void ASTNode.computeLowerBoundsViolations(java.util.List<Pair<ASTNode, String>> list) { + for (int i = 0; i < getNumChildNoTransform(); i++) { + getChildNoTransform(i).computeLowerBoundsViolations(list); + } + } + public class Pair<T1, T2> { + public final T1 _1; + public final T2 _2; + public Pair(T1 _1, T2 _2) { + ASTNode.assertNotNull(_1); + ASTNode.assertNotNull(_2); + this._1 = _1; + this._2 = _2; + } + public boolean equals(Object other) { + if (other instanceof Pair) { + Pair<?,?> p = (Pair<?,?>) other; + return _1.equals(p._1) && _2.equals(p._2); + } else { + return false; + } + } + public int hashCode() { + return 31*_1.hashCode() + _2.hashCode(); + } + } + public static void ASTNode.assertNotNull(Object obj) { + if (obj == null) { + throw new NullPointerException(); + } + } +} diff --git a/solve/src/main/jastadd/grammar.ast b/solve/src/main/jastadd/grammar.ast deleted file mode 100644 index d368969b515c013303353f9a519a82e18bd71cfd..0000000000000000000000000000000000000000 --- a/solve/src/main/jastadd/grammar.ast +++ /dev/null @@ -1,12 +0,0 @@ -abstract ModelElement ::= <Id:Long> ; -SocialNetwork : ModelElement ::= User* Post* ; - -User:ModelElement ::= <Name:String> Friend:UserRef* Submission:SubmissionRef* Like:CommentRef* ; - -abstract Submission : ModelElement ::= <Timestamp:Long> <Content:String> Comment* ; -Comment : Submission ::= /<Post:Post>/ ; -Post : Submission ::= ; - -UserRef ::= <User:User> ; -CommentRef ::= <Comment:Comment> ; -SubmissionRef ::= <Submission:Submission> ; diff --git a/solve/src/main/jastadd/queries.jrag b/solve/src/main/jastadd/queries.jrag index fd9bf33af1b02feb47e003ebc4e5103856d58857..b61f0cd1130aa1912992e2974455e233387fbf57 100644 --- a/solve/src/main/jastadd/queries.jrag +++ b/solve/src/main/jastadd/queries.jrag @@ -6,11 +6,11 @@ aspect Queries { // java.util.Set<User> s = this.getCommentLikerFriends(comment); java.util.Set<User> s = new java.util.HashSet<>(); s.add(this); - for (UserRef f : getFriends()) { - for (CommentRef cref : f.getUser().getLikes()) { - if (cref.getComment() == comment) { - s.add(f.getUser()); - for (User commentLikerFriend : f.getUser().getCommentLikerFriends(comment)) { + for (User f : friends()) { + for (Comment otherComment : f.likes()) { + if (otherComment == comment) { + s.add(f); + for (User commentLikerFriend : f.getCommentLikerFriends(comment)) { s.add(commentLikerFriend); } } @@ -22,7 +22,7 @@ aspect Queries { syn int Comment.score() { int score = 0; java.util.Set<java.util.Set<User>> commentLikerGroups = new java.util.HashSet(); - for (User user : getLikedBy()) { + for (User user : likedBy()) { commentLikerGroups.add(user.getCommentLikerFriends(this)); } for (java.util.Set<User> userSet : commentLikerGroups) { @@ -60,7 +60,7 @@ aspect Queries { syn int Post.score() { int result = 0; for (Comment comment : commentsForPost()) { - result += 10 + comment.getLikedBy().size(); + result += 10 + comment.likedBy().size(); } return result; } diff --git a/solve/src/main/jastadd/refs.jadd b/solve/src/main/jastadd/refs.jadd deleted file mode 100644 index 435aed1a3f4742ee7e1370463730da6de13a9a0c..0000000000000000000000000000000000000000 --- a/solve/src/main/jastadd/refs.jadd +++ /dev/null @@ -1,13 +0,0 @@ -aspect References { - public UserRef User.createUserRef() { - return new UserRef(this); - } - - public CommentRef Comment.createCommentRef() { - return new CommentRef(this); - } - - public SubmissionRef Submission.createSubmissionRef() { - return new SubmissionRef(this); - } -} diff --git a/solve/src/main/java/de/tudresden/inf/st/ttc18live/Main.java b/solve/src/main/java/de/tudresden/inf/st/ttc18live/Main.java index 74c7bec791aa5cae032557de36ed74129e21338b..4c3ab71861562ac99854ff8192dac52a77c01262 100644 --- a/solve/src/main/java/de/tudresden/inf/st/ttc18live/Main.java +++ b/solve/src/main/java/de/tudresden/inf/st/ttc18live/Main.java @@ -10,12 +10,10 @@ import org.apache.logging.log4j.Logger; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; -import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.text.ParseException; -import java.util.ArrayList; +import java.util.List; import java.util.stream.Collectors; @SuppressWarnings("FieldCanBeLocal") @@ -31,15 +29,14 @@ public class Main { result.setId(id); sn.addUser(result); for (Comment comment : likes) { - result.addLike(comment.createCommentRef()); + result.addToLikes(comment); } return result; } private static void addFriends(User one, User... others) { for (User other : others) { - one.addFriend(other.createUserRef()); - other.addFriend(one.createUserRef()); + one.addToFriends(other); } } @@ -199,25 +196,25 @@ public class Main { .map(c -> c.toString() + ":(" + c.score() + "." + c.getTimestamp() + ")") .collect(Collectors.joining(", "))); for (Comment comment : scoringComments) { - logger.debug("{} likedBy {}", comment, comment.getLikedBy()); - for (User user : comment.getLikedBy()) { + logger.debug("{} likedBy {}", comment, comment.likedBy()); + for (User user : comment.likedBy()) { logger.debug("{} and {}: {}", comment, user, user.getCommentLikerFriends(comment)); - logger.debug("{} friends: {}", user, printList(user.getFriendList())); + logger.debug("{} friends: {}", user, printList(user.friends())); // check that commentLikers are all friends } } } - private static String printList(List<UserRef> userRefList) { + private static String printList(List<User> userList) { StringBuilder sb = new StringBuilder("["); boolean first = true; - for (UserRef userRef : userRefList) { + for (User user : userList) { if (first) { first = false; } else { sb.append(", "); } - sb.append(userRef.getUser()); + sb.append(user); } return sb.append("]").toString(); } diff --git a/solve/src/main/java/de/tudresden/inf/st/ttc18live/Translator.java b/solve/src/main/java/de/tudresden/inf/st/ttc18live/Translator.java index c86231fb2d9a5d7a35df065246d712d2084797fd..b93584e6d0f79cd2fffe49317665f775c8a8c873 100644 --- a/solve/src/main/java/de/tudresden/inf/st/ttc18live/Translator.java +++ b/solve/src/main/java/de/tudresden/inf/st/ttc18live/Translator.java @@ -4,11 +4,8 @@ import SocialNetwork.SocialNetworkRoot; import de.tudresden.inf.st.ttc18live.jastadd.model.List; import de.tudresden.inf.st.ttc18live.jastadd.model.Post; import de.tudresden.inf.st.ttc18live.jastadd.model.User; -import de.tudresden.inf.st.ttc18live.jastadd.model.UserRef; import de.tudresden.inf.st.ttc18live.jastadd.model.Comment; -import de.tudresden.inf.st.ttc18live.jastadd.model.CommentRef; import de.tudresden.inf.st.ttc18live.jastadd.model.Submission; -import de.tudresden.inf.st.ttc18live.jastadd.model.SubmissionRef; import de.tudresden.inf.st.ttc18live.jastadd.model.ModelElement; import de.tudresden.inf.st.ttc18live.jastadd.model.ModelChange; @@ -72,19 +69,19 @@ public class Translator { User user = userMap.get(emfUser); for (SocialNetwork.User emfFriend : emfUser.getFriends()) { User friend = userMap.get(emfFriend); - user.addFriend(new UserRef(friend)); + user.addToFriends(friend); } // fix submissions for (SocialNetwork.Submission emfSubmission : emfUser.getSubmissions()) { Submission submission = submissionMap.get(emfSubmission); - user.addSubmission(new SubmissionRef(submission)); + user.addToSubmissions(submission); } // fix likes for (SocialNetwork.Comment emfComment : emfUser.getLikes()) { Comment comment = commentMap.get(emfComment); - user.addLike(new CommentRef(comment)); + user.addToLikes(comment); } } diff --git a/solve/src/main/java/de/tudresden/inf/st/ttc18live/translator/XmlToJastaddTranslator.java b/solve/src/main/java/de/tudresden/inf/st/ttc18live/translator/XmlToJastaddTranslator.java index 8274f7106735af9ae04352f76995cc72f82648e6..7e4f09e6477e06e01d7db0ffafa00618724ee2b1 100644 --- a/solve/src/main/java/de/tudresden/inf/st/ttc18live/translator/XmlToJastaddTranslator.java +++ b/solve/src/main/java/de/tudresden/inf/st/ttc18live/translator/XmlToJastaddTranslator.java @@ -81,7 +81,7 @@ public class XmlToJastaddTranslator { String[] submissionTokens = userAndSubmissions.getValue().split(" "); User user = userAndSubmissions.getKey(); for (String token : submissionTokens) { - user.addSubmission(submissionMap.get(Long.valueOf(token)).createSubmissionRef()); + user.addToSubmissions(submissionMap.get(Long.valueOf(token))); } } // resolveModelElement friends @@ -90,7 +90,7 @@ public class XmlToJastaddTranslator { String[] friendsTokens = userAndFriends.getValue().split(" "); User user = userAndFriends.getKey(); for (String token : friendsTokens) { - user.addFriend(userMap.get(Long.valueOf(token)).createUserRef()); + user.addToFriends(userMap.get(Long.valueOf(token))); } } // resolveModelElement likes @@ -99,7 +99,7 @@ public class XmlToJastaddTranslator { String[] likesTokens = userAndLikes.getValue().split(" "); User user = userAndLikes.getKey(); for (String token : likesTokens) { - user.addLike(((Comment) submissionMap.get(Long.valueOf(token))).createCommentRef()); + user.addToLikes(((Comment) submissionMap.get(Long.valueOf(token)))); } } logger.info("Done translating"); @@ -256,8 +256,7 @@ public class XmlToJastaddTranslator { String[] tokens = parsedUser.friends.split(" "); for (String token : tokens) { User friend = resolveUser(token, modelChangeSet); - user.addFriend(friend.createUserRef()); - friend.addFriend(user.createUserRef()); + user.addToFriends(friend); } } // maybe set other fields? (submission is set, but refers to later introduced changes) @@ -285,7 +284,7 @@ public class XmlToJastaddTranslator { submission.setContent(parsedSubmission.content); // resolveModelElement user User submitter = resolveUser(parsedSubmission.submitter, modelChangeSet); - submitter.addSubmission(submission.createSubmissionRef()); + submitter.addToSubmissions(submission); // check if there are any comments attached if (parsedSubmission.comments != null) { for (ParsedComment parsedSubComment : parsedSubmission.comments) { diff --git a/solve/src/test/java/de/tudresden/inf/st/ttc18live/test/Query1SortingTest.java b/solve/src/test/java/de/tudresden/inf/st/ttc18live/test/Query1SortingTest.java index 41f8b84562da0a349ce4f9eb8b4ec9c3fc930529..4dbcc13c062b88d49e2428aca17dc580bf2e3c25 100644 --- a/solve/src/test/java/de/tudresden/inf/st/ttc18live/test/Query1SortingTest.java +++ b/solve/src/test/java/de/tudresden/inf/st/ttc18live/test/Query1SortingTest.java @@ -49,8 +49,8 @@ public class Query1SortingTest { User user = new User(); user.setId(7001L + j); result.addUser(user); - submitter.addSubmission(comment.createSubmissionRef()); - user.addLike(comment.createCommentRef()); + submitter.addToSubmissions(comment); + user.addToLikes(comment); } } } @@ -67,10 +67,10 @@ public class Query1SortingTest { StringBuilder sb = new StringBuilder("Users = "); for (User user : socialNetwork.getUserList()) { sb.append(user.getId()); - if (user.getNumLike() > 0) { + if (!user.likes().isEmpty()) { sb.append("-likes->{"); - for (CommentRef commentRef : user.getLikeList()) { - sb.append(commentRef.getComment().getId()).append(","); + for (Comment comment : user.likes()) { + sb.append(comment.getId()).append(","); } sb.append("}"); }