Skip to content

Commit 7d75f25

Browse files
committed
Update README.md
1 parent aa8b165 commit 7d75f25

11 files changed

+114
-3
lines changed

.vscode/settings.json

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"lib/**/*.jar"
66
],
77
"cSpell.words": [
8+
"overengineered",
89
"structs",
910
"unreads",
1011
"XMLUI"

README.md

+108-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,108 @@
1-
# University_Of_Greenwich-COMP1549-Advanced_Programming
1+
# Java Chat App - University_Of_Greenwich-COMP1549-Advanced_Programming - Coursework
2+
3+
## Index
4+
- [Java Chat App - University\_Of\_Greenwich-COMP1549-Advanced\_Programming - Coursework](#java-chat-app---university_of_greenwich-comp1549-advanced_programming---coursework)
5+
- [Index](#index)
6+
- [Introduction](#introduction)
7+
- [Project overview](#project-overview)
8+
- [Bugs](#bugs)
9+
- [Testing](#testing)
10+
- [Improvements](#improvements)
11+
- [Conclusion](#conclusion)
12+
- [Screenshots](#screenshots)
13+
- [References](#references)
14+
- [Running the program](#running-the-program)
15+
- [Running/building from source](#runningbuilding-from-source)
16+
- [Running from release](#running-from-release)
17+
18+
## Introduction
19+
This repository contains the coursework source code and specification for the Advanced Programming module (COMP1549) at the University of Greenwich.
20+
Everyone was tasked with creating a chat application in Java. This application had to provide the following features:
21+
- The ability to pass a server `IP`, `port` and `username` as command line arguments, or to be prompted for them if they were not provided.
22+
- Connect to an existing server at the specified address, or create a new server if one did not exist.
23+
- Be able to publicly and privately send messages between connections via the server.
24+
- Be able to automatically migrate hosts when the server is shut down.
25+
26+
## Project overview
27+
The application could be made as either a command line interface or a graphical user interface.
28+
29+
While initially I had planned to create a command line based tool, I moved to using a graphical user interface as it would ease development due to the requirement of being able to privately send messages and the difficulty of interrupting and handling command line input buffers.
30+
31+
I was unsure if we were allowed to use any external libraries for this project, so I decided to create everything from scratch where a default library did not exist for my needs.
32+
33+
The networking in this application is split up into two parts, there is the core which handles the more generic network events and then there is the [`ChatManager`](src/chat_app/backend/ChatManager.java) which has code specific to this app.
34+
The networking core primarily uses the `java.net.Socket` and `java.net.ServerSocket` classes. I had created four classes that make use of these packages, [`Client`](src/readiefur/sockets/Client.java), [`ServerManager`](src/readiefur/sockets/ServerManager.java), [`ServerClientHost`](src/readiefur/sockets/ServerClientHost.java) and [`ASocket`](src/readiefur/sockets/ASocket.java). All four of these files were inspired by my [`CSharpTools.Pipes`](https://github.com/ReadieFur/CSharpTools/blob/main/src/CSharpTools.Pipes) project as I quickly noticed when researching java networking, that a very similar approach to my C# code could've been taken.
35+
To summarize these classes, the `ServerManager` class is responsible for creating a server which clients can then connect to, it create new socket connections as needed and manage all client and server events. The other two classes, `Client`, `ServerClientHost` are both implementations of the abstract `ASocket` class which contains many virtual methods that help wrap the functionality of the `java.net.Socket` class. The code in these two files only have minor differences.
36+
The `ChatManager` class is responsible for handling all of the chat specific events, such as handshaking with clients, managing message events, automatically migrating hosts and more. Once the core events have been processed by this class, it will then dispatch specific events for this app. Because this class is instanced and due to the fact it can automatically manage connections, you could create multiple instances in a single application, with this class not being a singleton it makes it useful for unit testing.
37+
38+
The frontend of this application is over-engineered, this is a thing I commonly do in my projects as I like to make my programs as modular as possible, so that in the future, like with what was seen in the networking core for this app, I can reuse the code in other projects.
39+
What I had overengineered was my UI parser, I was not a huge fan of the way `java.awt` and `javax.swing` handled UI creation, there would've been a lot of repetition if I had taken this approach. I have had previous experience using C#'s Windows Presentation Foundation (WPF), so I decided to create a similar XML parser for Java, this took me in total about 2 and a half days to create (over the weekend), it was also a good excuse to implement some reflection (and therefore annotations, aka attributes in C#) as bonus marks were available for this.
40+
To summarize how my UI parser works, any class that extends the [`XMLUI`](src/readiefur/xml_ui/XMLUI.java) class, when constructed, will automatically load an XML file with the same name as the owning class.
41+
The parser will then recursively parse the XML tree and attempt to build a UI.
42+
Tags on the XML nodes were used to customize the components and these tags were reflected on the corresponding component class to set the values.
43+
I had also added in some extra features from WPF, though simplified, namely static resources and one-way data binding. The ability to use static resources helped me reduce duplication and the one-way data binding helped me to make automatically syncing the state of the UI and the backend easier, this was one feature that I was especially proud of.
44+
45+
As a result of my design choices, we can see that my program will be primarily event driven, this is due to the multi-threaded nature of the `ServerManager` class and GUI events as well as the abstraction done to make interfacing with each class easier.
46+
47+
While I could've gone on for quite a bit more about the other things I did in this project, this section is already getting quite long, so I have decided to leave it there with the above key information about my development of the program.
48+
49+
## Bugs
50+
While I have tried to keep the program as bug free as possible, it is almost always inevitable that bugs will be present in any program.
51+
For the most part, in my manual testing I have experienced very few bugs, however there is one that I have noticed that I have not been able to fix.
52+
Unfortunately this bug is extremely difficult for me to reproduce, therefore making it equally as hard for me to fix. The bug will occur at startup when a client is trying to connect to a server. I am unsure as to what exactly is causing this issue, however I feel like it could be a race condition on my automatic migration system, this could also explain why the bug is so hard to reproduce. But then looking at my error log and stack trace, the error seems to lie in parsing the data received which after reading the error code online, is due to corrupt data. This bug is considered to be a fatal bug to me because it renders the entire application unusable and floods the console with this error indefinitely. Below you can see a screenshot of the error and the stack trace.
53+
<img src="images/rare_bug.png" width="700">
54+
Other than this one very rare and very annoying bug, I have not experienced any other bugs in my testing.
55+
56+
## Testing
57+
I have tested this application using both manual and JUnit (automated) testing.
58+
The automatic testing was done using JUnit, the tests that I have setup will test the backend of the program. I was going to additionally test the frontend of the program using Windows' UI Automation framework, however after a quick look into the Inspect tool, I noticed that none of the UI elements appeared, this was due to the fact that `java.awt` uses a custom render engine that is not compliant with the Windows UI Automation framework. So for the frontend testing, I had to resort to manually testing the GUI.
59+
60+
## Improvements
61+
What I would've liked to improve on, I would've like to clean up the `ChatManager` class a lot more. While I had refactored it a few times (which can be seen by checking out my commit history), I feel like it could be cleaned up a lot more. It is messy in part due to the fact it started off as being a singleton class, which also contained the CLI code and me not being entirely sure how I wanted to structure the program, it ended up being a more figure it out as I go along type of project.
62+
63+
## Conclusion
64+
Overall I am somewhat satisfied with the result of this project. It was my first time using Java and along the way I had learnt a fair amount about the language, you can check out my [findings.md](findings.md) file if you would like which contains a few of the things that I had discovered about the language along the way, however it should be noted that most of it is just me pointing out how C# is superior to Java x3.
65+
66+
## Screenshots
67+
Below are some screenshots of the program in action.
68+
- In this first image we can see a message being broadcasted to all clients.
69+
<img src="images/broadcast_message.png" width="700">
70+
- In this next image we can see that the server has sent a private message to a client, and the client has received a notification indicating that they have an unread message.
71+
<img src="images/unread_message.png" width="700">
72+
- In this image we can see that the peer "Anonymous1" has received a private message from the peer "Anonymous" and that the peer "Anonymous2" cannot see the message.
73+
<img src="images/private_message.png" width="700">
74+
- In this image we can see that a system message has been placed into the global chat, indicated by a prefix and suffix of `====` as well as being in a light grey colour, that the peer "Anonymous1" has disconnected.
75+
<img src="images/client_disconnect.png" width="700">
76+
- In this final image we can see that the server has disconnected and that one of old clients have become the server and the other old client has automatically connected to the new server.
77+
<img src="images/server_disconnect.png" width="700">
78+
79+
<!-- ## Video demonstration -->
80+
<!-- TODO: Video demonstration -->
81+
<!-- [![CAPTION](THUMBNAIL)](VIDEO) -->
82+
83+
## References
84+
The timestamps used on here are from cached versions of the pages found on Google and the Wayback Machine, the links are to the original pages.
85+
86+
| Source | Author | Date | Used in |
87+
| --- | --- | --- | --- |
88+
| [Convert a number range to another range, maintaining ratio](https://stackoverflow.com/questions/929103/convert-a-number-range-to-another-range-maintaining-ratio) | [jerryjvl](https://stackoverflow.com/users/111781/jerryjvl) | 11th Jan 2023 | [ChatManager.java:190](src/chat_app/backend/ChatManager.java#L190) |
89+
| [Build your own Command Line with ANSI escape codes](https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html#8-colors) | Haoyi | 10th Feb 2023 | [ConsoleColour.java](src/readiefur/console/ConsoleColour.java) |
90+
| [StreamCorruptedException: invalid type code: AC](https://stackoverflow.com/questions/2393179/streamcorruptedexception-invalid-type-code-ac)| [user207421](https://stackoverflow.com/users/207421/user207421) | 16th Feb 2023 | [ASocket.java:20](src/readiefur/sockets/ASocket.java#L20) |
91+
| [CSharpTools.Pipes](https://github.com/ReadieFur/CSharpTools/blob/main/src/CSharpTools.Pipes) | [ReadieFur](https://github.com/ReadieFur) (aka me, Tristan Read) | 27th Jan 2023 | [ServerManager.java](src/readiefur/sockets/ServerManager.java) |
92+
| [Interface WindowListener](https://docs.oracle.com/javase/7/docs/api/java/awt/event/WindowListener.html) | Oracle | 31st Jan 2023 | [Window.java:40](src/readiefur/xml_ui/controls/Window.java#L40) |
93+
94+
## Running the program
95+
### Running/building from source
96+
- Clone this repository
97+
- Open in one of the pre-configured IDEs OR open in your own IDE
98+
- VSCode
99+
- IntelliJ IDEA
100+
- Run or build the program targeting the `App.java` file.
101+
- If you have built the program from source and you want to execute the `RunScenario.bat` file, you will need to change the `JAR_FILE_NAME` variable to the name of the jar file you have built (the default is the name of the project source folder)
102+
103+
### Running from release
104+
Please note that the built jar file on the releases page was built on OpenJDK 11.0.18. As a result if you are using a different version of Java, you may need to build the program from source.
105+
- Download the latest release from the [releases page](./releases/latest)
106+
- Either
107+
- Run a single instance by opening the `University_Of_Greenwich-COMP1549-Advanced_Programming-Coursework.jar` file
108+
- Run the `RunScenario.bat` file to open four instances of the program

RunScenario.bat

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
@echo off
22

3+
set JAR_FILE_NAME=University_Of_Greenwich-COMP1549-Advanced_Programming-Coursework.jar
4+
35
@REM Ensure that the working directory is where this file is placed https://stackoverflow.com/questions/17063947/get-current-batchfile-directory
46
cd %~dp0
57

@@ -24,7 +26,7 @@ goto run
2426
:packed_method
2527
@REM The program will be packed into a jar file.
2628
@REM We can use the -jar flag to specify the path to the jar file we want to run.
27-
set COMMAND=java.exe -jar University_Of_Greenwich-COMP1549-Advanced_Programming-Coursework.jar
29+
set COMMAND=java.exe -jar %JAR_FILE_NAME%
2830
goto run
2931
::#endregion
3032

images/broadcast_message.png

84 KB
Loading

images/client_disconnect.png

268 KB
Loading

images/private_message.png

205 KB
Loading

images/rare_bug.png

589 KB
Loading

images/server_disconnect.png

251 KB
Loading

images/unread_message.png

197 KB
Loading

references.md

-1
This file was deleted.

workspace.code-workspace

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
"settings": {
88
"java.debug.settings.onBuildFailureProceed": true,
99
"cSpell.words": [
10+
"Haoyi",
11+
"jerryjvl",
1012
"Unreads"
1113
]
1214
}

0 commit comments

Comments
 (0)