Homework: PennPals

Computing’s core challenge is how not to make a mess of it. — Edsger W. Dijkstra
Helpful Links
- Javadocs for server code (the same information can also be found in the javadoc comments above each method). This should be your first stop for any uncertainty about what a method does or what its arguments mean.
- CIS 1200 Java style guide
- Frequently Asked Questions
- If you prefer to work locally (instead of in Codio), download the stub code, then follow the IntelliJ setup instructions.
Overview
This assignment involves building an internet chat server (like Slack) in Java. Your code will model the internal state of the server and handle communication with chat clients.
The key content for this assignment is described in Chapters 24, 25, and 26 of the lecture notes – we encourage you to study these before getting to work. If you want to start on the project early, you will need to read the lecture notes ahead of the posted schedule. (This will also have the benefit that you will be prepared to ask questions during the lectures on these topics. :-)
Here are some checkpoints for this assignment (but as always, starting earlier is better!):
- Checkpoint 1 (Tuesday): Complete Task 1.
- Checkpoint 2 (Wednesday): Complete Task 2.
- Checkpoint 3 (Friday): Complete Task 3.
- Checkpoint 4 (Monday): Complete Task 4.
- Checkpoint 5 (Tuesday): Complete Task 5 (optional) and Task 6 and hand it in!
Make sure you run the tests for each task (and that they pass!) before moving on to the next section.
You will be changing just a few files…
src/main/java/org/cis1200/ServerModel.java
src/test/java/org/cis1200/ServerModelTest.java
… but you will need to read and understand some of the others.
Task 1: Understanding the Problem
Start by familiarizing yourself with the following concepts and design principles for this assignment:
Server
A computer system designed to provide a service to many connected clients at once.
Client (User)
An end user of a service like our chat server.
- In this assignment, a client is the program run by a user who has connected to the server to chat with other users.
- Each client is assigned a unique userId when they connect to the server. This integer cannot be changed, and it persists as long as the client is connected. If a client later reconnects, they will get a new userId.
- Each client also has a nickname - a string that other users can see. A user can change their own nickname at any time.
We use “client” and “user” interchangeably in these instructions.
Channel
A group of users (clients) connected to the server. Every channel has an owner – the user who created the channel.
- A user in a channel receives all messages sent to that channel after they join.
- A user in a channel can leave the channel at any time. After they leave, they will no longer get messages from that channel.
- At any given time, a user connected to the server can be in any number of channels (including none).
- Think about what Java construct you can use to group together all of the data related to a channel!
Owner
The owner of a channel can remove anyone from that channel (including themselves). If the owner leaves for any reason, the entire channel is removed.
Channel Privacy
A channel is either public or private. If it is public, any user who knows the name of the channel can join. If it is private, new users are only added if the owner invites them, in which case they automatically join.
Protocol
A standardized set of instructions for communicating over the Internet by requesting and transmitting data.
In this assignment, clients communicate with the server by sending commands that
instruct the server to create new channels, send messages on channels, etc. We
represent this communication protocol in our code base using subclasses of an
abstract class Command
:
NicknameCommand
changes the sender’s nickname.CreateCommand
creates a new channel with the sender as its owner.JoinCommand
lets the sender join a public channel.InviteCommand
adds a target user to a private channel owned by the sender.MessageCommand
sends a message to all users in a specific channel.LeaveCommand
lets the sender leave a channel they are in.KickCommand
removes a target user from a public or private channel owned by the sender.
Before moving on, familiarize yourself with the definitions of the Command
class and all of its subclasses in the provided file Command.java
. Pay
particular attention to the private instance variables of each class and the
“getter” methods that provide access to this information.
On receiving a command, the server is responsible for updating its internal state
and producing a ResponseSet
:
a set of responses sent to any clients that should be informed about the command.
Task 2: The internal state of the ServerModel
In this task, you need to:
- Add necessary instance variables to
ServerModel
(javadocs) and initialize them in the constructor. - Implement user query methods:
existingUserId
,getUserId
,existingNickname
,getNickname
, andgetRegisteredUsers
. - Implement channel query methods:
getChannels
,getUserNicknamesInChannel
, andgetOwner
methods. - Pass all tests in
Task2Test.java
.
If you’re unsure what a method does or what its arguments mean, check the online Javadocs or the Javadoc comments above the method definition (it’s the same information, since the online Javadocs are generated from the comments).
ServerModel
Overview
The ServerModel
is responsible for processing all incoming Command
s and
keeping track of the server state. You will need to add data structures to
track:
- All users connected to the server (their userIds and nicknames)
- The channels that users are in
- Information on each channel, like its owner, members, etc.
This is just the information that has to be stored in ServerModel
- the way in
which that information is stored is entirely up to you.
(The word Model
in ServerModel
means that this class just manages the core
state and associated behaviors of the server. Isolating the core functionality
in this way makes it easier to design and test.)
Data Structure Choices
You have a choice of three data structures to use for this assignment: TreeSet, TreeMap, and LinkedList. Think about which data structure(s) you’d like to use. Consider a data structure whose capabilities fit the nature of the information being stored. Some questions you can ask yourself to pick a data structure include:
- Are duplicate entries allowed?
- Is ordering important?
- What kind of relationship is being stored?
- Which data structures could avoid unnecessary looping?
- Which structures allow direct access to the data you need?
You may use only these data structures from java.util. In particular, even
if you are already familiar with classes such as HashSet
, HashMap
, or
ArrayList
, you may not use them for this assignment. One of the goals of
this homework is for you to practice working with these specific data
structures.
Do your best to avoid redundancy. Having the same information in multiple places will make your life much more difficult.
You can change your mind later. You need to make a choice now to get started with this point of the assignment, but as you learn more about what you need to do, you might find that you want to change things up. It is normal to need to do this. At each step of this project, we will ask you to document your choices so that you can see how they evolve as you work through the material and add new features.
Creating New Classes
You might find it helpful to represent parts of the server state using new classes.
You are not required to do so for this assignment, but if you do choose to create a new class, you should consider the following guidelines:
Define the class in a new file and in the proper package
If you want to define your custom class called NewClass
, you should create a
file named NewClass.java
. (Note that your file name should correspond to your
class name!) Each new class needs to have package org.cis1200;
at the top of
the file.
Override equals
This is useful for testing, but also required if you use the class as elements
of a LinkedList
or TreeSet
, or as keys of a TreeMap
. Checking if an
equivalent instance of your class is already in a Collection
requires
overriding equals
, since this defines the conditions under which two
instances are judged to be the same.
If you don’t override equals
, Java will use ==
by default, so two instances
with identical values in their fields may still be marked as “not equal”.
Consider implementing the Comparable
interface (javadocs)
This is required if you plan to use objects of the class as elements of a
TreeSet
or as keys of a TreeMap
, for reasons that are similar to the
reasons to override equals
. Because TreeSet
and TreeMap
are based on
insertion into a BST, they need to be able to compare elements to each other
and determine positioning.
Add Javadoc comments
All methods in the new class should have Javadoc comments to describe what they do.
Task 3: Connections and Setting Nicknames
This is the first task where you need to start implementing methods that
correspond to commands from the chat protocol. Each of these methods is defined
in the ServerModel
class and called by a corresponding updateServerModel
method of a subclass of Command
.
For this task, you need to:
- Implement
registerUser
,deregisterUser
, andchangeNickname
- Pass all tests in
Task3Test.java
- Add your own unit tests for these methods in
ServerModelTest
. Think about situations that were not covered byTask3Test
.
Hints: the isValidName
helper method has been provided for you. You may add
additional helper methods to the ServerModel
class, as long as they are marked
private
.
What is a Response
?
A Response
object represents a message that the server should
send to one or more clients after it finishes processing a command.
For example, when a client changes its nickname, every other client who can see that client should be notified of the change so that its client-side applications can display the new nickname.
The Response
class constructor is marked private
, so the only way to
construct a Response
is via the following static methods:
Response.connected
is used when a new client connects.Response.disconnected
is used when a client disconnects from the server.Response.names
is used when a client joins or is invited to a channel.Response.error
is used when it is not possible to complete a command for some reasonResponse.okay
is used when aCreateCommand
,MessageCommand
,LeaveCommand
, orKickCommand
executes successfully. More on that later.
Please read the instructions for the next few tasks carefully - as well as the
Javadocs for Response
and ResponseSet
- to ensure that you pass in the
correct parameters when constructing responses.
What is a ResponseSet
?
In class you’ve learned about Sets, which are collections of objects without duplicates. We can have Sets of Integers, Sets of Strings, etc. In the same way, you should just think of a ResponseSet as a Set of Responses! If you take a look at that class, you will see that its only instance field is a Set, to which Response instances are added to through a helper method.
Task 4: Channels and Messages
In this task, you should:
- Implement all parts of
createChannel
andjoinChannel
that don’t involve channel privacy - Implement
sendMessage
andleaveChannel
- Check that you pass all tests in
Task4Test.java
- Add your own unit tests for these methods in
ServerModelTest
. Think about situations that were not covered byTask4Test
. - Run the client application to try out your code for channel creation, joining channels, messaging, and leaving channels.
Testing with the Client Application

