Skip to content

Latest commit

 

History

History
1466 lines (1002 loc) · 54.5 KB

File metadata and controls

1466 lines (1002 loc) · 54.5 KB

Developer Guide

Introduction

The purpose of this Developer Guide is to provide useful information to software developers who desire to contribute to the project (e.g. optimizing of code, adding test cases, etc.), including an overview of the software architecture, design as well as current implementations and intended functionality of current features. The police database is for police officers(PO) and headquarters personnel(HQP). Both groups will have varying access and authorization levels to this database. POs would be able to read from the database after screening someone while on patrol and choose his course of action base on the status/threat level of subject. HQP would have the added functions of adding and removing people from the database. Refer to quick start to get started.

Setting up

To set up the project successfully on your computer, follow the steps below.

Prerequisites

In order to start the setup, you are required to install the following:

  • JDK 9 or later

  • IntelliJ IDE

Importing the project into IntelliJ

  1. Open IntelliJ (if you are not in the welcome screen, click File > Close Project to close the existing project dialog first)

  2. Set up the correct JDK version

    1. Click Configure > Project Defaults > Project Structure

    2. If JDK 9 is listed in the drop down, select it. If it is not, click New…​ and select the directory where you installed JDK 9

    3. Click OK

  3. Click Import Project

  4. Locate the build.gradle file and select it. Click OK

  5. Click Open as Project

  6. Click OK to accept the default settings

  7. Run the seedu.addressbook.Main class (right-click the Main class and click Run Main.main()) and try executing a few commands

  8. Run all the tests (right-click the test folder, and click Run 'All Tests') and ensure that they pass

  9. Open the StorageFile file and check for any code errors

    1. Due to an ongoing issue with some of the newer versions of IntelliJ, code errors may be detected even if the project can be built and run successfully

    2. To resolve this, place your cursor over any of the code section highlighted in red. Press ALT+ENTER, and select Add '--add-modules=java.xml.bind' to module compiler options

Configurations to do before writing code

Configuring the coding style

This project follows oss-generic coding standards. IntelliJ’s default style is mostly compliant with ours but it uses a different import order from ours. To rectify,

  1. Go to File > Settings…​ (Windows/Linux), or IntelliJ IDEA > Preferences…​ (macOS)

  2. Select Editor > Code Style > Java

  3. Click on the Imports tab to set the order

    • For Class count to use import with '*' and Names count to use static import with '*': Set to 999 to prevent IntelliJ from contracting the import statements

    • For Import Layout: The order is import static all other imports, import java.*, import javax.*, import org.*, import com.*, import all other imports. Add a <blank line> between each import

Optionally, you can follow the UsingCheckstyle.adoc document to configure Intellij to check style-compliance as you write code.

Updating documentation to match your fork

After forking the repo, the documentation will still have the SE-EDU branding and refer to the se-edu/addressbook-level3 repo.

If you plan to develop this fork as a separate product (i.e. instead of contributing to se-edu/addressbook-level3), you should do the following:

  1. Configure the site-wide documentation settings in build.gradle, such as the site-name, to suit your own project.

  2. Replace the URL in the attribute repoURL in DeveloperGuide.adoc and UserGuide.adoc with the URL of your fork.

Setting up CI

Set up Travis to perform Continuous Integration (CI) for your fork. See UsingTravis.adoc to learn how to set it up.

Design

The diagram below shows a high level architecture design of the current classes that are used in the project.

mainClassDiagramFULLedited

Implementation

This section describes some of the more important details of certain features implemented.

1a. Password feature

Current Implementation

This feature provides different access levels of commands to the user, depending on the password entered.

  1. unlockDevice() - attempts to match a hashcoded user input with an existing password in the passwordStorage.txt file.

The following is an example usage scenario of the password feature.

Step 1: User enters password for HQP.

Step 2: decipherUserCommandText() in MainWindow class identifies command as a password input, through the use of isLocked() method in the Password class.

Step 3: unlockDevice() in Password class is called.

Step 4: The user input, userCommandText, is then hashcoded using userCommandText.hashCode().

Step 5: Using a Buffered reader from the readAndWrite class, a loop through passwordStorage.txt tries to match the hashcoded input with an existing password.

Step 6: The user and password are stored in passwordStorage.txt in this format : "userID (hashcoded)password".

Step 7: When matched, the userID is returned and a welcome message is displayed for the particular user.

Design Considerations

Aspect: How password feature is implemented
  • Alternative 1 (current choice): Using a password with no need for username

    • Pros: Reduce user’s keyboard input

    • Cons: Slow buffered reader has to loop through all passwords in the text file

  • Alternative 2: Using username and password

    • Pros: Can use a hashmap for quick look up, with the userID as key and hashcoded password as the value

    • Cons: More input from user, and difficult to store in an external text file.

1b. Update Password Feature

Current Implementation

This feature enables only HQP to update any existing password.

  1. updatePassword() - user enters existing password to update.

  2. updatePasswordFinal() - user enters new alphanumeric password to replace existing password.

The following is an example usage scenario of the update password feature.

Step 1: User enters password for HQP.

Step 2: User enters "update password" command.

Step 3: decipherUserCommandText() in MainWindow class identifies the command as "update password" and begins update password sequence.

Step 4: User enters password for HQP.

Step 5: Similar to the password feature, the process of the user input to match the existing HQP password maintains.

Step 6: User enters new 5-character long alphanumeric password.

Step 7: The new entered password runs through passwordValidityChecker() to check if the password is at least 5 characters long and at least alphanumeric. This password is stored as oneTimePassword String.

