001package edu.pdx.cs.joy.grader; 002 003import edu.pdx.cs.joy.ParserException; 004import edu.pdx.cs.joy.grader.gradebook.*; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008import java.io.*; 009import java.util.ArrayList; 010import java.util.List; 011import java.util.Optional; 012 013public class ProjectGradesImporter { 014 015 private final GradeBook gradeBook; 016 private final Assignment assignment; 017 private final Logger logger; 018 019 public ProjectGradesImporter(GradeBook gradeBook, Assignment assignment, Logger logger) { 020 this.gradeBook = gradeBook; 021 this.assignment = assignment; 022 this.logger = logger; 023 } 024 025 public static TestedProjectSubmissionOutputParser.ProjectScore getScoreFrom(Reader reader) throws TestedProjectSubmissionOutputParser.TestedProjectSubmissionOutputParsingException, IOException { 026 return TestedProjectSubmissionOutputParser.parseTestedSubmissionOutput(reader); 027 } 028 029 public void recordScoreFromProjectReport(String studentId, Reader report) throws TestedProjectSubmissionOutputParser.TestedProjectSubmissionOutputParsingException, IOException { 030 TestedProjectSubmissionOutputParser.ProjectScore score = getScoreFrom(report); 031 032 if (score.getTotalPoints() != this.assignment.getPoints()) { 033 String message = "Assignment " + this.assignment.getName() + " should be worth " + this.assignment.getPoints() + 034 " points, but the report for " + studentId + " was out of " + score.getTotalPoints(); 035 throw new IllegalStateException(message); 036 } 037 038 Optional<Student> maybeStudent = gradeBook.getStudent(studentId); 039 if (maybeStudent.isEmpty()) { 040 warn("Student \"" + studentId + "\" not found in gradebook"); 041 return; 042 } 043 044 Student student = maybeStudent.get(); 045 Grade grade = student.getGrade(this.assignment); 046 if (grade == null) { 047 grade = new Grade(assignment, score.getScore()); 048 student.setGrade(assignment.getName(), grade); 049 050 } else { 051 grade.setScore(score.getScore()); 052 } 053 054 info("Recorded grade of " + score.getScore() + " for " + studentId); 055 } 056 057 private void info(String message) { 058 this.logger.info(message); 059 } 060 061 private void warn(String message) { 062 logger.warn(message); 063 } 064 065 public static void main(String[] args) { 066 String gradeBookFileName = null; 067 String assignmentName = null; 068 List<String> projectFileNames = new ArrayList<>(); 069 070 for (String arg : args) { 071 if (gradeBookFileName == null) { 072 gradeBookFileName = arg; 073 074 } else if (assignmentName == null) { 075 assignmentName = arg; 076 077 } else { 078 projectFileNames.add(arg); 079 } 080 } 081 082 usageIfNull(gradeBookFileName, "Missing grade book file"); 083 usageIfNull(assignmentName, "Missing assignment name"); 084 usageIfEmpty(projectFileNames, "No project file names provided"); 085 086 GradeBook gradeBook = getGradeBook(gradeBookFileName); 087 Assignment assignment = getAssignment(assignmentName, gradeBook); 088 Logger logger = LoggerFactory.getLogger(ProjectGradesImporter.class.getPackage().getName()); 089 090 ProjectGradesImporter importer = new ProjectGradesImporter(gradeBook, assignment, logger); 091 092 for (String projectFileName : projectFileNames) { 093 File projectFile = getProjectFile(projectFileName); 094 String studentId = getStudentIdFromFileName(projectFile); 095 try { 096 importer.recordScoreFromProjectReport(studentId, new FileReader(projectFile)); 097 098 } catch (FileNotFoundException ex) { 099 throw new IllegalStateException("Could not find file \"" + projectFile + "\""); 100 101 } catch (IllegalStateException | IOException ex) { 102 throw new IllegalStateException("While recording score from " + projectFileName, ex); 103 104 } catch (TestedProjectSubmissionOutputParser.TestedProjectSubmissionOutputParsingException e) { 105 logger.warn("Could not find score in " + projectFileName); 106 } 107 } 108 109 saveGradeBookIfModified(gradeBook, gradeBookFileName); 110 } 111 112 private static void saveGradeBookIfModified(GradeBook gradeBook, String gradeBookFileName) { 113 if (gradeBook.isDirty()) { 114 File file = new File(gradeBookFileName); 115 try { 116 XmlDumper dumper = new XmlDumper(file); 117 dumper.dump(gradeBook); 118 119 } catch (IOException e) { 120 usage("Can't write grade book in \"" + gradeBookFileName + "\""); 121 } 122 } 123 } 124 125 private static String getStudentIdFromFileName(File projectFile) { 126 String fileName = projectFile.getName(); 127 int index = fileName.lastIndexOf('.'); 128 if (index < 0) { 129 return usage("Project file \"" + fileName + "\" does not have a file extension"); 130 } 131 132 return fileName.substring(0, index); 133 } 134 135 private static File getProjectFile(String projectFileName) { 136 File projectFile = new File(projectFileName); 137 if (!projectFile.exists()) { 138 return usage("Project file \"" + projectFileName + "\" does not exist"); 139 140 } else if (!projectFile.isFile()) { 141 return usage("Project file \"" + projectFileName + "\" is not a file"); 142 } 143 144 return projectFile; 145 } 146 147 private static Assignment getAssignment(String assignmentName, GradeBook gradeBook) { 148 Assignment assignment = gradeBook.getAssignment(assignmentName); 149 if (assignment == null) { 150 return usage("Could not find assignment \"" + assignmentName + "\" in grade book"); 151 } 152 return assignment; 153 } 154 155 private static GradeBook getGradeBook(String gradeBookFileName) { 156 try { 157 XmlGradeBookParser parser = new XmlGradeBookParser(gradeBookFileName); 158 return parser.parse(); 159 160 } catch (IOException ex) { 161 return usage("Couldn't read grade book file \"" + gradeBookFileName + "\""); 162 163 } catch (ParserException ex) { 164 return usage("Couldn't parse grade book file \"" + gradeBookFileName + "\""); 165 } 166 } 167 168 private static void usageIfEmpty(List<String> list, String message) { 169 if (list.isEmpty()) { 170 usage(message); 171 } 172 } 173 174 private static void usageIfNull(String argument, String message) { 175 if (argument == null) { 176 usage(message); 177 } 178 } 179 180 private static <T> T usage(String message) { 181 PrintStream err = System.err; 182 183 err.println("** " + message); 184 185 err.println("java ProjectGradesImporter gradeBookFileName assignmentName projectFileName+"); 186 err.println(); 187 err.println("Imports grades (of the form \"5.8 out of 6.0\") from project reports into a grade book."); 188 err.println("The name of the project report file begins with the student's id."); 189 err.println(); 190 err.println(" gradeBookFileName Name of file containing grade book"); 191 err.println(" assignmentName Assignment/project whose score is to be recorded"); 192 err.println(" projectFileName Name of file containing graded project"); 193 err.println(); 194 195 System.exit(1); 196 197 return null; 198 } 199 200}