diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index b88330f554..399a25215a 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -27,8 +27,8 @@ The key classes providing functionality to TutorLink are:
2. Ui
: Collects data (via Strings sent via CLI) from the user and relays information to the user (via
printing back to the CLI).
3. Parser
: Interprets the raw data from the user; applies data validation and handles necessary exceptions.
-4. Storage
: Serves as long-term storage of data to be retained even after TutorLink is shut down.
-5. CommandResult
represents the result of user input.
+4. Storage
: Handles the loading and storage of data to be retained even after TutorLink is shut down.
+5. CommandResult
: Represents the result of user input.
### Target User Profile
@@ -110,8 +110,8 @@ The flow of logic for both `Student` and `Component` commands can be summarized
1. Retrieve arguments from `HashMap`.
2. Execute data validation on the arguments and throw appropriate exception in the case of failure.
-2. Add/Delete `Student` and `Component`.
-3. Return `CommandResult` that contains the result of the Add/Delete operation.
+3. Add/Delete `Student` and `Component`.
+4. Return `CommandResult` that contains the result of the Add/Delete operation.
The following sequence diagrams depict the exact steps involved in the `AddStudentCommand`:
@@ -168,19 +168,23 @@ The sequence diagram of the DeleteGradeCommand is shown below.
![DeleteGradeCommand.png](diagrams%2FDeleteGradeCommand.png)
-### Storage feature
+### Storage Load feature
-#### Implementation
+The `StudentStorage`, `GradeStorage` and `ComponentStorage` classes implement the feature to load data from the
+data `.txt` files into their respective List objects at the start of the program.
-The `Storage` class is responsible for the automatic loading and saving of list data to and from `.txt` files,
-so that data will be retained between runs of the application.
+The load list methods for the Storage classes have largely similar logic flows.
+The following section and sequence diagram elaborate on the implementation of the `loadGradeList` method in `GradeStorage`:
-#### Example Usage Scenario
-
-Step 1: The user launches the application. During startup, the `main` method calls constructors for `Storage` objects
-for each of `StudentList`, `ComponentList` and `Gradelist`.
-
-Step 2: The predefined filepaths are passed into the constructor. The directory and file are created if they do not
-currently exist.
+![GradeStorage.png](diagrams/GradeStorage.png)
-
+1. TutorLink constructs a new `GradeStorage`.
+2. TutorLink calls `loadGradeList`.
+3. `GradeStorage` creates a new `ArrayList` of `Grade`s.
+4. `GradeStorage` creates a new `Scanner` with the path to the file.
+5. While there are next lines in the data file:
+ - `Scanner` returns the current file line as a String and moves to the next file line.
+ - `GradeStorage` calls its `getGradeFromFileLine` method with the file line.
+ - If the file line references a valid `Component` and a valid `Student`, a `Grade` is returned and added to the `ArrayList`.
+ - If not (e.g. if data file was corrupted), the file line is simply ignored, and the loop continues to the next iteration.
+6. The `ArrayList` of `Grade`s is returned to TutorLink.
diff --git a/docs/diagrams/GradeStorage.png b/docs/diagrams/GradeStorage.png
new file mode 100644
index 0000000000..1b353aabae
Binary files /dev/null and b/docs/diagrams/GradeStorage.png differ
diff --git a/docs/diagrams/GradeStorage.puml b/docs/diagrams/GradeStorage.puml
new file mode 100644
index 0000000000..ec5ac6cd7d
--- /dev/null
+++ b/docs/diagrams/GradeStorage.puml
@@ -0,0 +1,55 @@
+@startuml
+
+!include Style.puml
+participant ":TutorLink" as TL LOGIC_COLOR_5
+participant "gradeStorage: GradeStorage" as GS LOGIC_COLOR_4
+participant "grades: ArrayList" as AL LOGIC_COLOR_6
+participant "fileScanner: Scanner" as FS LOGIC_COLOR_7
+
+create GS
+TL -> GS: new GradeStorage(GRADE_FILE_PATH, initialComponentList, initialStudentList)
+activate GS
+TL <-- GS: gradeStorage: GradeStorage
+deactivate GS
+
+TL -> GS: loadGradeList()
+activate GS
+
+create AL
+GS -> AL: new ArrayList()
+activate AL
+GS <-- AL: grades: Grade
+deactivate AL
+
+create FS
+GS -> FS: new Scanner(path: String)
+activate FS
+GS <-- FS: fileScanner: Scanner
+deactivate FS
+
+loop fileScanner.hasNext()
+ GS -> FS: nextLine()
+ activate FS
+ GS <-- FS: currentLine: String
+ deactivate FS
+ GS -> GS: getGradeFromFileLine(currentLine: String)
+ activate GS
+ GS --> GS: newGrade: Grade
+ deactivate GS
+
+ alt success
+ GS -> AL: add(newGrade)
+ activate AL
+ GS <-- AL
+ deactivate AL
+ else InvalidDataFileLineException
+ end
+
+end
+
+destroy FS
+
+TL <-- GS: grades: Grade
+deactivate GS
+
+@enduml
diff --git a/src/main/java/tutorlink/exceptions/InvalidDataFileLineException.java b/src/main/java/tutorlink/exceptions/InvalidDataFileLineException.java
new file mode 100644
index 0000000000..85e1b18c62
--- /dev/null
+++ b/src/main/java/tutorlink/exceptions/InvalidDataFileLineException.java
@@ -0,0 +1,7 @@
+package tutorlink.exceptions;
+
+public class InvalidDataFileLineException extends TutorLinkException {
+ public InvalidDataFileLineException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/tutorlink/storage/GradeStorage.java b/src/main/java/tutorlink/storage/GradeStorage.java
index 1fa483eb2d..f154677b50 100644
--- a/src/main/java/tutorlink/storage/GradeStorage.java
+++ b/src/main/java/tutorlink/storage/GradeStorage.java
@@ -1,6 +1,7 @@
package tutorlink.storage;
import tutorlink.component.Component;
+import tutorlink.exceptions.InvalidDataFileLineException;
import tutorlink.grade.Grade;
import tutorlink.student.Student;
@@ -24,29 +25,10 @@ public ArrayList loadGradeList()
ArrayList grades = new ArrayList<>();
Scanner fileScanner = new Scanner(path);
while (fileScanner.hasNext()) {
- String[] stringParts = fileScanner.nextLine().split(READ_DELIMITER);
- String componentName = stringParts[0];
- String matricNumber = stringParts[1];
- double score = Double.parseDouble(stringParts[2]);
-
- Component selectedComp = null;
- for (Component comp : componentList) {
- if (comp.getName().equals(componentName)) {
- selectedComp = comp;
- break;
- }
- }
- Student selectedStudent = null;
- for (Student student : studentList) {
- if (student.getMatricNumber().equals(matricNumber)) {
- selectedStudent = student;
- break;
- }
- }
-
- if (selectedComp != null && selectedStudent != null) {
- Grade newGrade = new Grade(selectedComp, selectedStudent, score);
- grades.add(newGrade);
+ try {
+ grades.add(getGradeFromFileLine(fileScanner.nextLine()));
+ } catch (InvalidDataFileLineException e) {
+ // ignore invalid data file entries
}
}
return grades;
@@ -60,6 +42,35 @@ public void saveGradeList(ArrayList grades) throws IOException {
fileWriter.close();
}
+ private Grade getGradeFromFileLine(String fileLine) throws InvalidDataFileLineException {
+ String[] stringParts = fileLine.split(READ_DELIMITER);
+ String componentName = stringParts[0];
+ String matricNumber = stringParts[1];
+ double score = Double.parseDouble(stringParts[2]);
+
+ Component selectedComp = null;
+ for (Component comp : componentList) {
+ if (comp.getName().equals(componentName)) {
+ selectedComp = comp;
+ break;
+ }
+ }
+
+ Student selectedStudent = null;
+ for (Student student : studentList) {
+ if (student.getMatricNumber().equals(matricNumber)) {
+ selectedStudent = student;
+ break;
+ }
+ }
+
+ if (selectedComp != null && selectedStudent != null) {
+ return new Grade(selectedComp, selectedStudent, score);
+ } else {
+ throw new InvalidDataFileLineException("Invalid grade");
+ }
+ }
+
private String getFileInputForGrade(Grade grade) {
String componentName = grade.getComponent().getName();
String matricNumber = grade.getStudent().getMatricNumber();