Step 8: The user enters the same new password. It matches with the oneTimePassword.

Step 9: The Buffered reader then reads reads through passwordStorage.txt, and a Print writer from the ReadAndWrite class writes existing passwords to a temporary file, while writing the new password in place of the old password to change.

Design Considerations

Aspect: How password feature is implemented
  • Alternative 1 (current choice): Using a password with no need for username

    • Pros: Reduce user’s keyboard input

    • Cons: Slow buffered reader has to loop through all passwords in the text file

  • Alternative 2: Using username and password

    • Pros: Can use a hashmap for quick look up, with the userID as key and hashcoded password as the value

    • Cons: More input from user, and difficult to store in an external text file.

2a. "find" command (edited)

Current Implementation

The new "find" command is revised from the existing "find" command in AB3. Instead of finding a person by name, it finds a person using his NRIC. It also implements the following operations:

  1. execute() - executes the "find" command itself and displays the result to the user.

  2. getPersonWithNric() - Searches the addressbook to retrieve the person with the specified NRIC.

The following is an example usage scenario of the "find" command:

Step 1: The user input his password and unlocks the system.

Step 2: The user executes "find s1234567a" command.

Step 3: Parser class determines the command word and runs prepareFind method.

Step 4: prepareFind determines string is a valid nric, then instantiates a new FindCommand.

Step 5: Logic class calls the execute() method on the FindCommand object.

Step 6: The getPersonWithNric() method called in execute() searches the addressbook for the person with "s1234567a" if he exists and person is stored in a list.

Step 7: The person is found and is stored in a matchedPerson list variable. execute() returns a CommandResult using the matchedPerson list as its argument.

Step 8: The CommandResult object displays to the user the searched person and his details, all of which in string form.

Alternatives considered:

  • Continue to use the original way of finding by name

    • However, there could be multiple people with the same name

    • Using nric to find people would be better as each person has a unique nric

2b. "check" command

Current Implementation

Only HQP may use this command. This command displays the timestamps of which a person with the specified NRIC was screened using the "find" command. The "check" command makes some use of the "find" command. Every time the "find" command successfully finds a person, a line in the format of: "NRIC timestamp" is printed in a text file called "screeningHistory.txt". The "check" command will read this file and retrieve the timestamps corresponding to the specified NRIC.

It also implements the following operations:

  1. execute() - executes the "check" command itself and displays the result to the user.

  2. getPersonWithNric() - Searches the addressbook to retrieve the person with the specified NRIC.

Below is an example of its usage:

Step 1: The user(a HQP) input his password and unlocks the system.

Step 2: The user executes "check s1234567a"

Step 3: Parser class determines the command word and runs prepareCheck method.

Step 4: prepareCheck determines string is a valid nric, then instantiates a new CheckCommand.

Step 5: Logic class calls the execute() method on the CheckCommand object.

Step 6: execute() also calls the getPersonWithNric() method. This method will read the screeningHistory.txt line by line, where each line is in the format of "NRIC timestamp", for example "s1234567a 18/10/2018-2038hrs by hqp". Each line is split into the NRIC and timestamp. If line[0] is the NRIC specified, the corresponding timestamp is stored in a list.

Step 7: The list from step 6 gets returned by execute() to create a CommandResult object which displays all the timestamps to the user.

Alternatives considered:

  • Having a text file for each person, stored in a 'persons' folder

    • Each timestamp would then be stored in the respective text file

    • Pros: Retrieving timestamps would be much more efficient

    • Cons: Space complexity would increase especially if the number of persons increased drastically

2c. "edit" command

Current Implementation

Only a HQP may use this command. This command allows HQP to update their chosen parameters which include the status, offense, postal code and wanted attributes of a specific NRIC. It is similar to the "find" command in the sense that it searches for the person in the addressBook list by NRIC.

It also implements these methods:

  1. execute() - executes the "edit" command itself and displays result to user

This is an example scenario of "edit" command

Step 1: The user inputs HQP password and logs in as HQP.

Step 2: The user types "edit n/s1234567a p/510247 s/wanted w/murder o/gun" and executes it.

Step 3: Parser class determines the command word and runs the prepareEdit method

Step 4: prepareEdit method in Parser class would parse each non-empty input such as NRIC, Postal Code, Status, Wanted & Offense from the input text to instantiate the EditCommand class.

Step 5: Logic class then calls the execute method on EditCommand Object. Person with NRIC "s1234567a" is searched for in the addressbook. If he/she exists, then the person’s attributes get updated accordingly.

Step 6: CommandResult with successful message is returned to Logic class, which then displays to user: "Edited person: s1234567a".

3a. "showunread" command

Current Implementation

Once system is unlocked, regardless of which user you are, you can use this command. This command lists the new/unread messages in your inbox based on the password you used to unlock the system. When messages are sent, they are stored inside a text file called "inboxMessages/'userID'", where 'userID' refers to the ID of the intended recipient. These text files store messages directed to each individual who can log in and access their personalised inbox. It also implements the following operations:

  1. execute() - executes the "showunread" command itself and displays the result to the user.

  2. loadMessages() - Searches the text file storing messages for the specific police officer identified by the userID and loads it into a data structure, sorting the messages according to how urgent they should be attended to (sorted first by read status, followed by priority and then the time the message was sent).

  3. concatenateMsg() - Loaded messages are then concatenated in a single string as fullPrintedMessage and passed to the main window through CommandResult.

The following is an example usage scenario of the "showunread" command:

Step 1: The user input his password and unlocks the system.

Step 2: The user executes "showunread" command. The "showunread" command calls execute() which also calls getMessagesFor() method.

