Test logging plugin used to retrieve more detailed test logs.
Referenced and modified use of java.utils.Optionals when retrieving CommandResult from an executed Command from
Team W17-2,
MainWindow.java
lines 191 - 194.
Refer to the guide Setting up and getting started.
The Architecture Diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main (consisting of classes Main
and MainApp)
is in charge of the app launch and shut down.
The bulk of the app's work is done by the following four components:
UI: The UI of the App.AnimalLogic: The command executor.AnimalModel: Holds the data of the App in memory.AnimalStorage: Reads data from, and writes data to, the hard disk.Commons represents a collection of classes used by multiple other components.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues
the command delete 1.
Each of the four main components (also shown in the diagram above),
interface with the same name as the Component.{Component Name}Manager class (which follows the corresponding API
interface mentioned in the previous point.For example, the AnimalLogic component defines its API in the AnimalLogic.java
interface and implements its functionality using the AnimalLogicManager.java
class which follows the AnimalLogic interface. Other components interact with a given component through its interface
rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a
component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
The API of this component is specified in Ui.java
The UI consists of a MainWindow that is made up of parts. Some core components include: CommandBox, ResultDisplay,
AnimalListPanel, AnimalDetailPanel, and AnimalCard, along with other components. All these, including the MainWindow,
inherit from the abstract UiPart class which captures the commonalities between classes that represent parts of the visible GUI.
The UI component uses the JavaFx UI framework. The layout of these UI parts are defined in matching .fxml files that are in the src/main/resources/view folder.
Generally, the UI consists of the command box for the user to input commands, a result display to give an output based on the command given, and a main animal display panel consisting of 2 parts:
AnimalListPanel which consists of a list of AnimalCard objectsAnimalDetailPanel which is a detailed view of Animal objects.The layout of the MainWindow is specified in MainWindow.fxml
The UI component does the following actions:
CommandBox class of the UI where
users can input a command.Model data so that the UI can be updated with the modified data. For example, when an animal
is deleted or added to the catalog, the UI is updated through the AnimalListPanel class, where the list that is
referenced is an Observable<Animal> list that is updated live.Logic component, because the UI relies on the Logic to execute commands.Model component, as it displays Animal object residing in the Model.API : AnimalLogic.java
Here's a (partial) class diagram of the AnimalLogic component:
The sequence diagram below illustrates the interactions within the AnimalLogic component, taking execute("delete 1") API call as an example.
Note: The lifeline for DeleteAnimalCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
How the AnimalLogic component works:
AnimalLogic is called upon to execute a command, it is passed to an AnimalCatalogParser object which in
turn creates a parser that matches the command (e.g., DeleteAnimalCommandParser) and uses it to parse the command.AnimalCommand object (more precisely, an object of one of its subclasses e.g., DeleteAnimalCommand) which is executed by the AnimalLogicManager.AnimalModel when it is executed (e.g. to delete a person).CommandResult object which is returned back from AnimalLogic.Here are the other classes in AnimalLogic (omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
AnimalCatalogParser class creates an XYZCommandParser (XYZ is a placeholder for the specific command name e.g., AddAnimalCommandParser) which uses the other classes shown above to parse the user command and create a XYZCommand object (e.g., AddAnimalCommand) which the AnimalCatalogParser returns back as a AnimalCommand object.XYZCommandParser classes (e.g., AddAnimalCommandParser, DeleteAnimalCommandParser, ...) inherit from the AnimalParser interface so that they can be treated similarly where possible e.g, during testing.API : AnimalModel.java
The AnimalModel component,
Animal objects (which are contained in a UniqueAnimalList object).Animal objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiable ObservableList<Animal> that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.AnimalUserPref object that represents the user’s preferences. This is exposed to the outside as a AnimalReadOnlyUserPref objects.AnimalModel represents data entities of the domain, they should make sense on their own without depending on other components)Note: An alternative (arguably, a more OOP) model is given below. It has a PetId list in the AnimalCatalog, which Animal can reference. This allows AnimalCatalog to only require PetId object, instead of each Animal needing their own PetId objects.
API : AnimalStorage.java
AnimalStorage and Storage are used synonymously.
The AnimalStorage component,
can save both animal catalog data and user preference data in JSON format, and read them back into corresponding objects.
inherits from both AnimalCatalogStorage and AnimalUserPrefStorage, which means it can be treated as either
one (if only the functionality of only one is needed). This also allows AnimalStorage to act as a unified facade that
exposes the relevant APIs for other classes to interact with the Storage.
depends on some classes in the Model component (because the Storage component's job is to save/retrieve objects
that belong to the Model). Specifically, it depends on the Animal model. To decrease the amount of coupling,
JsonAdaptedAnimal is used, which acts as an adapter for Animal to be serialized/deserialized by Jackson. As such, it
is important for developers to take extra caution when modifying Animal and its attributes, and update
JsonAdaptedAnimal accordingly.
Classes used by multiple components are in the commons package.
This section describes some noteworthy details on how certain features are implemented.
HelpAnimalCommand FeatureThe HelpAnimalCommand is a command designed to display useful help messages to the User, without having them refer to
the User Guide constantly, which could be a cumbersome and frustrating user experience.
Here's a brief outline of the HelpAnimalCommand's operations and attributes:
HelpAnimalCommandParser#parse - Parses the user input to create a HelpAnimalCommand that may or may not contain
an argument.HelpAnimalCommand#execute(AnimalModel model) Executes the command to display a help message to the User.Given below is an example usage scenario of the HelpAnimalCommand:
help command to find out how to use the App. The user can optionally include a known command's
name as argument, e.g. help add to find out how to use the AddAnimalCommand.CommandException is thrown. Otherwise, if the syntax is valid, the help command displays 1 of 2 possible outcomes:
The following activity diagram shows how the HelpAnimalCommand works:
Aspect: How the help is implemented
help command searches for the specified command in a CommandEnum class.
CommandEnum encapsulates the commands' name and help
message, rather than hard-coding and maintaining a Map of commandName: helpMessage. If the help message were
to be updated, developers only have to update the getHelp method in the respective commands, and it would
automatically be refllected by help.CommandEnum for help command to display the relevant help message.Command classes at run-time.
CommandEnum class for the help command to display the newly added command's help message.AddAnimalCommand FeatureThe AddAnimalCommand is a specific command designed to add an animal to the animal catalog. It identifies the animal to
be added with attributes such as its name, ID, sex, species, breed, age, date of birth and date of admission.
Here's a brief outline of its operations and attributes:
AddAnimalCommandParser#parse — Parses the user input to create an AddAnimalCommand with the various
attributes of the Animal to be added.AddAnimalCommand#execute(AnimalModel model) — Executes the command to add the specified animal to the model.Given below is an example usage scenario of the AddAnimalCommand:
add command with the proper CLI syntax, giving a compulsory input field for each attribute.
Note that the position of the cli syntax can be in any order.CommandException describing the error is thrown. Otherwise, it adds the animal with its
inputted attributes to the model and returns a successful command result.The following sequence diagrams shows how the AddAnimalCommand works:
In the logic component:
list, search and reset) have similar logic sequence diagrams, and hence only AddAnimalCommand will be explained in detail.
In the model component:
Aspect: How the addition is handled
DeleteAnimalCommand FeatureThe DeleteAnimalCommand is a specific command designed to remove an animal from the animal catalog. It identifies the animal to be deleted based on its displayed index in the animal list.
Here's a brief outline of its operations and attributes:
DeleteAnimalCommand#execute(AnimalModel model) — Executes the command to delete a specified animal.targetIndex — An attribute that holds the index of the animal to be deleted.Given below is an example usage scenario of the DeleteAnimalCommand:
find command.delete command, providing the index of the animal to be deleted. For instance, delete 3 would attempt to delete the third animal on the list.CommandException. Otherwise, it retrieves the animal corresponding to the index, removes it from the model, and returns a successful command result.AddAnimalCommand for the sequence diagrams of the logic and model components of DeleteAnimalCommand as they are largely similar.
Aspect: How the deletion is handled
EditAnimalCommand FeatureThe EditAnimalCommand is a specific command designed to edit the field(s) of a selected animal from the animal catalog. It identifies the animal to be edited based on its displayed index in the animal list.
EditAnimalCommandParser#parse(String args) — Parses the user input to create a EditAnimalCommand object with the given animal index.EditAnimalCommand#execute(AnimalModel model) — Executes the command to edit an animal's attribute(s) for an animal in the animal catalog.Given below is an example usage scenario of the EditAnimalCommand:
edit command with the animal index and the prefixes of the attribute to be edited. For instance, edit 1 n/Boo s/Cat will edit the first animal's name to "Boo" and the species to "Cat".CommandException. Otherwise, it proceeds to edit the attributes of the selected animal, and returns a successful command result.AddAnimalCommand for the sequence diagrams of the logic and model components of EditAnimalCommand as they are largely similar.
Aspect: Choices of attributes to edit
ID.
ID.ID when adding animal, user has to delete the entry and add again.ID can be edited, user does not have to delete the entry and add a new animal.ListAnimalCommand FeatureThe ListAnimalCommand is a command designed to list all animals in the animal catalog. It does not take in any arguments.
Here's a brief outline of its operations and attributes:
ListAnimalCommand#execute(AnimalModel model) — Executes the command to list all animals in the animal catalog.Given below is an example usage scenario of the ListAnimalCommand:
list command.The following sequence diagram shows how the ListAnimalCommand works:
In the logic component:
Aspect: How the listing is handled
SearchAnimalCommand FeatureThe SearchAnimalCommand is a command designed to search for animals in the animal catalog. It takes in at least one prefix as an argument.
Here's a brief outline of its operations and attributes:
SearchAnimalCommandParser#parse(String args) — Parses the user input to create a SearchAnimalCommand object with the given predicates based on the prefixes.SearchAnimalCommand#execute(AnimalModel model) — Executes the command to filter animals in the animal catalog based on the predicate.Given below is an example usage scenario of the SearchAnimalCommand:
search command with the prefixes of the attributes to be searched. For instance, search b/Poodle would search for animals of breed Poodle.CommandException. Otherwise, it retrieves the animals that match the valid prefixes, and returns a successful command result.ListAnimalCommand for the sequence diagrams of the model component of SearchAnimalCommand as they are largely similar, except for the predicate passed into updateFilteredAnimalList.
Aspect: How the search is handled
AddTaskCommand FeatureThe AddTaskCommand is a specific command designed to add a task to the task list of an animal. It identifies the animal to be selected based on its index in the current animal list.
Here's a brief outline of its operations and attributes:
AddTaskCommand#execute(AnimalModel model) — Executes the command to add a task to the task list of a specified animal.targetIndex — An attribute that holds the index of the specified animal.task — An attribute that holds the task that is to be added.Given below is an example usage scenario of the AddTaskCommand:
find command.addtask command, providing the index of the specified animal and a task description of "Feed dog". For instance, addtask 3 Feed dog will add the task with task description "Feed dog" to the third animal in the list.CommandException. Otherwise, it retrieves the animal corresponding to the index, adds the task to the task list of that animal, and returns a successful command result.The following sequence diagram shows how the AddTaskCommand works:
AddAnimalCommand for the sequence diagrams of the logic and model components of AddTaskCommand as they are largely similar.
Aspect: Multiplicity of tasks to be added and animals to be modified
addtask command multiple times to add multiple tasks.DeleteTaskCommand FeatureThe DeleteTaskCommand is a specific command designed to delete a task to the task list of an animal. It identifies the animal to be selected based on its index in the current animal list and the task to be deleted based on its index in the task list of the selected animal.
Here's a brief outline of its operations and attributes:
DeleteTaskCommand#execute(AnimalModel model) — Executes the command to delete a specified task of a specified animal.targetAnimalIndex — An attribute that holds the index of the specified animal.targetTaskIndex — An attribute that holds the index of the task to be deleted.Given below is an example usage scenario of the DeleteTaskCommand:
find command.deletetask command, providing the index of the specified animal and the index of the task to be deleted. For instance, deletetask 3 1 will delete the first task in the task list of the third animal in the displayed animal list.CommandException. Otherwise, it retrieves the animal corresponding to the animal index, deletes the task corresponding to the task index of the task list of that animal, and returns a successful command result.AddAnimalCommand for the sequence diagrams of the logic and model components of DeleteTaskCommand as they are largely similar.
Aspect: Multiplicity of tasks to be deleted and animals to be modified
deletetask command multiple times to delete multiple tasks.MarkTaskCommand and UnmarkTaskCommand FeatureThe MarkTaskCommand is a command designed to mark task(s) as done for an animal in the animal catalog.
The UnmarkTaskCommand is a command designed to mark task(s) as uncompleted for an animal in the animal catalog.
Both commands take in one animal index and at least one task index as arguments.
MarkTaskCommand and UnmarkTaskCommand have very similar implementations, hence only MarkTaskCommand will be explained in detail.
Here's a brief outline of its operations and attributes:
MarkTaskCommandParser#parse(String args) — Parses the user input to create a MarkTaskCommand object with the given animal index and task index(s).MarkTaskCommand#execute(AnimalModel model) — Executes the command to mark task(s) as done for an animal in the animal catalog.Given below is an example usage scenario of the MarkTaskCommand:
mark command with the animal index and task indexes. For instance, mark 1 2 3 would mark tasks 2 and 3 as done for the animal at index 1.CommandException. Otherwise, it retrieves the animal and tasks that match its respective indexes, marks it as done, and returns a successful command result.The following sequence diagrams shows how the MarkTaskCommand works:
In the logic component:
In the model component:
UnmarkTaskCommand works similarly to MarkTaskCommand, except that updateTask takes in false instead of true.
Aspect: How the marking is handled
ResetTaskCommand FeatureThe ResetTaskCommand is a command designed to reset all tasks as uncompleted for all animals in the animal catalog. It does not take in any arguments.
Here's a brief outline of its operations and attributes:
ResetTaskCommand#execute(AnimalModel model) — Executes the command to reset all tasks as uncompleted for all animals in the animal catalog.Given below is an example usage scenario of the ResetTaskCommand:
reset command.The following sequence diagram shows how the ResetTaskCommand works:
In the logic component:
In the model component:
Aspect: How the resetting is handled
Detailed View FeatureThe detailed view is a feature that shows the details of the animals not seen in the entries of the animal list. These include
Date of Birth(DOB), Date of Admission(DOA), Age, and Tasks that are added to the animal. The detailed view is handled by the AnimalDetailPanel class.
Here's a brief outline of its operations:
AnimalDetailPanel#updateDetails(Animal animal) — Updates the detail panel of the application with the input animal's details.AnimalDetailPanel is either updated by the user by clicking on an animal entry cell, or using animal-specific commands. The following activity diagram shows how the detailed view works:
For update of AnimalDetailPanel by clicking, this is handled in the AnimalListPanel class using a Listener. The Listener will listen to changes in selected cell, and update the animal details to show the selected animal.
For update of AnimalDetailPanel by animal-specific commands, animal-specific commands that automatically update the Detailed View with the targeted animal include add, edit, addtask,
deletetask, mark, and unmark. All other commands are considered non-animal-specific. For such animal-specific commands, the CommandResult will accept an additional argument Animal,
and this is retrieved by the AnimalDetailView in the MainWindow class. To differentiate between CommandResult that contains an Animal (animal-specific commands) and non-animal-specific commands, OptionalCommandResult class.
Aspect: How the detailed view is displayed
Target user profile: Volunteers at animal shelters.
Value proposition: Our application aims to provide a centralized platform to ensure efficient storage and access to critical details, enhancing the volunteer experience in animal shelters.
Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *
| Priority | As a... | I want to... | So that I can... |
|---|---|---|---|
*** | volunteer | view specific information about each pet. | understand their unique needs. |
*** | volunteer | be able to access a user manual. | easily learn how to navigate the app. |
*** | volunteer | view all animals in a single page. | - |
*** | volunteer | add new animal entries | - |
*** | volunteer | update existing animal profiles | - |
** | volunteer | add tasks to each animal | know each animal's needs. |
** | volunteer | mark tasks as done | keep track of which animal's needs has been taken care of. |
(For all use cases below, the System is the AnimalCatalog and the Actor is the user, unless specified
otherwise)
Use Case: UC01 - Help on Animal Commands
MSS:
Extensions:
Use Case: UC02 - Add Animal to Catalog
MSS:
Extensions:
Use Case: UC03 - Delete Animal from Catalog
MSS:
Extensions:
Use Case: UC04 - Edit Animal Details in Catalog
MSS:
Extensions:
Use Case: UC05 - List All Animals in Catalog
MSS:
Use Case: UC06 - Search for Animals in Catalog
MSS:
Extensions:
Use Case: UC07 - Add Task to Animal's Task List
MSS:
Extensions:
Use Case: UC08 - Delete Task from Animal's Task List
MSS:
Extensions:
Use Case: UC09 - Mark Task as Done in Animal's Task List
MSS:
Extensions:
Use Case: UC10 - Unmark Task as Uncompleted in Animal's Task List
MSS:
Extensions:
add, edit, addtask, deletetask, mark, unmark.Given below are instructions to test the app manually.
Note: These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.
Initial launch
Download the jar file and copy into an empty folder
Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
Saving window preferences
Resize the window to an optimum size. Move the window to a different location. Close the window.
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
Implement more detailed error messages for search command. The current error message for invalid inputs for the search command is not very accurate. It will be improved in the future by providing more accurate error messages. e.g. search nil/other will return an error message saying that the prefix provided is invalid, instead of saying that the search input is empty since it is not recognised.
Include INDEX numbers of tasks in the detailedView. Currently, tasks are listed in the detailedView without the INDEX. While usable, it can get inconvenient to figure out which INDEX a task is when the task list gets longer, as users have to manually count up/down. It will be improved by displaying the INDEX of the task beside each task, e.g
1. [ ] Task 1
2. [ ] Task 2
3. [X] Task 3
Add a view command, to view details of animals. Currently, to view the details of an animal, users have two approaches:
3.1. Click on an animal entry in the animal list to see the detailed view.
3.2. Most animal-specific commands that involve specifying an INDEX of animal will automatically show the details of the animal in the detailed view. Commands include: add, edit, addtask, deletetask, mark, unmark.
While intuitive, it was an oversight to not include a view animal command to make it more CLI-friendly. We plan on adding a view INDEX command in the future, where the detailed view will show the details of the animal at the specified INDEX of the view INDEX command.
Implement persistent search status. Currently, the search command filters the animals based on the tags passed in. If the user follows up with any command other than delete, the filtered list will reset to show all animals.
For example, search s/Dog will show all animals whose species is Dog. If user uses the following command (add, edit, addtask, deletetask, mark, unmark, reset) right after the search command, the list will reset and show all animals.
To implement the persistent search status, we plan to keep track of the last FilteredAnimalList and display the animals within the last FilteredAnimalList after the update.
Accommodate extreme length inputs for Animal name and Task description. Currently, when a user inputs an animal name and task description of extreme length, the text will be cut off in the UI. While it's highly unlikely to have such extreme length name and task description, it will still be good to include a horizontal scrollbar in the JavaFX AnimalDetailPanel component to accommodate such scenarios.
Implement more detailed error messages for add command. Currently, our AnimalCatalog prevents adding of identical animals, and this identity is tracked using the primary key ID of the animal. When a user tries to add an animal and specifies an ID that already exists in the AnimalCatalog, the error message states that This animal already exists in the Catalog. While performing as expected, it can be further enhanced with the animal ID, such as Animal with ID: 1111 already exists in the Catalog.
Allow for multiple task creations for single animal and creations of the same tasks for multiple animals. Currently, we only allow for one task creation for one animal per command. This can be implemented by allowing a user to specify if they are adding a single task to multiple animals with an additional single keyword or multiple tasks to a single animal with an additional multiple keyword.
Our groups faced challenges and required to put great effort for this project. These included:
PetId, AdmissionDate, DateOfBirth, Sex, Task, and many more to fit the target audience. These meant a lot more test cases and error handling for all inputs for these classes.