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 Body to 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 the showNotif command 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 delete command allows the user to delete a Body, Worker, or Fridge in Mortago. It uses flagging to differentiate them.

  • Justification: If the user adds a Body by mistake, the delete command 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 Body makes additional changes as follows:

    • If the Body was assigned a Fridge, this command will remove the Body and reset the status of the Fridge to UNOCCUPIED.

    • If the Body has an associated Notif, this command will also delete the Notif.

Minor Enhancement: I automated fridge management.

  • What it does: If a Body is assigned a Fridge and either delete or update commands are used on this Body, Mortago will automatically make relevant changes to the Fridge.

  • 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 delete command was explained earlier. In addition to that, the following features are automated:

    • If the status of a Body is updated to CLAIMED or DONATED, its associated FRIDGE 's status is reset to UNOCCUPIED and the Body is no longer assigned to this Fridge.

    • A user cannot assign a Fridge to a Body with status CLAIMED or DONATED.

    • An OCCUPIED Fridge cannot be deleted. The user needs to either assign the Body to another Fridge or delete the Body.

    • A Fridge cannot be assigned multiple Body(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:

    • Wrote the user guide and developer guide for the delete and notifications feature (Pull requests #252, #267).

    • Updated existing diagrams to fit the team’s chosen colour scheme (#123).

    • Updated use cases for notification feature in the developer guide (#40).

  • 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

Notif1

2) Wait for 10 seconds. Mortago automatically changes the status of the Body to CONTACT_POLICE and shows you a pop-up notification.

Notif2

3) Type showNotif and press ENTER to execute it.

Notif3

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.

Notif4

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.

Notif5

{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 about Notifs in Section 3.2.1.

  • If you had assigned a Fridge to this Body, Mortago automatically sets the status of the Fridge to UNOCCUPIED.

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.

DeleteStep1

2) The result box displays the message as shown below.

DeleteStep2

3) And you can check that Jim Kerr is no longer in the list of workers.

DeleteStep3

{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_PERIOD and NOTIF_TIME_UNIT variables 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 the Body for which the Notif is created. This is passed in as a parameter when a new instance of the class is instantiated.

  • alert: Refers to a Runnable function which checks if the current status of the body is ARRIVED and if so, changes it to CONTACT_POLICE.

  • notifCreationTime: Refers to a Date object 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 the Notif which is handled by the NotifCommand.

  • period: Refers to a long value for which the NotifCommand needs to wait before executing the alert function of the notif. long is used because notifCreationTime.getTime() returns a long which is useful in storage. It will be explained in further detail later. Currently, this value is set to 10.

  • timeUnit: Refers to a TimeUnit associated with the period. Currently, this value is set to TimeUnit.SECONDS.

The following class diagram (Figure 15) models the relationships and dependencies among classes in this feature:

NotifCommandClassDiagram
Figure 1. Notification Class Diagram

The following sequence diagrams (Figure 16 and 17) illustrate the execution of the notification feature:

NotifCommandSequenceDiagram
Figure 2. Notification Command Sequence Diagram
ChangeUiFnSequenceDiagram
Figure 3. ChangeUI function Sequence Diagram

The following activity diagram summarizes what happens when a user adds a new body and a NotifCommand is instantiated:

NotifCommandActivityDiagram
Figure 4. Notification Command Activity Diagram
Is NotifCommand only executed when a Body is added?

No! If the status of the Body is changed to ARRIVED using the UpdateCommand, NotifCommand is still executed. The Notif is scheduled to be executed after the specified period from the point in time when the status of the body was updated.

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:

  1. All the Notif (s) are fetched from the storage.

  2. For each Notif, the difference of the current system time and notifCreationTime is calculated.

  3. If the difference is more than the period, then the status of the associated Body is changed to CONTACT_POLICE. Otherwise, the NotifCommand is scheduled to be executed after the calculated time difference.

  4. The Notif is added to the model.

When is the NotifCommand not executed?
  • If the status of the Body is changed before the 10 second window.

  • If the Body is deleted before the specified period.

  • If the difference between notifCreationTime and system time is more than period when the app is initialized.

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 notifCreationTime exceeds period .

    • 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 and notifCreationTime exceeds period.

    • 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}