Step 3: The loadMessages() method searches message storage file for the messages directed to the respective user, if any, and they are stored into a data structure.

Step 4: The messages that are found and are stored in a TreeSet, split by its read status, message priority, timestamp, and the message itself for sorting purposes.

Step 5: The concatenateMsg() method will then append all unread messages in sorted order to a string to be passed to the CommandResult object later.

Step 6: execute() returns a CommandResult using the concatenated string as its argument.

Step 7: The CommandResult object displays to the user the number of unread messages he has, and the list of unread messages sorted according to their urgency.

Alternatives considered:

  • Using a List instead of a TreeSet.

    • Pros: Smaller space complexity.

    • Cons: Less efficient code as 'sort' function must be called every time a new message is stored to maintain sorted order. Eventually, we decided to use TreeSet in our implementation as we felt that the pros outweighed the cons. This becomes more obvious when the amount of data stored gets larger.

  • Using a single text file for storing messages, storing the userID of the recipient in the text file.

    • Pros: Fewer files to manage and filepaths to traverse.

    • Cons: Less efficient as it means more memory is required for storage per message stored (additional information of recipient of message required to be stored in the data structure itself when loaded). Eventually, we also used multiple message storage files, each dedicated to a specific user, as this allowed us to increase the time efficiency of the code as the getMessagesFor() method did not need to sort through the messages based on recipient anymore. This benefit becomes especially obvious as well when there is a large number of messages that has to be stored, directed towards multiple users.

3b. "inbox" command

Current Implementation Inbox command has the same implementation as the "showunread" command - except that it shows you all the messages that are in your inbox (both read and unread). This is to allow you to access the messages that you have previously marked as read.

3c. "read" command

Current Implementation

Once the system is unlocked, you can access unread messages directed to you via the "showunread" command explained above. Once action has been taken based on what the message sent to you is about, you can mark the message as read using the "read" command. Messages displayd in "showunread" command is first stored inside a static HashMap, with the key as the message index and the message itself as the value of the HashMap. When the user wishes to mark a message as read, he will type "read 'index'", and the respective message displayed at that specific index will be marked as read and updated in the message storage file of the user. The "read" command can only be used after the "showunread" command has been used at least once successfully.

The following is an example usage scenario of the "read" command:

Step 1: User inputs his password and unlocks the system.

Step 2: User executes "showunread" OR "inbox" command. If command is successfully executed, a list of unread messages directed to the user will be displayed.

Step 3: Messages that are read from the user’s inbox will also be recorded in a static HashMap called recordNotifications, with the message index used as the key.

Step 4: User executes "read 3" command. If 3 is a valid index (i.e. there were at least 3 unread messages that were displayed), the third message displayed will be marked as read.

Step 5: For the messages to be marked as read, the message itself is updated in the HashMap based on the index, and the message storage text file will be overwritten with the messages stored in the HashMap, effectively updating the read status of the message read.

Step 6: The CommandResult object displays to the user a message indicating that the updating of the read status was successful or not.

3d. "clearinbox" command

Current Implementation

Once the system is unlocked, you can clear your own inbox should there be too many messages stored in it using this command. Once the command has been entered, ReadNotification object will first be generated to attempt reading from the text file storing messages in your inbox. This is to check that the file exists in the first place. If it reads from the text file successfully, a WriteNotification object will then be generated, instantiating a PrintWriter that overwrites the contents in the text file storing the messages in your inbox.

It also implements the following methods:

  1. execute() - executes the "clearinbox" command and displays the result to the user.

  2. readFromFile() - method from ReadNotification object that attempts to access the contents of the text file.

  3. clearInbox() - method from WriteNotification object that clears the content in the text file storing the user’s messages.

  4. clearInboxRecords() - clears any records of messages displayed to ensure that all traces of existing messages are also cleared.

The following is an example usage scenario of the "clearinbox" command:

Step 1: User inputs his password and unlocks the system.

Step 2: User executes "clearinbox" command. If command is successfully executed, the feedback "Inbox cleared!" will be displayed to the user.

3e. "rb" command

Current Implementation

The rb command is an abbreviation of request backup. Both PO & HQP can use this command as anyone can request for help. When the command is executed, a Msg object is generated. Inside this Msg object, several fields exist which include:

  • Priority of offense

  • Patrol resource ID of requester

  • Patrol resource respective Google Maps URL Location.

  • Current case patrol resource needs help with

Then the Msg object is passed to the writeNotifcation object to be written into the HQP’s message file. The filepath for HQP’s message is ./inboxMessages/headquartersInbox

It also implements these following methods:

  1. execute() - executes the "RequestHelpCommand" command and displays result to user.

The following is an example usage scenario of the "rb" command:

Step 1: User inputs PO1 password and logs in as PO1.

Step 2: User executes "rb gun".

Step 3: Parser class identifies user command as "rb" and runs prepareRequest method.

Step 4: prepareRequest method identifies offense & current user ID session.

Step 5: RequestHelpCommand class is instantiated with message template consisting & case which in this case is 'gun'.

Step 6: WriteNotification is instantiated to write the message the HQP inbox file.

Step 7: CommandResult with successful message is returned to Logic class, which then displays to user: "Request for backup case from po1 has been sent to HQP."

3f. "dispatch" command

Current Implementation

Only HQP has access to the "dispatch" command. Dispatch command sends a message to both the designated requester & backup officers. The system creates two WriteNotification classes, the first writes to the requester inbox and the second writes to the backup officer inbox.

