001package edu.pdx.cs410J.grader; 002 003import com.google.common.io.Files; 004import edu.pdx.cs410J.ParserException; 005import edu.pdx.cs410J.grader.gradebook.GradeBook; 006import edu.pdx.cs410J.grader.gradebook.Student; 007import edu.pdx.cs410J.grader.gradebook.XmlGradeBookParser; 008import jakarta.mail.MessagingException; 009import jakarta.mail.Session; 010import jakarta.mail.Transport; 011import jakarta.mail.internet.InternetAddress; 012import jakarta.mail.internet.MimeMessage; 013import org.slf4j.Logger; 014import org.slf4j.LoggerFactory; 015 016import java.io.File; 017import java.io.IOException; 018import java.io.PrintStream; 019import java.nio.charset.Charset; 020import java.util.*; 021 022public class StudentFileMailer extends EmailSender { 023 private static Logger logger = LoggerFactory.getLogger(StudentFileMailer.class.getPackage().getName()); 024 025 private final String subject; 026 private final Session session; 027 028 public StudentFileMailer(String subject, Session session) { 029 this.subject = subject; 030 this.session = session; 031 } 032 033 public static void main(String[] args) { 034 String gradeBookFileName = null; 035 String subject = null; 036 List<String> fileNames = new ArrayList<>(); 037 038 for (String arg : args) { 039 if (gradeBookFileName == null) { 040 gradeBookFileName = arg; 041 042 } else if (subject == null) { 043 subject = arg; 044 045 } else { 046 fileNames.add(arg); 047 } 048 } 049 050 usageIfNull(gradeBookFileName, "Missing grade book file name"); 051 usageIfNull(subject, "Missing email subject"); 052 usageIfEmpty(fileNames, "Missing file names"); 053 List<File> files = getFiles(fileNames); 054 GradeBook gradeBook = getGradeBook(gradeBookFileName); 055 Map<Student, File> filesToSendToStudents = getFilesToSendToStudents(files, gradeBook); 056 057 StudentFileMailer mailer = new StudentFileMailer(subject, newEmailSession(false)); 058 filesToSendToStudents.forEach((student, file) -> { 059 try { 060 mailer.mailFileToStudent(file, student); 061 062 } catch (MessagingException | IOException ex) { 063 logger.error("While mailing \"" + file + "\" to " + student, ex); 064 } 065 }); 066 } 067 068 private void mailFileToStudent(File file, Student student) throws MessagingException, IOException { 069 InternetAddress studentEmail = getEmailAddress(student); 070 071 logger.info("Mailing \"" + file + "\" to \"" + studentEmail + "\""); 072 073 MimeMessage message = 074 newEmailTo(this.session, studentEmail) 075 .from(TA_EMAIL) 076 .replyTo(DAVE_EMAIL) 077 .withSubject(this.subject) 078 .createMessage(); 079 message.setText(readTextFromFile(file)); 080 081 sendEmailMessage(message); 082 } 083 084 private String readTextFromFile(File file) throws IOException { 085 StringBuilder sb = new StringBuilder(); 086 Files.copy(file, Charset.defaultCharset(), sb); 087 return sb.toString(); 088 } 089 090 private void sendEmailMessage(MimeMessage message) throws MessagingException { 091 Transport.send(message); 092 } 093 094 private InternetAddress getEmailAddress(Student student) { 095 StringBuilder name = new StringBuilder(); 096 name.append(student.getFirstName()); 097 name.append(" "); 098 if (student.getNickName() != null) { 099 name.append("\""); 100 name.append(student.getNickName()); 101 name.append("\" "); 102 } 103 name.append(student.getLastName()); 104 105 return newInternetAddress(student.getEmail(), name.toString()); 106 } 107 108 private static Map<Student, File> getFilesToSendToStudents(List<File> files, GradeBook gradeBook) { 109 Map<Student, File> filesToSendToStudents = new HashMap<>(); 110 for (File file : files) { 111 String studentId = getStudentIdFromFileName(file); 112 Optional<Student> maybeStudent = gradeBook.getStudent(studentId); 113 if (maybeStudent.isEmpty()) { 114 cannotFindStudent(studentId); 115 } else { 116 filesToSendToStudents.put(maybeStudent.get(), file); 117 } 118 } 119 120 return filesToSendToStudents; 121 } 122 123 private static void cannotFindStudent(String studentId) { 124 logger.warn("Cannot find student with id \"" + studentId + "\" in grade book"); 125 } 126 127 private static String getStudentIdFromFileName(File file) { 128 String studentId; 129 String fileName = file.getName(); 130 int index = fileName.lastIndexOf('.'); 131 if (index < 0) { 132 studentId = fileName; 133 134 } else { 135 studentId = fileName.substring(0, index); 136 } 137 return studentId; 138 } 139 140 private static List<File> getFiles(List<String> fileNames) { 141 List<File> files = new ArrayList<>(fileNames.size()); 142 for (String fileName : fileNames) { 143 File file = new File(fileName); 144 if (!file.exists()) { 145 throw new IllegalStateException("File \"" + fileName + "\" does not exist"); 146 147 } else if (!file.isFile()) { 148 throw new IllegalStateException("File \"" + fileName + "\" is not a file"); 149 } 150 151 files.add(file); 152 } 153 154 return files; 155 } 156 157 private static GradeBook getGradeBook(String gradeBookFileName) { 158 try { 159 XmlGradeBookParser parser = new XmlGradeBookParser(gradeBookFileName); 160 return parser.parse(); 161 162 } catch (IOException ex) { 163 return usage("Couldn't read grade book file \"" + gradeBookFileName + "\""); 164 165 } catch (ParserException ex) { 166 return usage("Couldn't parse grade book file \"" + gradeBookFileName + "\""); 167 } 168 } 169 170 171 private static void usageIfEmpty(List<String> list, String message) { 172 if (list.isEmpty()) { 173 usage(message); 174 } 175 } 176 177 private static void usageIfNull(String arg, String message) { 178 if (arg == null) { 179 usage(message); 180 } 181 } 182 183 private static <T> T usage(String message) { 184 PrintStream err = System.err; 185 186 err.println("** " + message); 187 err.println(); 188 err.println("usage: java StudentFileMailer gradeBookFileName subject fileName+"); 189 err.println(); 190 err.println("Emails a file to a student in a grade book. The name of the file must"); 191 err.println("begin with the student's id."); 192 err.println(); 193 err.println(" gradeBookFileName Name of the grade book file"); 194 err.println(" subject The subject of the email"); 195 err.println(" fileName A file to send to the student"); 196 err.println(); 197 198 System.exit(1); 199 200 throw new UnsupportedOperationException("Should never get here"); 201 } 202}