Overview
Incident Management System is a desktop incident Manager application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
Summary of contributions
-
Major enhancement: Implemented Incident Search and Listing
-
What it does: allows the user to list a filtered or unfiltered list of incidents dependent on commands and parameters used.
-
Justification: This feature improves the product significantly because a user can handle large sets of data efficiently through searching for relevant incident reports based on the parameters, to prepare these incidents for filling and submission, or for reviewing.
-
Highlights: This enhancement is easily extendable to various data within the Incident model, and has been designed to easily accommodate additional parameters. It required an in-depth analysis of design alternatives, as the implementation was challenging, requiring a good understanding of how to parse multiple parameters with multiple words for each parameter, and consideration of the abstraction of said parameters.
-
Credits: Extended from the FindPerson command in the initial AB3
-
-
Major enhancement: Implemented initial Incident GUI layout [#59]
-
Summary: Modified the GUI for a new panel for displaying Incidents and the relevant information in the initial implementation.
-
Highlights: This enhancement required an in-depth understanding of the GUI design and the JavaFX library, as well as great familiarity with the initial Incident class. Further abstraction of the Incident class was also executed to ensure SLAP principlese were adhered to.
-
-
Code contributed: [View on RepoSense]
-
Other contributions:
Contributions to the User Guide
Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users. |
Listing all incidents: list-i
Shows a list of all incidents in the Incident Manager
Format: list-i
Example usage of the list-i
command returning all incidents within the system:
image::listIncidentsCommand.png[width="500"]
-
The listing returns all incidents, inclusive of all incomplete drafts and complete drafts and submitted incident reports
-
Adding any keywords or parameters will result in an error. Only
list-i
is allowed.
Locating an incident report using incident ID, operator name or description keyword: find-i
Finds incidents containing the relevant specified parameters.
Possible Parameters: id/
, op/
, desc/
, self
Different Parameters
By Operator Name
Format: find-i op/<OPERATOR KEYWORD [MORE_KEYWORDS]>
Lists all incidents whereby the operator name contains any of the given keywords
-
Accepts multiple search terms for the parameter, searching for any match with any search term
-
Example of the
find-i
command with one word under parameterop/
, returning all incidents whereby the operator name matchesalex
(case-insensitive):
-
Example of the
find-i
command with multiple words under parameterop/
, returning all incidents whereby the operator name matchesirfan
orbernice
(case-insensitive):
By Description
Format: find-i desc/<DESCRIPTION KEYWORD [MORE_KEYWORDS]…>
Lists all incidents whereby the incident description contains any the given keywords
-
Example of the
find-i
command with parameterdesc/
, returning all incidents whereby the description contains either keywordfire
orarson
:
By ID
Format: find-i id/KEYWORD
Lists all incidents whereby the incident ID is an exact match with the given keyword
-
Requires an exact ID match, only accepts one ID
-
Example of
find-i
command with parameterid/
returning all incidents whereby the ID matches0620150001
exactly:
Self-Search
Format: find-i self
Lists all incidents whereby the operator name matches the logged-in user’s name.
-
Example of executing
find-i self
to list all incidents:
-
Requires an exact name match with the logged-in user’s name
Examples:
-
ID Match:
find-i id/0920160001
Returns Incident #0920160001 -
Multiple Parameters:
find-i op/Dave desc/fire
Returns any incidents whereby the operator’s name contains 'Dave' and the description contains 'fire' -
Multi-word Parameter Search:
find-i op/Alex Bernice
Returns any incidents whereby the operator’s name contains either 'Alex' or 'Bernice' -
Self-Search:
find-i self
Returns any incidents whereby the operator’s name matches the logged-in operator’s name
If multiple keywords of the same prefix are provided by user, the command will take the last valid parameter of each prefix. For example find-i desc/arson desc/fire op/alex op/charlotte is equivalent to find-i desc/fire op/charlotte .Rationale: user need not waste time backspacing if an input was keyed in wrongly. |
Future Extensions
-
Find Command filters search results by the following:
-
Incident status
-
DateTime
-
District number of Incident
-
Vehicle Type of Vehicle involved
-
Vehicle Number of Vehicle involved
-
Contributions to the Developer Guide
Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project. |
Incident Finding and Listing feature
Implementation
The incident search mechanism features a set of different types of searches that a user could utilise to list out all related incidents, regardless of status of report. Further documentation on the commands available in this set can be found in the User Guide. It is facilitated by the List Incidents Command and the Find Incidents Command. To differentiate the reports by statuses, the Incident Filling and Submission feature cover these capabilities already, as mentioned earlier.
Overview of Running Find Incidents and List Incidents commands
-
Listing all - Displays all incidents in
Model
, taking in no parameters
eg.list-i
-
Finding based on parameters- Displays all incidents in
Model
based on matching parameters indicated-
ID - Displays all incidents with exact matches in
IncidentId incidentId
inIncident incident
, withinModel
eg.find-i id/0620150001
-
Description - Displays all incidents with keyword(s) contained within the
Description description
inIncident incident
, withinModel
+ eg.find-i desc/traffic
-
Operator - Displays all incidents with keyword(s) contained within the name of the
Person operator
inIncident incident
, withinModel
eg.find-i op/bill
-
Operator - Displays all incidents with the name of the
Person operator
inIncident incident
matching the logged-in user’s name exactly, withinModel
eg.find-i self
-
Activity Diagram for illustration:
Overview of Implementation of Find Incidents and List Incidents commands
-
The incident search mechanism is facilitated by
ModelManager
, which implements abstract classModel
. -
ModelManager
contains aFilteredList<Incidents> filteredIncidents
, which internally stores the list of displayed incidents in the GUI. -
filteredIncidents
implements the following key methods utilised in the List Incidents and Find Incidents command:-
updateFilteredIncidentsList(Predicate<Incident> predicate)
- Updates the stored filtered incidents list with the new predicate -
getFilteredIncidentsList()
- Returns full list of all incidents
-
Implementation of List Incidents Command
The following sequence diagram shows how the list-i
command works when list-i
is called:
list-i
-
The
LogicManager
passes the command toIncidentManagerParser
when running commandexecute("list-i")
, which instantiates aListIncidentsCommand
withPredicate<Incident> PREDICATE_SHOW_ALL_INCIDENTS
that returns all incidents regardless of state. -
The
LogicManager
then callsListIncidentsCommand#execute()
, which runsListIncidentsCommand#handleAllIncidents()
, a private method withinListIncidentsCommand
. -
handleAllIncidents()
runsModel#updateFilteredIncidentList()
withPredicate<Incident> PREDICATE_SHOW_ALL_INCIDENTS
, which always evaluates to true. -
This
Predicate<Incident>
is passed toFilteredList<Incident> filteredList
, as a parameter to run the methodfilteredList#setPredicate()
. -
The list of visible incidents is updated.
-
CommandResult commandResult
is returned to theLogicManager
to log the success/failure of the method.
Implementation of Find Incidents Command
Next, we will look at an example in which the user calls find-i
to look for incidents written by an operator whose name contains Alex
.
The execution of this method is a little more complex. The following sequence diagram shows how the find-i
command identifies the keyword and flag, and returns related incidents:
find-i op/alex desc/pmd
The key steps are as follows:
-
IncidentManagerParser
passes the arguments toFindIncidentsCommandParser
to parse the keywords after the prefixesdesc/
andop/
in the command. -
FindIncidentsCommandParser
utilisesParserUtil
to parse out the keywords, in this case "pmd" for the description prefix and "alex" for the operator name prefix -
FindIncidentsCommandParser
creates a new instance ofDescriptionKeywordsPredicate
to be added toList<Predicate<Incident>> predicateArr
-
It does the same for
NameKeywordsPredicate
and any other valid search parameters identified -
A new instance of
FindIncidentsCommand
is passed the newList<Predicate<Incident>> predicateArr
, combining the predicates usingcombinePredicates()
to account for all predicates in theList
-
As before, the
LogicManager
callsFindIncidentsCommand#execute()
, which causes the Model to runModel#updateFilteredIncidentList(predicate)
using the combined predicate stored inFindIncidentsCommand
. -
This filters and updates the list in
FilteredList<Incident> filteredList
, by runningfilteredList#setPredicate(predicate)
with the passed combined predicate. -
Upon updating the list similar to the List Command above,
FindIncidentsCommand
also callsModel#getFilteredIncidentList()
to returnObservableList<Incident>
. It obtains the size of this list, and returns it inCommandResult commandResult
.
Design Considerations
Aspect: How multiple keywords with the same prefixes are processed
-
Current choice: Keywords are read as an array into
Predicate<Incident>
to be fed into a stream to search for any match with any of the keywords-
Pros: Requires lesser code. Abstraction of checking matches in keywords remains within the
Predicate<Incident>
class
Able to separate the handling of multiple keywords with the same prefixes, inPredicate<Incident>
, with the handling of different prefixes, done inFindIncidentsCommand
-
Cons: More difficult to implement
-
-
Alternative: Every new predicate takes in a keyword and returns all results with exact matches, to be combined in
FindIncidentsCommand
as separate predicates-
Pros: Easier to implement
-
Cons: May lead to confusing implementation of the
combinePredicates()
function for returning results which have all prefixes fulfilled, but only require at least one match in keywords fulfilled for each prefix
-
Aspect: How multiple different prefixes are processed
-
Current choice:
FindIncidentsCommandParser
checks for the presence of every possible prefix and creates a newPredicate<Incident>
to be added topredicateArr
to be combined inFindCommandParser
-
Pros: Intuitive to use, majorly improves the Find Incidents Command
Utilises Inheritance and Polymorphism principles from OOP to combine theDescriptionKeywordsPredicate
andNameKeywordsPredicate
andIdKeywordsPredicate
, inherited fromPredicate<Incident>
class, all stored inpredicateArr
-
Cons: Challenging to implement.
-
-
Alternative:
FindIncidentsCommandParser
returns a newFindCommand
for every prefix identified-
Pros: Less complicated
-
Cons: More code needed
Does not follow theCommand
interface abstracted from, in that multipleFindCommands
will runexecute()
at each time, returning multipleCommandResults
-
-
Alternative: Do not allow multiple different prefixes to be processed
-
Pros: Easy to implement, less challenging.
-
Cons: Very limited capabilities of Find Incidents Command if multiple parameters cannot be accepted at once.
-
Aspect: How predicate is added to FindIncidentsCommand
-
Current choice:
FindIncidentsCommand
class callsModel
to create a new Predicate based on search string.-
Pros: Abstracts the creation and management of predicates to the
Model
. Maintains Separation of Concerns principle. -
Cons: Requires greater level of coupling between classes.
-
-
Alternative:
FindIncidentsCommand
orFindIncidentsCommand
directly create Predicate based on search string.-
Pros: Less dependencies within the parser class.
-
Cons: Breaks Model-View-Controller pattern.
-
Aspect: How user keys in find-i
keywords
-
Current choice: Parse user input after flag (eg.
op\
ordesc\
)-
Pros: Easy to implement.
-
Cons: Have to parse keyword from command and flag, user has to follow style of flag for successful search.
-
-
Alternative: Prompt user for search input
-
Pros: Separates command from keyword for ease of reading and parsing.
-
Cons: Difficult to implement multi-command execution.
-
Aspect: How listing all incidents is called
-
Current choice: Utilise separate command
list-i
-
Pros: Intuitive to use.
-
Cons: Similar code under different command, leading to code reuse.
-
-
Alternative: Utilise
find-i
command (eg.find-i unfiltered
)-
Pros: Less overlap in code.
-
Cons: Unintuitive to the user as no search is being made, even more keywords to remember.
-
Aspect: Whether the search only returns full word matches
-
Current choice: Search only returns full word matches
-
Pros: Intuitive to use.
-
Cons: Unable to return similar words eg. search for "desc/fire" does not return description containing "fires"
-
-
Alternative: Search returns all keyword-containing matches
-
Pros: Able to account for similar words to be returned.
-
Cons: Unintuitive to return certain longer words from certain searches eg. "desc/the" returns descriptions containing "weather"
Faster search as code is less inefficient
-