The message sent to the requester’s inbox includes the ETA for the backup officer with his/her location both in raw longitude & latitude form and Google Maps URL format.

It is similar for the message sent to the backup’s inbox which includes the ETA that he/she should arrive within & Google Maps URL location of the requester’s Location.

It also implements these following methods:

  1. execute() - executes "dispatch" command and displays result to user

The following is an example usage scenario of the "dispatch" command:

Step 1: User inputs HQP password and logs in as HQP.

Step 2: User executes "dispatch PO1 gun PO3".

Step 3: Parser class identifies user command as "dispatch" and runs prepareDispatch method.

Step 4: prepareDispatch method identifies PO1 as backup officer, gun as case & PO3 as requester officer.

Step 5: DispatchCommand class is instantiated with 2 different WriteNotification classes for two different files.

Step 6: DispatchCommand object is executed, Msg for requester & backup officer are generated to include content explained above.

Step 7: Both Msg objects are passed to WriteNotification class to be written to the respective recipient files.

Step 8: CommandResult with successful message is returned to Logic class, which then displays to user: "Dispatch for PO3 backup is successful."

4a. "updatestatus" command

Current Implementation

Only HQP can use this command. This command sets the engagement status(the "isEngaged" boolean) of a PO to false. It also implements the following methods:

  1. execute() - executes the "updatestatus po[id]" command, sets the isEngaged boolean to false and displays the result to the user

The following is an example usage scenario of the "updatestatus" command:

Step 1: User inputs password and unlocks the system

Step 2: User executes "updatestatus po1" (example PO here is "po1")

Step 3: Parser class identifies command as "updatestatus" and runs prepareUpdateStatus method.

Step 4: prepareUpdateStatus checks is po1 is a valid PO ID through a regex expression and instantiates a new UpdateStatus command.

Step 5: Logic class calls the execute() method in the UpdateStatusCommand object.

Step 6: execute() also calls for the setStatus() method in PatrolResourceStatus class sets the isEngaged boolean of "po1", in this case, to false.

Step 7: A CommandResult object with the successful message is created to be displayed to the user.

Alternatives considered:

  • Using a text file to store the statuses of the POs

    • Pros: The statuses are saved even after exiting the system

    • Cons: Time and space complexity increases especially if there are many POs to manage

4b. "checkstatus" command

Current Implementation

This command lists out all the POs and their current engagement statuses. The POs and their details are stored in an Arraylist as the assumption here is the system will be running continuously for the whole working time, or shift, for example. It also implements the following methods:

  1. execute() - executes the "checkstatus" command and stores all POs in a list

  2. extractEngagementInformation() - iterates through the ArrayList of POs and only store and return their ID and engagement statuses

The following is an example usage scenario of the "checkstatus" command:

Step 1: User inputs password and unlocks the system.

Step 2: User executes "checkstatus".

Step 3: Parser class identifies command as "checkstatus" and returns a new CheckPOStatusCommand object.

Step 4: Logic class calls the execute() method in the CheckPOStatusCommand object.

Step 5: execute() also calls for the extractEngagementInformation() method and stores the PO Ids and the engagement status in a list.

Step 6: A CommandResult object is created and displays the list to the user.

Alternatives considered:

  • Similar to what was mentioned in "updatestatus" command section, use a text file for each PO and store their status

    • Pros: Easier to identify a PO, just look for the text file with their ID

    • Cons: Space would be an issue especially when there are many POs to manage

5. "logout" command

Current Implementation

This command logs the current user out of the System.

  1. execute() - executes the "logout" command and returns all boolean flags related to passwords are set to false.

The following is an example usage scenario of the "logout" command:

Step 1: User executes "logout".

Step 2: decipherUserCommandText() in MainWindow class identifies command as "logout".

Step 3: Boolean flags for isHQP, isPO1, isPO2, isPO3, isPO4, isPO5 in the Password class is set to false. This is done using the lockIsHqp() and lockIsPo() methods in the Password class.

Step 4: isUpdatePasswordConfirm and isUpdatingPassword flags are also set to false through lockUpdatePasswordConfirm() and lockUpdatingPassword() in the Password class is also set to false.

Step 5: A CommandResult object is created and displays a message that the user is logged out of the System and prompts for a password.

Design Considerations

Aspect: How logout executes
  • Alternative 1 (current choice): Logout extends command.

    • Pros: Easy to implement.

    • Cons: Using MainWindow instead of parser to detect that it is the logout command.

  • Alternative 2: Logout as a method in password class.

    • Pros: Can access boolean flags privately in the same class.

    • Cons: Not using abstract class of command.

6. Autocorrection feature

Current Implementation

The autocorrect mechanism is facilitated by use of dynamic programming. The algorithm called EditDistance checks the number of single character changes to be made to convert an invalid input into one expected by the system. Currently, changes involving one single character can be corrected by the system for commands and changes involving one or two single characters can be corrected by the system for NRICs. It implements the following operations:

  1. checkDistance() - It returns the edit distance needed to convert one string to the other. In this case, it returns the number of single character changes (either addition of a character, deletion of a character or changing a character) to convert invalid user input into its most probable correct implementation.

The following is an example usage scenario of the autocorrection feature for commands:

Step 1: The user inputs his password and unlocks the system.

Step 2: The user enters an invalid command.

Step 3: The system predicts the most probable intended command the user would have wanted to input and then prompts the user to use the prediction given in its valid format.

The following is an example usage scenario of the autocorrection feature for NRICs:

Step 1: The user inputs his password and unlocks the system.

Step 2: The user tries to edit, delete or check an invalid NRIC.

