PROJECT: Mortago
1. Introduction
This project portfolio page showcases my contributions to Mortago - A Software Engineering project developed in my second year of undergraduate study at the National University of Singapore.
About the Team
My team consisted of 5 Year 2 Computer Science undergraduates taking the module CS2103T, a compulsory Software Engineering module.
About the Project
We were given the code for Address Book Level 3 (AB3), a contact management software developed over the years by previous students of this module. We were challenged to delve into Brownfield software development by either developing more features for the given application or morph it to a completely new product. We were required to use the given code as the foundation and maintain its original Command Line Interface (CLI) nature. My team chose to morph it to suit a mortuary management system called Mortago.
Mortago is a one-stop platform which automates fridge management, reminds its users of necessary updates, and even allows them to conveniently generate reports! It completely removes the need to use a register. It consolidates all the information about bodies and fridges in one beautiful dashboard. It is a desktop application supporting CLI and is targeted towards mortuary managers who prefer typing while still enjoy the benefits of Graphical User Interface (GUI). It is developed using Java over a short span of 6 weeks and has approximately 20,000 lines of code.
I worked on the notification feature and the delete command. Moreover, I was responsible for automating fridge management in Mortago. The sections below summarize my contributions to the code base, user guide, developer guide, as well as other team project tasks.
The following are the frequently used symbols in this document:
- 
delete: A dark-red text (also known as a mark-up) indicates that this text is either a full or partial command that can be entered into the CLI. It can also mean a component, class, function, or object used in the code base.
- 
Tips : An annotation indicates important information which may be useful to a user. 
| This is an example of a tip. | 
2. Summary of contributions
This section summarizes my coding, documentation, and other contributions to the team project.
Enhancements
Major Enhancement: I added the notification feature.
- 
What it does: This enhancement reminds the mortuary manager to contact the police, after 10 seconds from the point of adding a Bodyto Mortago, by automatically changing its status and showing a pop-up notification. It also maintains a list of all the notifications (Notif) that can be viewed by either using theshowNotifcommand or clicking on the bell icon beside the command box.
- 
Justification: If the next-of-kin of a body has been uncontactable for more than 24 hours, police must be informed to start a more thorough investigation. It can be tedious for the mortuary manager to manually keep checking which bodies have crosses the 24 hour period. This feature serves the dual purpose of automatically changing the status of the body as well as reminding the manager. For the purpose of testing, the time period is set to 10 seconds instead of 24 hours. 
- 
Highlights: This command makes use of threading to update the body status after 10 seconds. Reflecting changes in the UI was initially challenging because JavaFX works on a separate thread from the main Logic commands. 
- 
Credits: @bjhoohaha/duke’s AlertWindow.java was reused to create NotifWindow.
Major Enhancement: I morphed the delete command in AB3.
- 
What it does: The deletecommand allows the user to delete aBody,Worker, orFridgein Mortago. It uses flagging to differentiate them.
- 
Justification: If the user adds a Bodyby mistake, thedeletecommand offers a convenient way to remove it. Flagging is used because it is more convenient for the user instead of using 3 different commands for deletion.
- 
Highlights: Since Mortago aims to automate mortuary management, deleting a Bodymakes additional changes as follows:- 
If the Bodywas assigned aFridge, this command will remove theBodyand reset the status of theFridgetoUNOCCUPIED.
- 
If the Bodyhas an associatedNotif, this command will also delete theNotif.
 
- 
Minor Enhancement: I automated fridge management.
- 
What it does: If a Bodyis assigned aFridgeand eitherdeleteorupdatecommands are used on thisBody, Mortago will automatically make relevant changes to theFridge.
- 
Justification: Manually managing bodies and fridges in a mortuary is very tedious as any change to a body may mean that the status of the fridge has changed as well. For instance, when a body is claimed, its fridge is no longer occupied. If a manager is handling several bodies and fridges simultaneously, he may make errors. 
- 
Highlights: How Mortago automates fridge management for the deletecommand was explained earlier. In addition to that, the following features are automated:- 
If the status of a Bodyis updated toCLAIMEDorDONATED, its associatedFRIDGE's status is reset toUNOCCUPIEDand theBodyis no longer assigned to thisFridge.
- 
A user cannot assign a Fridgeto aBodywith statusCLAIMEDorDONATED.
- 
An OCCUPIEDFridgecannot be deleted. The user needs to either assign theBodyto anotherFridgeor delete theBody.
- 
A Fridgecannot be assigned multipleBody(s).
 