The chat server is now functional enough to try channel creation, joining
channels, messaging, and leaving channels, by running it together with one or
more instances of hw07-client.jar
(the client application).
Running the Client in Codio
- Start the server with the menu.
- Launch a client instance with the menu. If you want multiple clients at once, click on the menu option once for each client.
- Click the “PennPals” option to open up a window to view the client.
Running the Client in IntelliJ

- Start the server by running
ServerMain.java
.

-
Launch a client instance by right-clicking on
hw07-client.jar
and clicking “Run”. -
When prompted to enter the server’s host name, enter “localhost” to connect the client to the server running on your computer.

If you need multiple instances of the client, you may need to open a command
line (PowerShell for Windows, Terminal for macOS) and run
java -jar <path-to-client>
, where <path-to-client>
is replaced by the
location of hw07-client.jar
. If you’re not sure how to type the path manually,
just drag the .jar
from File Explorer/Finder to the command line window after
typing java -jar
Note: Using the client application is not a substitute for writing JUnit tests!
Task 5 (Kudos): Channel Privacy
Note: this task is optional, and not required to receive full credit on the homework assignment. However, completing this task will give you additional practice with Java collections and will produce a more fully featured chat implementation.
In this task, you should:
- Add channel privacy to your server state
- Modify
createChannel
to deal with creation of private channels - Modify
joinChannel
to handle users trying to join private channels - Implement
inviteUser
andkickUser
: if a owner kicks themselves, the channel should be destroyed too - Check that your code passes all provided test cases in
Task5Test.java
- Add your own unit tests to
ServerModelTest
for these methods. Think about situations that were not covered byTask5Test
. - Try out these features using multiple instances of the client application
Task 6: Refactoring
You’ve completed all of the required features! Hooray! Now look for any redundant data, duplicate code, convoluted functions, or other issues that make your code less readable. Don’t be afraid to adjust some data structures, add helpers, and so on.
If you are worried about breaking your code, make a zipfile for your current version, before making any modifications. However, this is the point where your unit tests will help: if you do introduce a bug while refactoring, a good test suite should immediately detect and help you isolate it.
Make to check that your code complies with our style guidelines.
Submission Instructions
You will be uploading only the following files:
src/main/java/org/cis1200/ServerModel.java
src/test/java/org/cis1200/ServerModelTest.java
- Any additional classes you made
If you are using Codio
The easiest option is to use the Zip Project
menu item in
Codio. Do not include any of the other provided files, since doing so may
cause your submission to fail to compile. You can directly upload the zip
produced by Codio into Gradescope.
If you are using IntelliJ
Gradescope allows you to easily drag-and-drop files into it, or you can click “Browse” in Gradescope to open up a file browser on your computer to select files. Upload only the files listed above.
Grading Breakdown
- Automated testing (90%)
- Task 2: Server State Access (5%)
- Task 3: Connections and Nicknames (40%)
- Task 4: Channels and Messages (35%)
- Task 5: Invite-Only Channels (0%, Kudos only)
- Model state encapsulation (5%)
- Style (5%)
- Manual grading (10%)
- Server model design (5%)
- Quality of your testing (5%)
You have three free submissions for this assignment. Each additional submission will cost you five points from your final score.