Step 3: The system predicts the most probable intended NRIC the user would have wanted to input and then prompts the user to use the prediction given in the valid format of the command.

The input is checked by the algorithm in the MainWindow before it is sent to the Parser class. This is to ensure invalid input can be caught by the algorithm to give its correction before it is deemed as invalid by the Parser during which time all commands will be laid out to the user.

Alternatives considered:

  • Running the algorithm from the Parser- This however will not allow the prediction to be reported efficiently.

  • Include predictions with more than one character changes- This will bring in ambiguity in the correction algorithm and increases chances of errors.

7a. "help" command

Current Implementation

The help command returns the list of commands which can be input by the user based on their level of access. A HQP user is shown all the commands while a PO user is shown only limited commands.

It also implements these methods:

  1. execute() - executes the "help" command itself and displays result to user

This is an example scenario of "help" command

Step 1: The user inputs PO password and logs in as PO.

Step 2: The user types "help" and executes it.

Step 3: Parser class determines the command word and return the list of commands that can be input by a PO.

7b. "add" command

Current Implementation

Only a HQP may use this command. This command allows HQP to update the Police Records with a new subject. The subject can be added with the details- name, NRIC, date of birth, postal code, status, offense and optional past offences.

It also implements these methods:

  1. execute() - executes the "add" command itself and displays result to user

This is an example scenario of "add" command

Step 1: The user inputs HQP password and logs in as HQP.

Step 2: The user types "add John Doe n/s1234567a d/1996 p/510246 s/xc w/none o/theft o/drugs" and executes it.

Step 3: Parser class determines the command word and runs the prepareAdd method

Step 4: prepareAdd method in Parser class would parse the inputs from the input text to instantiate the AddCommand class.

Step 5: Logic class then calls the execute method on AddCommand Object. Person with NRIC "s1234567a" is added in the addressbook.

Step 6: CommandResult with successful message is returned to Logic class, which then displays to user: "New person added: John Doe Nric: s1234567a DateOfBirth: 1996 Postal Code: 510246 Status: xc Wanted For: [none] Past Offences:[drugs][theft]".

Logging

We are using java.util.logging package for logging. The Parser class is used to manage the logging levels and logging destinations.

  • The logging level can be controlled using the logLevel setting in the configuration file (See [Implementation-Configuration])

  • The Logger for a class can be obtained using Parser.getLogger(Class) which will log messages according to the specified logging level

  • Currently log messages are output through: Console and to a .log file.

Logging Levels

  • SEVERE : Critical problem detected which may possibly cause the termination of the application

  • WARNING : Can continue, but with caution

  • INFO : Information showing the noteworthy actions by the App

  • FINE : Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size

Configuration

Certain properties of the application can be controlled (e.g App name, logging level) through the configuration file (default: config.json).

Documentation

We use asciidoc for writing documentation.

Note
We chose asciidoc over Markdown because asciidoc, although a bit more complex than Markdown, provides more flexibility in formatting.

Editing Documentation

See UsingGradle.adoc to learn how to render .adoc files locally to preview the end result of your edits. Alternatively, you can download the AsciiDoc plugin for IntelliJ, which allows you to preview the changes you have made to your .adoc files in real-time.

Publishing Documentation

See UsingTravis.adoc to learn how to deploy GitHub Pages using Travis.

Converting Documentation to PDF format

We use Google Chrome for converting documentation to PDF format, as Chrome’s PDF engine preserves hyperlinks used in webpages.

Here are the steps to convert the project documentation files to PDF format.

  1. Follow the instructions in UsingGradle.adoc to convert the AsciiDoc files in the docs/ directory to HTML format.

  2. Go to your generated HTML files in the build/docs folder, right click on them and select Open withGoogle Chrome.

  3. Within Chrome, click on the Print option in Chrome’s menu.

  4. Set the destination to Save as PDF, then click Save to save a copy of the file in PDF format. For best results, use the settings indicated in the screenshot below.

chrome save as pdf
Figure 1. Saving documentation as PDF files in Chrome

Site-wide Documentation Settings

The build.gradle file specifies some project-specific asciidoc attributes which affects how all documentation files within this project are rendered.

Tip
Attributes left unset in the build.gradle file will use their default value, if any.
Table 1. List of site-wide attributes
Attribute name Description Default value

site-name

The name of the website. If set, the name will be displayed near the top of the page.

not set

site-githuburl

URL to the site’s repository on GitHub. Setting this will add a "View on GitHub" link in the navigation bar.

not set

site-seedu

Define this attribute if the project is an official SE-EDU project. This will render the SE-EDU navigation bar at the top of the page, and add some SE-EDU-specific navigation items.

not set

Per-file Documentation Settings

Each .adoc file may also specify some file-specific asciidoc attributes which affects how the file is rendered.

Asciidoctor’s built-in attributes may be specified and used as well.

Tip
Attributes left unset in .adoc files will use their default value, if any.
Table 2. List of per-file attributes, excluding Asciidoctor’s built-in attributes
Attribute name Description Default value

site-section

Site section that the document belongs to. This will cause the associated item in the navigation bar to be highlighted. One of: UserGuide, DeveloperGuide, LearningOutcomes*, AboutUs, ContactUs

* Official SE-EDU projects only

not set

no-site-header

Set this attribute to remove the site navigation bar.

not set

Site Template

The files in docs/stylesheets are the CSS stylesheets of the site. You can modify them to change some properties of the site’s design.

The files in docs/templates controls the rendering of .adoc files into HTML5. These template files are written in a mixture of Ruby and Slim.

Warning