- 
Code Contributed
You can view my code -[via Reposense]
Other Contributions
Other contributions which I made to the team are discussed in this section.
- 
Project Management: - 
Set-up team repository on Github. 
- 
Set up Travis CI for continuous integration to build and test the software. 
- 
Set-up Coveralls to check code coverage. 
- 
Maintained the issue tracker on GitHub. 
 
- 
- 
Documentation: 
- 
Community 
3. Contributions to the User Guide
The following are the excerpts I wrote in the user guide to teach a user how the notification feature works and
how  they can use the delete command.
{start of extract 1: notification feature}
View notifs panel: showNotifs
This command allows you to view all Notif(s).
A Notif is a notification associated with a Body. In Singapore, if the next-of-kin is not contactable for more
than 24 hours from the time of addition of a Body in Mortago,
police must informed. Mortago removes the hassle of manually keeping track of the status of bodies! For the purpose of
testing, instead of 24 hours, Mortago currently
uses 10 seconds.
When you add a Body or manually set its status to ARRIVED, Mortago
automatically
changes its status to CONTACT_POLICE if its status is still ARRIVED after 10 seconds. It then shows a pop-up
to
remind you to
contact the police. It creates a Notif for this Body and you can view all Notif(s) by either clicking on the
notification bell or typing the showNotif command.
Format: showNotifs
Once you change the status of the Body from CONTACT_POLICE to any other possible status as described in
Section 8.1,
its associated Notif is deleted.
If you change the status of the Body before 10 seconds, no pop-up and Notif are created.
Example:
Imagine that a new Body (John Doe) has just arrived at your mortuary.
1) Type the add command as specified in the example in Section 3.1.1. Currently the status of this Body
is ARRIVED
 
2) Wait for 10 seconds. Mortago automatically changes the status of the Body to CONTACT_POLICE and shows
you a
pop-up
notification.
 
3) Type showNotif and press ENTER to execute it.
 
4) The notification bell opens up a panel and lists all the bodies for which you need to contact the police. You can see John Doe’s ID number B00000020 is in the list.
 
5) Suppose you have contacted the police, change the status of John Doe using the command update -b /id 20 /status
pending police report. John Doe’s ID is no longer listed in the notifs panel.
 
{end of extract 1}
{start of extract 2: delete command}
Deleting an entry : delete
You can delete a body, worker or fridge entry, using its Identification Number by entering a delete command with the
given format below.
Format: delete -FLAG  id
You only need to enter the numeric value of the Identification Number while ignoring the prefixed 0s. For example, if
you want to delete a Fridge with id F01, you need to only enter delete -f 1.
When you delete a Body:
- 
Mortago automatically deletes its associated Notifs. You can learn more aboutNotifsin Section 3.2.1.
- 
If you had assigned a Fridgeto thisBody, Mortago automatically sets the status of theFridgetoUNOCCUPIED.
You cannot delete a Fridge with status OCCUPIED. To still proceed with deletion, you need to either delete the
Body or assign it to another Fridge.
Example:
Imagine that you added someone (Jim Kerr) by mistake and you want to remove his details from Mortago. You see that his ID number is W00003.
To delete his record:
1) Type delete -w 3 and press ENTER to execute it.
 
2) The result box displays the message as shown below.
 
3) And you can check that Jim Kerr is no longer in the list of workers.
 
{end of extract 2}
4. Contributions to the Developer Guide
The following is the excerpt I wrote in the Mortago developer guide. It is targeted at potential future developers who may be interested to further develop the application.
{start of extract: notification feature}
Notification Feature
This feature in Mortago reminds a mortuary manager to contact the police when the next-of-kin of a body
has not been contactable for a given period of time from the point of admission of the Body. He / She then needs
to
contact
the police
to
proceed with a
more thorough investigation. In Singapore, this period is 24 hours. For testing purposes, it has been set to
10 seconds in Mortago.
If the status of a Body is ARRIVED after 10 seconds, it is updated to CONTACT_POLICE and a
pop-up alert is displayed to remind the user.
| If you want to change the time period, you can do so by modifying NOTIF_PERIODandNOTIF_TIME_UNITvariables in
AddCommand.java. | 
Implementation
This command is supported by the model component Notif and the logic component NotifCommand.
In Notif command, the following are the key private variables:
- 
body: Refers to theBodyfor which theNotifis created. This is passed in as a parameter when a new instance of the class is instantiated.
- 
alert: Refers to aRunnablefunction which checks if the current status of the body isARRIVEDand if so, changes it toCONTACT_POLICE.
- 
notifCreationTime: Refers to aDateobject which stores the date and time at the point of addition of the body in Mortago.
The constructor of a NotifCommand must be provided with the following parameters:
- 
notif: Refers to the instance of theNotifwhich is handled by theNotifCommand.
- 
period: Refers to alongvalue for which the NotifCommand needs to wait before executing thealertfunction of thenotif.longis used becausenotifCreationTime.getTime()returns alongwhich is useful in storage. It will be explained in further detail later. Currently, this value is set to10.
- 
timeUnit: Refers to aTimeUnitassociated with theperiod. Currently, this value is set toTimeUnit.SECONDS.
The following class diagram (Figure 15) models the relationships and dependencies among classes in this feature:
 
