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
ExchangeCourseMapper
class (referred to as Main
in diagram) is responsible for 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.
Parser
: The command executor and logic checker.
Command
: Details and implementation of various commands/features of the app.
Storage
: Reads data from, and writes data to, mylist.json
.
How the architecture components interact with each other
Only some of the commands will need all 4 main components for example the Delete course command:
The Sequence Diagram below shows how the components interact with each other for the scenario
where the user issues the command delete 1
.
The UI
, Parser
and Storage
components (also shown in the diagram above),
The Command
component,
abstract
class with the same name as the Component.CheckInformationCommand
and PersonalTrackerCommand
as child classesFor example, the Command
component defines its API in the Command.java
abstract class and extends its functionality using the
PersonalTrackerCommand.java
and CheckInformationCommand
class. Other components such as ListSchoolsCommand
and DeleteCoursesCommand
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 the components and any additional components.
The abstract command classes for our two main features, CheckInformationCommand
and PersonalTrackerCommand
.
must inherit from the abstract Command
class, which has the method to read the Json file containing course
information. Each child class has the abstract execute
method, to be implemented by their concrete child classes,
specific to the command functionality.
Addition of new command features
When adding new command classes, developers should make sure that the concrete class inherits from either the
CheckInformationCommand
or PersonalTrackerCommand
classes, depending on the new command’s functionality.
The new command class should also have an implementation of the execute
method, and uses the UI
class to
print messages on the CLI interface.
CheckInformationCommands
list out information from the JSON file containing course mapping information, or from the
user’s Personal Tracker.
Possible CheckInformationCommands
are:
ListCommandsCommand
HelpCommand
ListSchoolsCommand
ListUniCoursesCommand
ObtainContactsCommand
FilterCoursesCommand
ListPersonalTrackerCommand
CompareMappedCommand
The above list of Command classes are concrete classes, and must implement the abstract
execute(userInput)
method.
PersonalTrackerCommands
are commands that can modify the user’s saved mapping plans from the Personal Tracker,
as well as access the list of saved mappings.
Possible CheckInformationCommands
are:
AddCoursesCommand
DeleteCoursesCommand
FindCoursesCommand
The above list of Command classes are concrete classes, and must implement the abstract
execute(userInput, storage)
method.
The Parser class is responsible for handling and interpreting user input in the application. It reads user commands, processes them by splitting the input into command keywords and parameters, and then directs the flow of control to the appropriate command classes to execute the specified actions.
As ExchangeCourseMapper
is mainly split into two main parts; Check Information and Personal Tracker. We decided to
split the Parser
class diagram into the two parts respectively to increase readability and neatness.
This class diagram represents the parsing of commands in Check Information. The multiplicities dependencies of the command are 0 or 1 because the dependency is only formed when the command is called, else, it will be zero.
This class diagram represents the parsing of commands in Personal Tracker. The Parser
class has associations with the
UI
class and Storage
class and dependencies with the commands in Personal Tracker.
Storage System Overview
The storage system is structured to manage the persistence and integrity of course data for the application. It consists of the following key components:
Storage Class: The main interface for adding, deleting, retrieving, and loading courses. It interacts with
CourseRepository
for data persistence, ensuring all course-related actions are directed to the appropriate storage
location.
CourseRepository: Acts as an intermediary layer, managing data access and defining the file path
(MYLIST_FILE_PATH
) for myList.json
. It provides similar methods as Storage
to add, delete, and retrieve course
data, facilitating structured data storage.
FileHandler: Responsible for file operations such as initializing, reading, writing, and appending to files. This class abstracts file manipulation, ensuring the storage system can perform reliable file operations without directly managing file-specific details.
DataIntegrityChecker: Ensures the integrity of the stored data by validating file structure and content. It provides methods for validating the entire file or individual lines, helping maintain consistent data formatting and correctness.
CourseValidator: Validates course inputs to check if they meet predefined criteria before being stored. This ensures that only valid data is added to the repository, reducing the likelihood of errors in the data storage.
UI: Responsible for providing feedback to the user regarding any invalid entries or formats, enhancing user experience by notifying them of issues in a clear and informative way.
Each component is designed to separate concerns, with Storage
focusing on high-level operations, CourseRepository
on data organization, FileHandler
on file I/O, and DataIntegrityChecker
on data validation. This modular design
allows for maintainability, testability, and scalability in managing persistent course data.
For commands that read through our data source file which contains university data, the process will be done in the
Command
class via a createJsonObject()
method,
where an IOException
message will be displayed if reading fails.
The ListCommandsCommand
provides users with a comprehensive list of all available commands in the CLI. This is particularly useful for new users or those unfamiliar with specific command formats.
ListCommandsCommand
class extends the CheckInformationCommand
superclass and overrides the execute
method.execute
method, printCommandList
from the UI class is called.LINE_SEPARATOR
is used before and after the list to create a visually distinct section in the CLI.ListCommandsCommand
with the HelpCommand
to provide a one-stop command for help-related requests, but separating them ensures clarity and keeps each command focused.This command provides users with detailed explanations of each feature and the ways to use them. This allows users to navigate this program easily and effectively.
HelpCommand
class extends the CheckInformationCommand
class where it overrides
the execute method for custom behaviour.getCommand()
method which extracts and processes the
command. It does so by using switch
statements to determine if the input matches one of the valid commands.IllegalArgumentException
exception will be thrown to handle
invalid commandsprintHelp()
method will be called to display the detailed help messages for the specific command.
Another switch
statement is used here to map each command to its corresponding help message.getCommand()
parses and
validates the input to extract a specific command and printHelp()
prints the relevant help message for the
parsed command.switch
statement is an efficient way to match valid commands.
switch
statements are also clearer and easier to read.if-else
statement
switch
statementsThis command is responsible for displaying and retrieving the full list of universities from our data source file which contains university data. It helps the users to identify the possible choices in Oceania.
ListSchoolCommand
class extends the CheckInformationCommand
class where it overrides the execute
method for
custom behaviour.fetchSchoolData()
method from a JSON file to obtain the names via
createJsonObject()
method from the superclass.validateJsonObject()
method.displaySchoolList()
method will iterate over the keys of the database which contains the University
names, upon acquiring the keys, they will be printed over the CLI.displaySchoolList()
and execute()
are separated for ease of debugging and code tracing. This is
also in line with the idea that each method has a responsibility of its own.execute
method but kept SLAP in mind to ensure
readability.This command is responsible for listing out all the mappable partner university’s (PU) courses and NUS courses. This allows users to plan their course mapping as it lists out all the possible courses they can map in a specified partner university.
ListUniCoursesCommand
class extends the CheckInformationCommand
class where it overrides the execute method
for custom behaviour.list courses [PU_NAME]
).getUniCourses()
method which will search for the specified PU in the
JsonObject with findUniversityName()
.UnknownUniversityException
will be thrown.listCourses()
will be called. Then getUniversityObject()
and getCourseArray()
methods
will be called to get the JsonObject containing the PU and the JsonArray containing the list of courses it offers.iterateCourses()
method to iterate through the JsonArray courseArray
which
contains the list of courses.printListUniCoursesCommand
method in the UI class.getPuName()
focuses on extracting the university name from user input and findUniversityName()
focuses on searching the university in the data set.The command is responsible to retrieve the email contact and contact number data for a specified partner university. It helps users to reach out to the partner universities for any enquiries about programs or exchange opportunities.
ObtainContactsCommand
class extends the CheckInformationCommand
class where it overrides the execute()
method for custom behaviour.createJsonObject()
method from the
superclass.getSchoolName()
and getContactType()
methods are used to parse the user input, extracting the requested
university name and contact type (email or phone number).findMatchingSchool()
method identifies the correct university entry within the JSON data.isSchoolValid()
method inside the SchoolContactValidator
class is used to check if the
school name exists.checkValidContact()
method checks the validity of the contact type through a
handler isValidContactType()
in SchoolContactValidator
class.contactTypeIdentifier()
method then checks retrieves the contact type and displays the contact information via
theprintContactInformation()
in the UI
class.execute
method is essential and unique to every command class so inheritance was used.SchoolContactValidator
) is used to handle
the validity of each input category. This is in line with the separation of concerns where each method has a
responsibility.execute
method but kept SLAP in mind to ensure
readability.This command is responsible for displaying and retrieving the full list of mappable courses from the partner universities to a user specified NUS course from our data source file which contains university data. It helps the users to identify whether that NUS course is suitable to be mapped overseas in Oceania.
FilterCoursesCommand
class extends Command
class where it overrides the execute
method for
custom behaviour.createJsonObject()
method from the
superclass.parseFilterCommand
method then separates input, which parses the user input to extract the details in the input,
still of String
type.getNusCourseCode
method then extract out the user specified NUS course code from the parsed input, checking
if the course code is a School of Computing course or follows the format of a NUS course code, using the methods
isValidSocCourseCode
and isValidNusCourseCodeFormat
methods in the NusCourseValidator
class.displayMappableCourses()
method along with teh Json object. The method
will iterate over the keys of the database which contains the University names, then obtain the array courses
stored in the “courses” field. The courses
array is then iterated over, for each course,
if the value in the “nus_course_code” is equals to the NUS course code passed into the method, the university name and
“pu_course_code” value of the course will be printed to the CLI.NusCourseCodeValidator
class, separate from the methods used in the FilterCoursesCommand
class, which
are mainly used for the logic behind the filtering of courses.This command is responsible for adding users’ desired course mapping into the myList.json
file.
Additionally, each course mapping is checked against the current course mappings found in
our database, to ensure that the course mapping is accurate and is limited
to universities in Oceania. This command hence helps the users to keep track of their course mapping process.
AddCoursesCommand
class extends Command
class where it overrides the execute
method for
custom behaviour.createJsonObject()
method from the
superclass.trimString
method then removes the add
command and checks whether the user gave any input after the command.
The method would return the trimmed user’s input without the add
command.parseAddCommand()
method to obtain the relevant information: NUS course code,
name of partner university and partner university course code.getUniversityAbbreviations()
method found in the
Parser
class to convert any partner university abbreviations to their full form.createJSONObject()
method, the information extracted from the
parseAddCommand()
method would be passed to the isValidInput()
method to verify the user’s course mapping.CourseValidator
class.getPUCourseList()
method is called to verify if the user’s partner university is
included in the database. An exception is thrown if the university is not found in the database.isValidCourseMapping()
method checks whether the NUS course code and PU course code are compatible
for course mapping against the database.myList.json
file.CourseValidator
class to enhance OOP
and improve readability.Sequence Diagram of AddCourseCommand
Sequence Diagram of Course Validator (extracted out of AddCourseCommand sequence diagram)
This command is responsible for deleting users’ existing course mapping plan from the myList.json
file.
This helps the users to keep track of their most recent course mapping plans, and to keep the myList.json
file organised.
DeleteCoursesCommand
class extends Command
class where it overrides the execute
method for
custom behaviour.execute
is called, the command first passes the user’s input into the parseDeleteCommand
method, which parses
the user input to extract the list index, still of String
type, of the course mapping plan
they would like to delete.getListIndex
method. The list index is then converted to an int
using the
Integer
class. If a valid list index format has been given by the user, the list index is returned.deleteCourse
method, which calls the getCourse
method from the Storage object, and accesses the line in the myList.json
file as specified by the list index to
obtain information of the course to delete, then deletes the course using the deleteCourse
method from the
Storage object.printDeleteMessage
is called to inform the user of the course plan which is deleted.list mapped
command, which shows the index of the saved course mapping plans.The ListPersonalTrackerCommand
is responsible for listing all the mapped modules stored in the user’s personal tracker.
This command retrieves all stored courses from myList.json
via the Storage class and displays them in an indexed list format on the CLI.
ListPersonalTrackerCommand
class extends CheckInformationCommand
and overrides the execute
method to define custom behavior.Storage
object to access stored course mappings.execute
Method:
myList.json
using courseRepository.isFileValid
and courseRepository.hasDuplicateEntries
. If the data integrity fails, the command exits without further execution.loadAllCourses
from the Storage class to retrieve the list of mapped modules.mappedModules
, printing each course with an index for readability by calling printMappedModules
from the IU class.The CompareMappedCommand
is responsible for comparing course mappings between two specified partner universities.
This command aids users in identifying common course mappings across the selected universities, as well as highlighting
unique course mappings specific to each university.
The CompareMappedCommand
class extends CheckInformationCommand
and overrides the execute
method to define its custom behavior.
Below is an outline of the execution flow:
myList.json
using courseRepository.isFileValid
and courseRepository.hasDuplicateEntries
. If the data integrity fails, the command exits without further execution.pu/
to retrieve the names of the two universities specified by the user.
printInvalidInputFormat
method in the UI
class is called to inform the user of incorrect input format.isValidUniversity
to check if the input is a valid university. Otherwise, it will print an error message with the wrong university name and a suggestion.myList.json
file through the Storage
class.null
through assertions.filterModulesByUniversity
method takes the list of all modules and filters out only those associated with the specified university.extractCourseCodes
method extracts the unique course codes for each university, enabling the subsequent comparison.getCommonCourseCodes
method calculates the intersection of course codes between the two universities, identifying courses available in both.getUniqueCourseCodes
method identifies unique courses by excluding the common course codes for each university.displayComparisonResults
method provides output for the comparison:
UI
class for better readability and user experience.execute
: Displaying results directly in the execute
method was an option. However, using dedicated methods (e.g., displayComparisonResults
) improved readability and made testing individual components easier.This command is responsible for the searching of a particular NUS course in the personalised tracker. This allows users to check and plan course mappings for that specified course.
FindCoursesCommand
class extends the CheckInformationCommand
class where it overrides the execute method for
custom behaviour specific to this class.getKeyword()
method to extract out the keyword(NUS course code)
to search within the personalised tracker. If there is no keyword, an IllegalArgumentException
will be thrown.findCommand()
method.findCommand
method, the mappings in the tracker are retrieved through
List<Course> mappedCourses = storage.loadAllCourses()
. If the tracker is empty, a message indicating empty tracker
will be printed.matchKeyword()
will be called, and it iterates the mappedCourses in the tracker to search for mappings that
match the keyword and adds them into a List<Course> foundCourses
.printFindCommand
will iterate and print the course mappings inside mappedCourses through
printFoundCourses()
in UI
class. If mappedCourses is empty, an IllegalArgumentException is thrown.UI
class handles displaying messages to the user, which keeps
FindCoursesCommand
focused solely on search logic, without managing user interactions directly.Version | As a … | I want to … | So that I can … |
---|---|---|---|
v1.0 | CEG student | see the possible Oceania Universities for CEG students | see all my possible choices in that region |
v1.0 | CEG student | search for NUS courses to map | search for related courses in PUs |
v1.0 | CEG student | key in the school I want to go for exchange | view the available course offered by the school |
v1.0 | CEG student | want to see a list of commands | know what to do to go to access the features |
v2.0 | CEG student | obtain the email address of the partner universities | send an email should I have any non-urgent queries |
v2.0 | CEG student | obtain the contact number of the partner universities | call the number should I have any urgent queries |
v2.0 | CEG student | add a course mapping plan for a PU | keep track of my courses for a specific PU |
v2.0 | CEG student | list out the mapped courses by calling the list command | I can track all the courses I have mapped to the different PUs |
v2.0 | CEG student | delete a course mapping plan for a PU | keep my list of saved plans organised |
v2.0 | CEG student | ask for help when I am in doubt | know what are the possible actions |
v2.0 | CEG student | compare different mapping plans for each PU | find the university best fit for my academic schedule |
v2.0 | CEG student | search for course mappings in my personalised tracker | check if I have mappings for that course |
[NOTE!] These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.
[NOTE!] SCHOOL_NAME inputs for the commands:
list courses
,obtain
,add
,compare
are not case-sensitive, and you can either input the University’s full name, or its abbreviation.
commands
commands
command
help add
list schools
list courses The University of Western Australia
list courses uwa
list courses tokyo university
obtain The University of Melbourne /email
obtain The University of Melbourne /number
obtain tokyo university /email
or obtain tokyo university /number
filter cs3241
filter gess1010
filter eeeeeeeeeee
add CS2040 /pu The university of western australia /coursepu CITS2200
add cs3241 /pu unimelb /coursepu comp30019
add invalid format
add cs2040 /pu invalid uni
add cs2040 /pu the university of western australia
add CS1231 /pu the university of western australia /coursepu CITS2200
add CS2040 /pu the university of western australia /coursepu CITS1111
NUS COURSE | PU COURSE
.add CS2040 /pu the university of australia /coursepu CITS2200
delete 1
delete 100
[NOTE!] The tests below would require the tester to corrupt the
myList.json
file stored in the data folder (found in the directory where the tester’s terminal is running from).To corrupt data: At least one saved course mapping plan saved in myList.json, then remove any of the information (NUS course code, Partner University’s name or the course that it offers which is mappable to the NUS course code).
To fix the file: Revert all changes, and make sure that there is no new line after the last course mapping plan.
list mapped
list mapped
list mapped
compare pu/the university of melbourne pu/the university of western australia
compare pu/the university of melbourne pu/the university of western australia
compare pu/the university of melbourne pu/the university of western australia
CS2040 | The university of western australia | CITS2200
find cs2040
find cs2040
find cs
find