Modifying the template files in docs/templates requires some knowledge and experience with Ruby and Asciidoctor’s API. You should only modify them if you need greater control over the site’s layout than what stylesheets can provide. The SE-EDU team does not provide support for modified template files.

Use Cases

The use cases for the current features and commands implemented can be found in Appendix B.

Testing

To run tests for the project, complete the step below.

  • In IntelliJ, right-click on the test folder and choose Run 'All Tests'

Appendix A: User Stories

Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *

PO- Police Officer HQP- Headquarters Personnel

Priority As a …​ I want to …​ So that I can…​

* * *

PO

request backup efficiently and quickly

get help in dangerous situations like capturing an escaped criminal, saving a person’s life

* * *

PO

know if accused is dangerous

know the steps I should take to handle the accused

* * *

PO

easily access numerous NRICs and commands with autocorrection

be efficient in going through many records even if some mistake is made

* * *

PO

quickly screen the subject using his NRIC

know his current status and past offences if any

* * *

HQP

know the screening history of a particular subject using his NRIC

use it in my investigation

* * *

PO

secure my device with a password

prevent breach of confidential data

* *

HQP

update password of any device regularly

so that I can increase security

*

PO

know the serial number and battery level

to return it to HQ and charge it when necessary

Appendix B: Use Cases