The following sequence diagrams (Figure 16 and 17) illustrate the execution of the notification feature:
 
 
The following activity diagram summarizes what happens when a user adds a new body and a NotifCommand is
instantiated:
 
| 
 | ||
| No! If the status of the  | 
Storing executed and pending Notifs
NotifCommand supports storage where each Notif with its associated Body and the long equivalent of the
notifCreationTime is stored in a JSON file along with the other Entities. When the MainApp is initialized, the
following happens:
- 
All the Notif(s) are fetched from the storage.
- 
For each Notif, the difference of the current system time andnotifCreationTimeis calculated.
- 
If the difference is more than the period, then the status of the associatedBodyis changed toCONTACT_POLICE. Otherwise, theNotifCommandis scheduled to be executed after the calculated time difference.
- 
The Notifis added to the model.
| 
 | ||
| 
 | 
Defensive programming
The NotifCommand heavily makes use of the ScheduledExecutorService and Platform.runLater(Runnable runnable) to
make changes to the Body status and Notif. They use threading to allow tasks to be handled concurrently. For instance,
even after scheduling a Runnable function, the user is still able to carry on with other commands of Mortago such
as updating the status of the Body, adding a new Fridge etc.
As per the official Java Documentation, Platform.runLater(Runnable runnable) runs the specified runnable function
on a thread dedicated to JavaFX application at some unspecified time in the future. So,
if some updates to the model are wrapped inside it as a Runnable while others are not, it can result in a
mismatch of model. For instance, you may want to delete a Notif which already exists in the model. The usual
process will be to first check whether it exists and if it does, then proceed with deletion. However, due to
threading, you may end up in a situation when the app finds the Notif at the point of checking but throws a
NullPointerException when proceeding with the deletion.
To prevent this, in Mortago, any addition or deletion of Notif in the model during the execution of the
NotifCommand and parts of UpdateCommand are wrapped inside Platform.runLater(Runnable runnable). This ensures
that updates to the model happen sequentially and not concurrently and the relevant changes can be reflected on the
UI.
Moreover, all these operations are wrapped inside a try-catch block. Either the NullPointerException or
DuplicateNotifException is directly thrown in the form of CommandException or it is logged in Logger. A
code snippet of NotifCommand to illustrate this is show below.
 if (model.hasNotif(notif)) {
    try {
        model.deleteNotif(notif);
    } catch (NullPointerException exp) {
        logger.info(MESSSAGE_NOTIF_DOES_NOT_EXIST);
    }
}
Platform.runLater(() -> {
    if (!model.hasNotif(notif)) {
        try {
            model.addNotif(notif);
        } catch (DuplicateNotifException exp) {
            logger.info(MESSAGE_DUPLICATE_NOTIF);
        }
    }
});Design Considerations
Aspect: How to delay change in status of the Body
- 
Alternative 1 (current choice): Use ScheduledExecutorService.- 
Pros: Does not depend on thread synchronization and avoids the need to deal with threads directly. 
- 
Cons: May cause memory leaks if cache is not cleared. 
 
- 
- 
Alternative 2: Use Thread.sleep- 
Pros: Straightforward way to delay a thread. 
- 
Cons: May quickly run into OutOfMemory error. 
 
- 
Alternative 1 is the current choice because of its simplicity and robustness as it abstracts away the need to manually deal with threads.
Aspect: How the behaviour of NotifCommand differs when the app is initialized
- 
Alternative 1 (current choice): Do not show a pop-up if the difference between system time and notifCreationTimeexceedsperiod.- 
Pros: Prevents the situation of multiple pop-ups on app initialization. 
- 
Cons: Does not prompt the user who may in turn forget to contact the police. 
 
- 
- 
Alternative 2: Show pop-up on app initialization for Notif(s) in storage for which the difference between system time andnotifCreationTimeexceedsperiod.- 
Pros: Ensures that the user does not forget about contacting the police. 
- 
Cons: May slow down the computer and lag the app if there are too many pop-up notifications at the same time. 
 
- 
Alternative 1 is the current choice because we want the app to be responsive and scalable in the long term. The notification bell is placed beside the command box to prevent instances of user forgetting to contact the police.
{end of extract}