The main objective of this project is implementing a basic messaging program. This program consists of users, the server, messages, and mailboxes. Users can add each other as friends, they can send/receive messages via mailboxes, and the server acts as the coordinator and longterm storage of the messages.
You are already provided with the general structure of the project. Within this context, there are 3 packages and 7 classes. The details of the classes, functionalities to be implemented and overall operations of the project with the corresponding format are presented in the following sections.
- Packages and classes
- Package: executable
The Main.java class is placed in this package.
The Main should be implemented in a way that it should read the corresponding parameters and events from input.txt and log the results to output.txt .
- Package: elements
3 main concepts of this project reside in this package: User , Server and M essage classes. The java files of these classes are currently empty, you need to implement these classes according to the information provided in this document.
Each user object created in the program has an ID, an inbox, an outbox, and a list of friends. The IDs of the users are determined by the Main method as consecutive numbers, starting from 0. A user can send another user a message. However, there is a prerequisite of receiving a message: the receiver and sender side should be in the friends list of each other. One can send a message even though the receiver is not in the friends list. In that case, the message is stored in the server but the receiver side cannot fetch it. In this program, a user can add or remove a friend. As soon as they become friends, the receiver becomes able to read that message.
The fields and signature of the methods that should be implemented for the User class are as follows:
int id ;
Inbox inbox ;
Outbox outbox ; ArrayList<User> friends ; User( int id ): void addFriend(User other ) also add the user to the other user’s friends list. void removeFriend(User other )
a constructor that takes ID number as a parameter a method for adding a friend to the friends list. It should
a method for removing a friend from the friends list. It should also remove the user from the other user’s friends list.
boolean isFriendsWith(User other ) It should return true if the user and the other user are friends, false otherwise.
void sendMessage(User receiver , String body , int time , Server server ) A new message should be created and added to the user’s
sent list which is in his/her outbox.
2.2.2. Message.java :
All messages in this program should be instances of this class. Each message should have an ID, a body (text), a sender, a receiver and various time stamps. The IDs of the messages are determined by the order they are created as consecutive integer values. The first message sent in the program has the ID of 0, the second message sent has the ID of 1 and so on. IDs should be unique, that is, if two messages have the same ID number, it means they are the same message. Also, messages should be comparable with each other regarding their body length.
The necessary fields and signature of the methods to be implemented for the Message class are as follows:
static int numOfMessages = 0; int id ;
String body ;
User sender ;
User receiver ; int timeStampSent ; int timeStampRead ; int timeStampReceived ; number of total messages in the program.
Message(User sender , User receiver , String body , Server server , int time ) 3 setter methods for timeStampSent, timeStampReceived and timeStampRead
int getId() String getBody() int compareTo(Message o )
a getter method for ID field a getter method for the body field
if this message is longer than the other message, return a
positive number. Else if the other message is longer, return a negative number. Return 0 if both messages have the same number of characters.
boolean equals(Object o ) String toString()
This method should return a String in this form:
Each line should start with a tab. <received> or <read> should be empty strings if the message has not been received/read yet.
2.2.3. Server.java :
There is only one server throughout the program. This server functions as the mechanism where all non-received messages are stored in a first come, first served (FCFS) manner. It has a finite capacity set at the beginning of the execution. This capacity is the third argument specified in the input file and its unit is the number of characters. If the sum of lengths of the messages stored in the server exceeds the capacity value, all messages in the server are deleted. Detailed information about this issue is available in Section 4.
The fields and methods to be implemented in Server.java : long capacity capacity of the server
long currentSize This number should be kept updated when
messages in the server are deleted or added. Total number of the characters of messages’ bodies in the msgs queue.
Server( long capacity )
void checkServerLoad(PrintStream printer ) long getCurrentSize() void flush()
2.3. Package: boxes 2.3.1. Box.java :
A queue where non received messages are stored. The constructor with a parameter
prints the warnings about the capacity
A getter method for the current size field empties the queue
Box.java is the parent class of Inbox.java and Outbox.java . Every Box should have an owner of type User.
2.3.2. Inbox.java :
Both read and unread messages sent to a user are stored in the user’s Inbox. An inbox has two main functionalities: receiving messages from the server, and reading messages. However there are various signatures of readMessages method due to different event types parsed from the input file.
- Inbox.java should be a child of Box.java .
- There should be two fields for read and unread messages of the inbox, unread should be a stack and read should be a FCFS queue.
- When the receiveMessages method is called, it should fetch from the server those messages that are sent from the owner’s friends to the owner.
These messages’ timeStampReceived should get updated and they should be pushed to the unread stack. The method shouldn’t return anything.
○ The messages received at the same time have the same timeStampReceived . But they are pushed to the stack one by one. So, the last sent message should be on top of the stack (first message to be read).
- There are 3 different methods for reading messages. Two of them return an integer and the last one is a void method. If the number of messages read successfully is 0
or 1, the non-void methods should return 1. Else, those methods should return the number of messages read successfully.
The fields and methods to be implemented in Inbox.java : Stack unread Queue read
Inbox(User user )
void receiveMessages(Server server , int time ) receives messages from the adds to the unread stack. This method also changes timeStampReceived with the parameter time
int readMessages( int num , int time ) This method is for reading a certain amount of messages from the unread stack. If the num parameter is 0, then all messages in unread should be read. If the number of messages in unread is less than read, still all messages should be read.
int readMessages(User sender , int time ) This method is for reading a specified sender’s messages.
void readMessage( int msgId , int time ) When this method is called, the message with the ID number msgId should be read, if it exists.
- readMessages and readMessage methods pop messages in the unread , read them (stamps their timeStampRead ) and then transfer them to the read
- Unlike the receiveMessages method, reading each message takes 1 time. For
example, suppose there are 3 messages in the stack and we should read all at time tick t. The message at the top of the stack should be read first and it’s timeStampRead should be t. The second message to be read should have a timeStampRead value of t+1. And the third message should be read at timeStampRead = t+2. Then, the method should return 3. The next event occuring after this reading should be at time tick t+3, not t+1.
2.3.3. Outbox.java :
The Outbox.java represents an outbox of the owner. It stores all messages a user has sent, in other words, all messages constructed with the sender field as the owner of this outbox.
- This class is a child class of Box.java .
- Even if a message is never added to the server’s queue due to capacity overload, this message should be added to the sent queue in the user’s outbox. The necessary fields and methods for Outbox.java
Queue sent ;
Outbox(User owner ) A constructor with the parameter User owner
- Input & Output
The first row of the input file specifies the number of users, number of queries, and capacity of the server : A B C
The next B lines are the queries. There are 10 types of events exactly.
- ➔ 0: sending a message:
0 <sender_id> <receiver_id> <message_body> Example:
0 1 4 Hi there!
User#1 sends user#4 the message “Hi there!”.
- ➔ 1: recieve messages: 1 <reciever_id>
Example: 1 25
User#25 receives all the messages that are sent to him/her from the server.
- ➔ 2: read a certain amount of messages:
2 <receiver_id> <numberOfMessages>
- Note: If the number of messages is 0, then read all.
- ➔ 21: read all the messages from a sender 21 <receiver_id> <sender_id>
- ➔ 22: read a specific message
22 <receiver_id> <message_id>
- ➔ 3: add a friend
- <id1> <id2>
Make User#<id1> and User#<id2> friends. In case they are already friends, do nothing.
- ➔ 4: remove a friend
- <id1> <id2>
Remove each other from their friends lists. In case they are already not friends, do nothing.
- ➔ 5: flush server 5
Deletes all messages from the queue of the server
- ➔ 6: print the current size of the server 6
Note: The output should be:
Current load of the server is <currentSize> characters.
- ➔ 61: print the last message a user has read
The corresponding output should be:
From: <sender_id> to: <user_id>
Received: <time_stamp1> Read: <time_stamp2> <message_body>