(For all use cases below, the System is the Police Records and the User is either the `Police Officer (PO)' or 'Headquarters Personnel (HQP)', unless specified otherwise)

Use case: Enter Headquarters Personnel password

MSS

  1. User opens System.

  2. System prompts User to enter his password.

  3. User enters HQP password.

  4. System displays message "Welcome Headquarters Personnel" and System prompts User for a command. Only HQP commands are set to accessible.

    Use case ends.

Extensions

  • 3a. User enters invalid password.

    • 3a1. System displays an error message and allows one less attempt for User at entering a correct password, with a maximum of 5 attempts.

      Use case resumes at step 1.

  • 3b. The number of attempts reaches zero.

    • 3b1. System shuts down.

      Use case ends.

Use case: Enter Police Officer password

MSS

  1. User opens System.

  2. System prompts User to enter his password.

  3. User enters Police Officer password.

  4. Only Police Officer commands are set to accessible, System displays message "Welcome Police Officer" and System prompts User for a command.

    Use case ends.

Extensions

  • 3a. User enters invalid password.

    • 3a1. System displays an error message and allows one less attempt for User at entering a correct password, with a maximum of 5 attempts.

      Use case resumes at step 1.

  • 3b. The number of attempts reaches zero.

    • 3b1. System shuts down.

      Use case ends.

Use case: Logout

MSS

  1. User logs out of the System at any point.

  2. System sets all commands to inaccessible, displays System logout message and prompts User for password.

Use case ends.

Use case: Update any password

MSS

  1. User requests to update password.

  2. System prompts User for current password to change.

  3. User enters existing password.

  4. System prompts User to enter new password.

  5. User enters new alphanumeric password.

  6. System prompts User to enter new password again.

  7. User enters same new alphanumeric password.

  8. System updates password to change to the new alphanumeric password and displays update password success message.

    Use case ends.

Extensions

  • 3a. User enters invalid password.

    • 3a1. System displays an error message and allows one less attempt for User at entering a correct password, with a a maximum of 5 attempts.

      Use case resumes at step 2.

  • 3b. The number of attempts reaches zero.

    • 3b1. System shuts down.

      Use case ends.

  • 5a or 7a. User enters new password without a number.

  • 5a1 or 7a1. System shows error message to include at least one number and prompts User to enter new alphanumeric password again.

    Use case resumes at step 5.

  • 5b or 7b. User enters new password without a letter.

  • 5b1 or 7b1. System shows error message to include at least one letter and prompts User to enter new alphanumeric password again.

    Use case resumes at step 5.

  • 5c or 7c. User enters new password without a letter nor a number.

  • 5c1 or 7c1. System shows error message for invalid new password.

    Use case resumes at step 5.

Use case: Add person

MSS

  1. User opens System.

  2. System prompts User to enter his password.

  3. User enters password.

  4. System prompts user to enter his command.

  5. User requests to add person to the list.

  6. System adds person to the list and informs User that person has been successfully added.

    Use case ends.

Extensions

  • 6a. Person already exists in the list.

    • 6a1. System shows an error message.

      Use case ends.

  • 6b. User enters person’s details with invalid formats.

    • 6b1. System shows an error message.

      Use case resumes at step 5.

  • *a. At any time, User cancels add action.

    • *a1. System requests for confirmation to cancel.

    • *a2. User confirms cancellation.

      Use case ends.

Use case: Delete person

MSS

  1. User opens System.

  2. System prompts user to enter his password.

  3. User enters password.

  4. System prompts user to enter his command.

  5. User keys in NRIC of person to delete

  6. System deletes the person.

  7. User requests to list persons.

  8. System shows a list of persons.

  9. User requests to delete a specific person in the list.

  10. System deletes the person.

    Use case ends.

Extensions

  • 3a. User enters an invalid password.

    • 3a1. System shows an error message.

      Use case resumes at step 1.

  • 5a. User enters invalid NRIC.

    • 5a1. System shows an error message.

      Use case resumes at step 5.

  • *a. At any time, User chooses to cancel the delete action.

    • *a1. System requests confirmation to cancel.

    • *a2. User confirms the cancellation.

      Use case ends.

Use case: Edit person

MSS

  1. User opens System.

  2. System prompts user to enter his password.

  3. User enters password.

  4. System prompts user to enter his command.

  5. User keys in edit command with NRIC and new details of person to change

  6. System edits the person’s respective details.

    Use case ends.

Extensions

  • 5a. User enters invalid NRIC format

    • 5a1. System shows an error message stating that NRIC has a certain alphanumeric format.

      Use case resumes at step 4.

  • 5b. User enters NRIC of a person that does not exist in the police records

    • 5b1. System shows an error message stating that person could not be found.

      Use case resumes at step 4.

  • 5c. User enters edit command with only NRIC tag without other details to change.

    • 5c1. System shows an error message stating that format is invalid

      Use case resumes at step 4.

  • 8a. User enters person’s details with invalid format.

    • 8a1. System shows an error message suggesting the correct usage of the command.

      Use case resumes at step 4.

Use case: Find person

MSS

  1. User boots System.

  2. System prompts user to enter his password.

  3. User enters password.

  4. System prompts user to enter his command.

  5. User requests to find person

  6. System prompts User to key in NRIC to find

  7. User enters NRIC of person

  8. System displays details of person, if found on the list.

    Use case ends.

Extensions

  • 3a. User enters an invalid password.

    • 3a1. System shows an error message.

      Use case resumes at step 2.

  • 7a. User enters an NRIC that does not exist in the list.

    • 7a1. System informs User that person is not in the list.

      Use case ends.

  • 7b. User enters person’s NRIC with invalid format.

    • 7b1. System shows an error message.

      Use case resumes at step 6.

  • 8a. The list of persons is empty.

    • 8a1. System shows an error message.

      Use case ends.

Use case: Check person

MSS

  1. User opens System.

  2. System prompts user to enter his password.

  3. User enters password.

  4. System prompts user to enter his command.

  5. User requests to check person’s screening history.

  6. System prompts User to key in NRIC to check.

  7. User enters NRIC of person.

  8. System displays past screening timestamps of person, if found on the list.

    Use case ends.

Extensions

  • 3a. User enters an invalid password.

    • 3a1. System shows an error message.

      Use case resumes at step 2.

  • 5a. The list is empty.

    • 5a1. System shows an error message.

      Use case ends.

  • 6a. User enters person’s details with invalid format.

    • 6a1. System shows an error message.

      Use case resumes at step 6.

  • 6b. User enters an NRIC that does not exist in the list.

    • 6b1. System informs User that person is not in the list.

      Use case ends.

  • 6c. User enters the an NRIC with invalid format.

    • 6c1. System shows an error message.

      Use case ends.

Use case: Update status of a PO

MSS

  1. User opens System.

  2. System prompts user to enter his password.

  3. User enters password.

  4. System prompts user to enter his command.

  5. User requests to update the engagement status of a PO (e.g "po1") to free

  6. System prompts User to specify the PO

  7. User enters the PO

  8. System shows the user that the PO’s status has been updated

    Use case ends.

Extensions

  • 3a. User enters an invalid password.

    • 3a1. System shows an error message.

      Use case ends.

  • 5a. User enters Command in an invalid format.

    • 5a1. System shows an error message

      Use case ends.

  • 7a. User enters an invalid PO ID or a PO that does not exist.

    • 7a1. System shows an error message

      Use case ends.

Use case: Check status of all POs

MSS

  1. User opens System.

  2. System prompts user to enter his password.

  3. User enters password.

  4. System prompts user to enter his command.

  5. User requests to see all POs and their current engagement status

  6. System shows the user a list of POs and each of their engagement status

    Use case ends.

Extensions

  • 3a. User enters an invalid password.

    • 3a1. System shows an error message.

      Use case ends.

  • 5a. User enters Command in an invalid format.

    • 5a1. System shows an error message

      Use case ends.

Use case: Autocorrection of commands

MSS

  1. User opens System.

  2. System prompts user to enter his password.

  3. User enters password.

  4. System prompts user to enter his command.

  5. User enters invalid command.

  6. System predicts what command the user would have wanted to type if it finds a correction and displays the valid implementation of the command.

    Use case ends.

Extensions

  • 3a. User enters an invalid password.

    • 3a1. System shows an error message.

      Use case resumes at step 2.

  • 6a. User enters an invalid command for which the system cannot find a prediction.

    • 6a1. System shows error message.

      Use case ends.

Use case: Autocorrection of NRICs

MSS

  1. User opens System.

  2. System prompts user to enter his password.

  3. User enters password.

  4. System prompts user to enter his command.

  5. User enters delete, edit or check command with invalid NRIC.

  6. System predicts the NRIC the user would have wanted to type if it finds a correction and displays the valid implementation of the command.

    Use case ends.

Extensions

  • 3a. User enters an invalid password.

    • 3a1. System shows an error message.

      Use case resumes at step 2.

  • 5a. User enters an invalid delete, edit or check command.

    • 5a1. System displays the valid usage of the command.

      Use case ends.

  • 6a. User enters an invalid NRIC for which the system cannot find a prediction.

    • 6a1. System shows error message.

      Use case ends.

Use case: Show unread messages

MSS

  1. User opens System.

  2. System prompts user to enter his password.

  3. User enters password.

  4. System prompts user to enter his command.

  5. User requests to display unread messages in inbox.

  6. System prints the number of unread messages and list of unread messages.

    Use case ends.

Extensions

  • 5a. There are no messages.

    • 5a1. System informs user that there are no messages available.

      Use case ends.

  • 5b. There are no unread messages.

    • 5b1. System informs user that there are no unread messages.

      Use case ends.

  • 5c. File containing user’s inbox messages is missing.

    • 5c1. System informs user that there was an error loading messages.

      Use case ends.

Use case: Show all messages

MSS

  1. User opens System.

  2. System prompts user to enter his password.

  3. User enters password.

  4. System prompts user to enter his command.

  5. User requests to display all messages in inbox.

  6. System prints the total number of messages, number of unread messages and full list of messages.

    Use case ends.

Extensions

  • 5a. There are no messages.

    • 5a1. System informs user that there are no messages available.

      Use case ends.

  • 5b. There are no unread messages.

    • 5b1. System informs user of his total number of messages, that there are 0 unread messages and the full list of messages.

      Use case ends.

Use case: Clear Inbox

MSS

  1. User opens System.

  2. System prompts user to enter his password.

  3. User enters password.

  4. System prompts user to enter his command.

  5. User enters command to clear his inbox.

  6. System informs user that his inbox has been cleared.

    Use case ends.

Extensions

  • 5a. There are no messages.

    • 5a1. System informs user that inbox has been cleared.

      Use case ends.

  • 6a. File storing user’s inbox messages cannot be found.

    • 6a1. System informs user that inbox clearance has been unsuccessful and that the storage file is missing.

      Use case ends.

Use case: Read messages

MSS

  1. User opens System.

  2. System prompts user to enter his password.

  3. User enters password.

  4. System prompts user to enter his command.

  5. User enters command to Show Unread Messages

  6. System finds the text file storing user’s messages and displays a numbered list of messages that are unread.

  7. User enters the message number he wishes to mark as read.

  8. System updates message read status to 'read'.

    Use case ends.

Extensions

  • 7a. User enters an invalid index.

    • 7a1. System shows an error message and informs user of the valid index range.

      Use case ends.

  • 7b. User enters an extremely large number for the index.

    • 7b1. System informs user that the index entered is too large.

  • 7c. There are no unread messages.

    • 7c1. System informs user that there are no unread messages.

      Use case ends.

  • *a. At anytime, user chooses to stop marking messages as read.

    Use case ends.

Use Case: Request Backup

MSS

  1. User opens System.

  2. System prompts User to enter his password.

  3. User enters his password.

  4. System prompts User to key in command.

  5. User types in to request backup with pre-defined case types.

  6. System adds message into Headquarters inbox.

  7. User will be notified with success message.

    Use case ends.

Extensions

  • 3a. User enters an invalid password.

    • 3a1. System shows an error message.

      Use case resumes in step 2.

  • 5a. User enters an invalid input with invalid command format.

    • 5a1. System shows error message and prompts correct format for request feature.

      Use case resumes from step 4.

  • 5b. User enters an invalid case type.

    • 5b1. System shows an error message and prompts user with list of offences.

      Use case resumes at step 4.

Use Case: Dispatch Backup

MSS

  1. User opens System.

  2. System prompts User to enter his password.

  3. User enters his password.

  4. System prompts User to key in command.

  5. User keys in backup officer to assist requester with case type.

  6. System adds new message with ETA & location of backup officer and case type in requester inbox.

  7. System adds new message with ETA & location of requester and case type in backup officer inbox.

    Use case ends.

Extensions

  • 0a. User keys in invalid command format.

    • 0a1. System shows error message and prompts correct format for dispatch feature.

      Use case resumes from step 4.

  • 3a. The entered password is invalid.

    • 3a1. System shows an error message.

      Use case resumes in step 2.

  • 5a. User is not a Headquarter Personnel.

    • 5a1. System shows an error message stating invalid credentials.

      Use case resumes in step 4.

  • 7a. User enters an engaged police officer as backup.

    • 7a1. System shows an error message stating that the police officer entered is engaged.

      Use case resumes in step 4.

  • 7b. User enters an invalid case type.

    • 7b1. System shows an error message and prompts user with list of offences.

      Use case resumes at step 4.

Appendix C: Non Functional Requirements

  1. Should work on any mainstream OS as long as it has Java 9 or higher installed.

  2. Should be able to hold up to 1000 persons.

  3. Should come with automated unit tests and open source code.

  4. Should favor DOS style commands over Unix-style commands.

  5. Business/domain rules:

    1. Device should accept any more input after 9 characters when PO is inputting NRIC

    2. Device will constantly remind PO to charge if battery level goes below a certain level.

  6. Accessibility: Different levels of access for POs and HQPs and drivers (ambulance,fire truck).

  7. Performance requirements: The system should respond within two seconds.

  8. Security requirements: The system should be password locked.

  9. Data requirements:

    1. Data should persist, and not volatile.

    2. Data should be recoverable from last save point

Appendix D: Glossary

Headquarters Personnel (HQP)

A PO with a high level of authorised access (read and write) to the information of subjects.

ID

Refers to the identity of the user of the program based on the password he uses the log in. Currently, there can be 6 possible users - 1 HQP and 5 POs.

Mainstream OS

Windows, Linux, Unix, OS-X

NRIC

Stands for National Registration Identity Card. It is a 7-digit number preceded and succeeded by a letter. This forms a sequence of characters unique to each person and is used for identification purposes.

Police Officer (PO)

A police officer that is on patrol duty. Has low level of authorised access (read only) to subject’s information.

Police Records

Refers to the database of information that the system has of people, which includes their NRIC, name, address, past offences and status.

Status

A status that is used to describe the engagement level of POs on duty. He can either be engaged (true) or free (false). It is also used to describe a subject, should he have a criminal record: wanted, xc (ex-convict), and clear.

Subject

A person that is being screened by a PO.

System

Refers to the PRISM Application itself (i.e. when a user exits the system, he closes the application).