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-iis 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-icommand with one word under parameterop/, returning all incidents whereby the operator name matchesalex(case-insensitive):
-
Example of the
find-icommand with multiple words under parameterop/, returning all incidents whereby the operator name matchesirfanorbernice(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-icommand with parameterdesc/, returning all incidents whereby the description contains either keywordfireorarson:
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-icommand with parameterid/returning all incidents whereby the ID matches0620150001exactly:
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 selfto 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
Modelbased on matching parameters indicated-
ID - Displays all incidents with exact matches in
IncidentId incidentIdinIncident incident, withinModel
eg.find-i id/0620150001 -
Description - Displays all incidents with keyword(s) contained within the
Description descriptioninIncident incident, withinModel+ eg.find-i desc/traffic -
Operator - Displays all incidents with keyword(s) contained within the name of the
Person operatorinIncident incident, withinModel
eg.find-i op/bill -
Operator - Displays all incidents with the name of the
Person operatorinIncident incidentmatching 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. -
ModelManagercontains aFilteredList<Incidents> filteredIncidents, which internally stores the list of displayed incidents in the GUI. -
filteredIncidentsimplements 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
LogicManagerpasses the command toIncidentManagerParserwhen running commandexecute("list-i"), which instantiates aListIncidentsCommandwithPredicate<Incident> PREDICATE_SHOW_ALL_INCIDENTSthat returns all incidents regardless of state. -
The
LogicManagerthen 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 commandResultis returned to theLogicManagerto 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/pmdThe key steps are as follows:
-
IncidentManagerParserpasses the arguments toFindIncidentsCommandParserto parse the keywords after the prefixesdesc/andop/in the command. -
FindIncidentsCommandParserutilisesParserUtilto parse out the keywords, in this case "pmd" for the description prefix and "alex" for the operator name prefix -
FindIncidentsCommandParsercreates a new instance ofDescriptionKeywordsPredicateto be added toList<Predicate<Incident>> predicateArr -
It does the same for
NameKeywordsPredicateand any other valid search parameters identified -
A new instance of
FindIncidentsCommandis passed the newList<Predicate<Incident>> predicateArr, combining the predicates usingcombinePredicates()to account for all predicates in theList -
As before, the
LogicManagercallsFindIncidentsCommand#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,
FindIncidentsCommandalso 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
FindIncidentsCommandas 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:
FindIncidentsCommandParserchecks for the presence of every possible prefix and creates a newPredicate<Incident>to be added topredicateArrto be combined inFindCommandParser-
Pros: Intuitive to use, majorly improves the Find Incidents Command
Utilises Inheritance and Polymorphism principles from OOP to combine theDescriptionKeywordsPredicateandNameKeywordsPredicateandIdKeywordsPredicate, inherited fromPredicate<Incident>class, all stored inpredicateArr -
Cons: Challenging to implement.
-
-
Alternative:
FindIncidentsCommandParserreturns a newFindCommandfor every prefix identified-
Pros: Less complicated
-
Cons: More code needed
Does not follow theCommandinterface abstracted from, in that multipleFindCommandswill 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:
FindIncidentsCommandclass callsModelto 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:
FindIncidentsCommandorFindIncidentsCommanddirectly 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-icommand (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
-