Lab:
Social Media
Beware! MapMonster is here for your code!
In this lab, you will be using sets and maps to make a fake social media application. You will also be implementing the Set and Map interfaces.
Files
Download and unzip socialmedialab.zip, which contains a number of files.
Classes you will complete:
User.java - represents one user on our social media application; each user has a collection of posts and the names of other users they follow
Main.java - class that you can use to run the social media application
Directory.java - stores all users of our social media application
SimpleSet.java - implements the Set methods listed below
SimpleMap.java - implements the Map methods listed below
Files provided for you to use:
Line.java - represents a line from (x1, y1) to (x2, y2) in a drawing in our social media application
Post.java - represents a user's post (with a text message and drawing) on our social media application
Display.java - a graphical interface provided to you for viewing the social media application
data.txt - a text file containing sample data used by our social media application
Entry.java - used by SimpleMap to store a single key and value
Files you can ignore: DrawPanel.java, PostDialog.java, and PostPanel.java.
Reference
interface java.util.Set<E>
int size()
boolean contains(Object obj)
boolean add(E obj)
if obj is not present in this set, adds obj and returns true; otherwise returns false
boolean remove(Object obj)
if obj is present in this set, removes obj and returns true; otherwise returns false
interface java.util.Map<K,V>
int size()
V get(Object key)
returns the value associated with key, or null if there is no associated value
V put(K key, V value)
associates key with value; returns the value formerly associated with key, or null if key was not present
V remove(Object key)
removes and returns the value associated with key; returns null if there is no associated value
Set<K> keySet()
returns a set of the keys in the map; because the returned set is still connected to the map, removing a key from the set will remove that key/value pair from the map, and adding a key to the set is forbidden
class java.util.TreeSet<E> implements java.util.Set<E>
class java.util.TreeMap<K,V> implements java.util.Map<K,V>
Part 0: Post (0 points)
The Post class has been provided to you. It represents a user's post on our social media application. Each Post has a text message and a drawing consisting of zero or more lines. Go ahead and familiarize yourself with the Post class constructor and methods below. Then move on to Part 1.
Post(String name, long time) // constructs an empty Post for given user name and time
String getName() // returns name of user who posted this
long getTime() // returns the time this was posted
String getText() // returns posted text message
Set<Line> getDrawing() // returns posted line drawing
void setText(String text) // replaces posted text message
void addLine(Line line) // adds Line to posted line drawing
Part 1: User (20 points)
The User class represents one user on our social media application. Each User has a collection of posts and the names of other users they follow. The User class's constructor and methods are illustrated by the following code segment.
User aluser = new User("Al");
aluser.follow("Bo");
aluser.follow("Cy");
boolean b;
b = aluser.isFollowing("Bo"); // true
b = aluser.isFollowing("Cy"); // true
aluser.unfollow("Cy");
b = aluser.isFollowing("Bo"); // true
b = aluser.isFollowing("Cy"); // false
Post post1 = some Post object;
long time1 = post1.getTime(); // 946702800000, for example
aluser.addPost(post1);
aluser.setPostText(time1, "I dyed my hair blonde!!! (and I guess I'm having twins)");
// replaced text in post1 (precondition: Post with given time has already been added to User)
Post post2 = another Post object;
long time2 = post2.getTime(); // 1332977400000, for example
aluser.addPost(post2);
aluser.setPostText(time2, "Let’s set a world record together with this world_record_triangle!");
// replaced text in post2
aluser.addLineToPost(time2, new Line(0, 100, 100, 100));
aluser.addLineToPost(time2, new Line(0, 100, 50, 0));
aluser.addLineToPost(time2, new Line(50, 0, 100, 100));
// added 3 lines to post2 (precondition: Post with given time has already been added to User)
Set<Post> posts = aluser.getPosts(); // returns set containing post1 and post2
Open User.java. The User class has three fields: the user's name, the Set of user names they are following, and a Map containing the user's posts. The keys of the Map are unique integer identifiers, and the values are the Posts themselves.
private String name;
private Set<String> following;
private Map<Long,Post> posts;
Do not add any other fields to this class.
The unique integer identifiers used as keys in the Map actually represent the system time when the Post was constructed. The system time is just the number of milliseconds elapsed since January 1, 1970. Because this is a really big number, it is represented using a long instead of an int. Roughly speaking, a long can store twice as many digits as an int. Remember that whenever we want to store an int in an ArrayList, ListNode, etc., we use Java's Integer wrapper class. Likewise, to store a long in our Map, we use Java's Long wrapper class.
For example, after running the code segment above, the posts field contains the following data.
Key Value
946702800000 Post object with time 946702800000 and text "I dyed ..."
1332977400000 Post object with time 1332977400000 and text "Let’s set ..."
Exercise 1-1: User
Complete the User class definition so that it behaves as shown above. Remember that you cannot construct a Set, because Set is an interface. Java's mysterious TreeSet class correctly implements the Set interface, so you should construct a TreeSet whenever you need to create an empty Set. Likewise, Java's TreeMap class correctly implements the Map interface.
Exercise 1-2: Main
Open Main.java, which contains a single method, also called main. This method creates a window for viewing the social media application.
Compile Main.java and run the Main class's main method. You should see a window pop up. In the title bar, it tells you that you are "Logged in as Bort".
If your name is not Bort, choose a more appropriate user name. (Note that you cannot have any spaces in your user name.) Modify the main method to use this new user name. If your name is Bort, then do not modify the main method!
Run the main method and confirm that your new user name now appears in the title bar.
Of course, nothing else works in this window, because you're not done with the lab yet ...
Part 2: Directory (25 points)
The Directory class stores all users of our social media application. Specifically, it has a single field called userMap of type Map, whose keys are user names and whose values are the corresponding User objects.
private Map<String,User> userMap;
For example, if our Directory contains 3 users named Al, Bo, and Cy, then userMap will appear as follows.
Key Value
"Al" User object with name "Al"
"Bo" User object with name "Bo"
"Cy" User object with name "Cy"
Do not add any other fields to this class.
The Directory class's constructor and methods are empty. It will be your job to fill in that code in the following exercises.
Exercise 2-1: Names
Consider the following code segment.
Directory dir = new Directory();
dir.addUserIfNew("Al");
dir.addUserIfNew("Bo");
dir.addUserIfNew("Cy");
dir.addUserIfNew("Di");
dir.addUserIfNew("Bo"); // ignored, because "Bo" has already been added
Set<String> names = dir.getNames("Cy"); // returns {Al, Bo, Di} -- all names except for given string
Complete the Directory class's constructor, addUserIfNew method, and getNames method, so that they behave as shown above.
Test your code by running the Main class's main method. You should now see a list of names in the Follow box on the left side of the window. This is a list of the other social media users saved in the data.txt file. Your own user name should not appear in the list. (In other words, the Display class uses the getNames method you just wrote to get the names of all users other than the one that's currently logged in.)
Try changing the main method to use one of the names you do see, and confirm that this name no longer appears in the Follow list.
Exercise 2-2: Following
Consider the following code segment.
dir.follow("Al", "Bo"); // Al will now follow Bo's posts
boolean b;
b = dir.isFollowing("Al", "Bo"); // returns true (Al is following Bo's posts)
b = dir.isFollowing("Bo", "Al"); // returns false (Bo is not following Al's posts)
dir.follow("Cy", "Al"); // Cy will now follow Al's posts
b = dir.isFollowing("Cy", "Al"); // returns true (Cy is following Al's posts)
dir.unfollow("Cy", "Al"); // Cy will not follow Al's posts's anymore
b = dir.isFollowing("Cy", "Al"); // returns false (Cy is not following Al's posts)
Complete the Directory class's follow, unfollow, and isFollowing methods, so that they behave as shown above.
(You will not see the effects of these changes in the Display yet.)
Exercise 2-3: Feed
Consider the following code segment.
dir.addPost(new Post("Al"));
dir.addPost(new Post("Bo"));
dir.addPost(new Post("Cy"));
dir.addPost(new Post("Al"));
Set<Post> feed;
feed = dir.getFeed("Al"); // returns both of Al's posts
dir.follow("Al", "Bo");
feed = dir.getFeed("Al"); // returns both of Al's posts AND Bo's post
As shown above, the Directory class's addPost method adds the given post to the appropriate User. The getFeed method returns a set that includes (1) all posts made by the user with the given name, and (2) all posts made by any user followed by the user with the given name. Complete the addPost and getFeed methods.
Test your code by running the main method. Click on the New Post button. In the dialog that pops up, write a message in the text field at the top and/or draw a picture in the large square region. Each new post you create should now appear at the top of the Feed box on the right side of the main window. You will not be able to see the content of posts from other users yet.
Exercise 2-4: setPostText
Complete the setPostText method, which replaces the text message associated with an existing post. The method takes in the name of the user who made the post, the time the post was created, and the new text message. The method finds the existing Post matching that name and time, and replaces its text message with the given text.
Test your code by running the main method. Click on a user name to follow them, and you should now see any text messages they posted. Try following and unfollowing, as well as creating your own posts.
Exercise 2-5: addLineToPost
Complete the addLineToPost method, which adds a Line to an existing post. The method takes in the name of the user who made the post, the time the post was created, and a Line. The method finds the existing Post matching that name and time, and adds the given Line to its drawing.
Test your code by running the main method. You should now see drawings posted by the users you are following.
Part 3: SimpleSet (20 points)
Open SimpleSet.java. A SimpleSet implements the Set methods shown above by storing its elements in an ArrayList. Complete these methods so that they behave exactly as specified above.
Be sure to test your code.
Part 4: SimpleMap (25 points)
Open Entry.java, which defines the Entry<K,V> class. The following code segment makes use of the Entry class.
Entry<Integer,Boolean> e = new Entry<Integer,Boolean>(2, true);
System.out.println(e.getKey());
System.out.println(e.getValue());
e.setValue(false);
System.out.println(e.getKey());
System.out.println(e.getValue());
What do you think it will print? Run the code to test your prediction.
Now open SimpleMap.java. A SimpleMap implements the Map methods shown above by storing its data in an ArrayList of Entry objects. For example, the following map data
Key Value
A 6
B 1
C 4
is stored inside SimpleMap as:
Complete the given methods. These methods should behave exactly as specified above. Note that the keySet method will return a SimpleSet.
Be sure to test your code.
Part 5: Saving (5 points)
In this part, we'll modify our social media application so that it saves all posts, along with who is following whom. Consider the following code segment.
Directory dir = new Directory();
dir.addUserifNew("Lee");
dir.addUserifNew("Roy");
dir.addUserIfNew("Sam");
dir.follow("Roy", "Lee");
dir.follow("Roy", "Sam");
dir.unfollow("Roy", "Sam");
dir.follow("Roy", "Sam");
Post p = new Post("Lee");
p.setText("Here's my favorite letter");
p.addLine(new Line(20, 10, 20, 90));
p.addLine(new Line(20, 90, 80, 90));
dir.addPost(p);
List<String> toSave = dir.save();
After the above code segment executes, toSave contains the following 5 strings (which will later be written to a text file).
follow Roy Lee
follow Roy Sam
text Lee 1153700000000 Here's my favorite letter
line Lee 1153700000000 20 10 20 90
line Lee 1153700000000 20 90 80 90
In the List returned by save in this example:
The string at index 0 represents that Roy is following Lee.
The string at index 1 represents that Roy is also following Sam.
The string at index 2 represents that Lee created a post at time 1153700000000 with the text message "Here's my favorite letter".
The string at index 3 indicates that a line connecting the points (20, 10) to (20, 90) appears in that same post.
The string at index 4 describes a second line in that same post.
Complete the Directory class's save method so that it behaves as described. Your code must save ALL of the following/post information--not just recently changed info. The strings in your list may appear in any order, with one exception. The text of a post must always appear somewhere before any lines from that same post. You may write additional methods, but you cannot add any new fields.
When you're ready to test your code, open Main.java. In the main method, you will see the following code.
new Display("Bort", "data.txt", false);
This code runs our social media application.
The first argument tells the Display class we'll be logging in with user name Bort.
The second argument tells the Display class to load data from the file data.txt--a text file formatted like the List returned by the Directory class's save method.
The third argument tells the Display class whether to automatically save all data to that text file any time a checkbox is clicked or a new post is created.
When you're ready, try changing the third argument to true, to tell the Display to save to the text file, but make a copy of the text file before trying this! If your code works, you should be able to check/uncheck boxes, make new posts, exit the social media application, restart the application, and still see the changes you made.
If you need to, you can redownload data.txt here.
Additional Credit Suggestions
Replace the logo.png with your own social media application name and logo (small prize, great honor, and 0 points)
When drawing a picture, add a feature that lets you undo recently drawn lines (in case you make a mistake).
Allow a user to delete one of their posts.
Allow a user to search for posts containing given text.
Allow a user to click when they like another user's post, and keep track of likes.
Allow a user to respond to comment on another user's post.
When drawing a picture, allow a user to select a color (or colors) to draw in.
At some appropriate time, consolidate redundant lines in a drawing. (For example, a line from A to B and a line from B to C with the same slope can be replaced with a line from A to C.)
Modify SimpleSet so that you can use it in a for-each loop. Hint: research Java's Iterator and Iterable interfaces.
Implement your own ideas for improving your social media application.