// $HeadURL: // http://seanderickson1@forge.abcd.harvard.edu/svn/screensaver/trunk/core/src/main/java/edu/harvard/med/iccbl/screensaver/io/AdminEmailApplication.java // $ // $Id$ // // Copyright © 2006, 2010, 2011, 2012 by the President and Fellows of Harvard College. // // Screensaver is an open-source project developed by the ICCB-L and NSRB labs // at Harvard Medical School. This software is distributed under the terms of // the GNU General Public License. package edu.harvard.med.iccbl.screensaver.io; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Set; import javax.mail.MessagingException; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import edu.harvard.med.screensaver.io.CommandLineApplication; import edu.harvard.med.screensaver.model.users.AdministratorUser; import edu.harvard.med.screensaver.model.users.ScreensaverUser; import edu.harvard.med.screensaver.service.EmailService; import edu.harvard.med.screensaver.service.ServiceMessages; import edu.harvard.med.screensaver.service.SmtpEmailService; public class AdminEmailApplication extends CommandLineApplication { private static Logger log = Logger.getLogger(AdminEmailApplication.class); public static final int SHORT_OPTION_INDEX = 0; public static final int ARG_INDEX = 1; public static final int LONG_OPTION_INDEX = 2; public static final int DESCRIPTION_INDEX = 3; public static final DateTimeFormatter EXPIRE_DATE_FORMATTER = DateTimeFormat.fullDate(); public static String USER_PRINT_FORMAT = "|%1$-10s|%2$-30s|%3$-60s"; private ServiceMessages _messages = null; public static final String[] EMAIL_RECIPIENT_LIST_OPTION = { "mr", "comma-separated-list", "mail-recipient-list", "Additional recipients to notify, delimited by \"" + EmailService.DELIMITER + "\"" }; public static final String[] NO_NOTIFY_OPTION = { "noemail", "", "no-email", "Do not send email notifications" }; public static final String[] TEST_EMAIL_ONLY = { "testemail", "", "test-email-only", "send all email notifications to the admin only (not to any users, for testing)" }; public static final String[] EMAIL_DSL_ADMINS_ONLY = { "emaildsladminsonly", "", "email-dsl-admins-only", "send email only to the data sharing level admins (and to the admin running the process), not to any users" }; @SuppressWarnings("static-access") public AdminEmailApplication(String[] cmdLineArgs) { super(cmdLineArgs); addCommandLineOption(OptionBuilder.hasArg() .withArgName(EMAIL_RECIPIENT_LIST_OPTION[ARG_INDEX]) .withDescription(EMAIL_RECIPIENT_LIST_OPTION[DESCRIPTION_INDEX]) .withLongOpt(EMAIL_RECIPIENT_LIST_OPTION[LONG_OPTION_INDEX]) .create(EMAIL_RECIPIENT_LIST_OPTION[SHORT_OPTION_INDEX])); addCommandLineOption(OptionBuilder .withDescription(NO_NOTIFY_OPTION[DESCRIPTION_INDEX]) .withLongOpt(NO_NOTIFY_OPTION[LONG_OPTION_INDEX]) .create(NO_NOTIFY_OPTION[SHORT_OPTION_INDEX])); addCommandLineOption(OptionBuilder .withDescription(TEST_EMAIL_ONLY[DESCRIPTION_INDEX]) .withLongOpt(TEST_EMAIL_ONLY[LONG_OPTION_INDEX]) .create(TEST_EMAIL_ONLY[SHORT_OPTION_INDEX])); addCommandLineOption(OptionBuilder .withDescription(EMAIL_DSL_ADMINS_ONLY[DESCRIPTION_INDEX]) .withLongOpt(EMAIL_DSL_ADMINS_ONLY[LONG_OPTION_INDEX]) .create(EMAIL_DSL_ADMINS_ONLY[SHORT_OPTION_INDEX])); } public boolean isAdminEmailOnly() { return isCommandLineFlagSet(EMAIL_DSL_ADMINS_ONLY[SHORT_OPTION_INDEX]); } public static String printUserHeader() { return String.format(USER_PRINT_FORMAT, "ID", "Name", "Email"); } public static String printUser(ScreensaverUser user) { return String.format(USER_PRINT_FORMAT, user.getEntityId(), user.getFullNameFirstLast(), user.getEmail()); } public static List<String> printUserInformation(ScreensaverUser user) { List<String> buf = Lists.newLinkedList(); buf.add("User ID: " + user.getEntityId()); buf.add("Login ID: " + user.getLoginId()); buf.add("eCommons ID: " + user.getECommonsId()); buf.add("Name: " + user.getFullNameFirstLast()); buf.add("Email: \"" + user.getEmail() + "\""); return buf; } @Override /** * Throws IllegalArgumentException if the AdministratorUser account does not have an email address. * * @throws IllegalArgumentException */ public AdministratorUser findAdministratorUser() throws IllegalArgumentException { AdministratorUser admin = super.findAdministratorUser(); if (admin != null) { if (admin.getEmail() == null) { throw new IllegalArgumentException("The administrative account given does not have an email address"); } } return admin; } /** * Generate an email, with the subject, message, and stacktrace to the admin user running the application. * * @param subject * @param msg * @param e the exception (may be null) * @throws MessagingException */ public final void sendErrorMail(String subject, String msg, Exception e) throws MessagingException { if (e != null) { log.error(subject + "; " + msg, e); StringWriter out = new StringWriter(); e.printStackTrace(new PrintWriter(out)); msg += "\nException:\n" + out.toString(); } else { log.error(subject + "; " + msg); } sendAdminEmails(subject, msg); } public boolean sendEmail(String subject, String msg, ScreensaverUser user) throws MessagingException { List<String> failMessages = Lists.newArrayList(); if (StringUtils.isEmpty(user.getEmail())) { failMessages.add("Empty address for the user: " + printUser(user)); } else { EmailService emailService = getEmailServiceBasedOnCommandLineOption(); if (isAdminEmailOnly()) { sendAdminEmails("Admin email only: " + subject, "originally for: " + printUser(user) + "\nOriginal Message:\n" + msg); } else { try { InternetAddress userAddress = new InternetAddress(user.getEmail()); emailService.send(subject, msg, getAdminEmail(), new InternetAddress[] { userAddress }, null); } catch (AddressException e) { failMessages.add("Address exception for user: " + printUser(user) + ", " + e.getMessage()); } } } if (!failMessages.isEmpty()) { sendFailMessages("User message: " + subject, msg, failMessages); } return failMessages.isEmpty(); } /** * Send email to the administratorUser (running this program), to the "extra recipients" (specified on the * command line), and to the admin accounts, passed in. * * @param subject * @param msg * @throws MessagingException */ public boolean sendEmails(String subject, String msg, Collection<? extends ScreensaverUser> users) throws MessagingException { List<String> failMessages = Lists.newArrayList(); Set<InternetAddress> recipients = Sets.newHashSet(); if (users != null) { for (ScreensaverUser user : users) { String address = user.getEmail(); if (StringUtils.isEmpty(address)) failMessages.add("Empty address for the user: " + printUser(user)); else { try { recipients.add(new InternetAddress(address)); } catch (AddressException e) { failMessages.add("Address excption for user: " + printUser(user) + ", " + e.getMessage()); } } } } if (!recipients.isEmpty()) { EmailService emailService = getEmailServiceBasedOnCommandLineOption(); emailService.send(subject, msg.toString(), getAdminEmail(), recipients.toArray(new InternetAddress[] {}), (InternetAddress[]) null); } if (!failMessages.isEmpty()) { sendFailMessages(subject, msg, failMessages); } return failMessages.isEmpty(); } public void sendAdminEmails(String subject, String msg) throws MessagingException { sendAdminEmails(subject, msg, null, null); } public void sendAdminEmails(String subject, String msg, File attachedFile) throws MessagingException { sendAdminEmails(subject, msg, null, attachedFile); } /** * Send email to the administratorUser (running this program), to the "extra recipients" (specified on the * command line), and to the admin accounts, passed in. * * @param subject * @param msg * @throws MessagingException */ public void sendAdminEmails(String subject, String msg, Collection<ScreensaverUser> adminUsers) throws MessagingException { sendAdminEmails(subject, msg, adminUsers, null); } public void sendAdminEmails(String subject, String msg, Collection<ScreensaverUser> adminUsers, File attachedFile) throws MessagingException { List<String> failMessages = Lists.newArrayList(); Set<InternetAddress> adminRecipients = Sets.newHashSet(); adminRecipients.add(getAdminEmail()); for (String r : getExtraRecipients()) { try { adminRecipients.add(new InternetAddress(r)); } catch (AddressException e) { failMessages.add("Address excption for: " + r + ", " + e.getMessage()); } } if (adminUsers != null) { for (ScreensaverUser user : adminUsers) { String address = user.getEmail(); if (StringUtils.isEmpty(address)) failMessages.add("Empty address for the user: " + printUser(user)); else { try { adminRecipients.add(new InternetAddress(address)); } catch (AddressException e) { failMessages.add("Address excption for user: " + printUser(user) + ", " + e.getMessage()); } } } } EmailService emailService = getEmailServiceBasedOnCommandLineOption(); try { emailService.send(subject, msg.toString(), getAdminEmail(), adminRecipients.toArray(new InternetAddress[] {}), (InternetAddress[]) null, attachedFile); } catch (IOException e) { String errmsg = "Exception when trying to attach the file: " + attachedFile; log.warn(errmsg, e); failMessages.add(errmsg + ", " + e.getMessage()); } if (!failMessages.isEmpty()) { sendFailMessages(subject, msg, failMessages); } } private void sendFailMessages(String subject, String msg, List<String> failMessages) throws MessagingException { StringBuilder errmsg = new StringBuilder("Failures: \n"); for (String m : failMessages) { errmsg.append("\n").append(m); } errmsg.append("\nOriginal Message:\n").append(msg); sendAdminEmails("Failed Message delivery for: " + subject, errmsg.toString()); } public final Set<String> getExtraRecipients() { Set<String> stringSet = Sets.newHashSet(); if (isCommandLineFlagSet(EMAIL_RECIPIENT_LIST_OPTION[SHORT_OPTION_INDEX])) { String recipientList = getCommandLineOptionValue(EMAIL_RECIPIENT_LIST_OPTION[SHORT_OPTION_INDEX]); stringSet.addAll(Arrays.asList(recipientList.split(EmailService.DELIMITER))); } return stringSet; } public ServiceMessages getMessages() { if (_messages == null) { _messages = (ServiceMessages) getSpringBean("serviceMessages"); } return _messages; } public final EmailService getEmailServiceBasedOnCommandLineOption() { EmailService emailService = null; if (isCommandLineFlagSet(NO_NOTIFY_OPTION[SHORT_OPTION_INDEX])) { emailService = new EmailService() { public void send(String subject, String message, InternetAddress from, InternetAddress[] recipients, InternetAddress[] cclist) throws MessagingException { try { send(subject, message, from, recipients, cclist, null); } catch (IOException e) { // this shall never happen e.printStackTrace(); } } public void send(String subject, String message, InternetAddress from, InternetAddress[] recipients, InternetAddress[] cclist, File attachedFile) throws MessagingException, IOException { log.info("Mock Email (Not Sent):\n" + SmtpEmailService.printEmail(subject, message, from, null, recipients, cclist, (attachedFile == null ? "" : "" + attachedFile.getCanonicalFile()))); } }; } else if (isCommandLineFlagSet(TEST_EMAIL_ONLY[SHORT_OPTION_INDEX])) { InternetAddress adminEmail = null; try { adminEmail = new InternetAddress(findAdministratorUser().getEmail()); } catch (AddressException e) { String msg = "Admin account used has an email problem: " + printUserInformation(findAdministratorUser()); throw new IllegalArgumentException(msg, e); } final InternetAddress finalAdminEmail = adminEmail; final EmailService wrappedEmailService = (EmailService) getSpringBean("emailService"); emailService = new EmailService() { public void send(String subject, String message, InternetAddress from, InternetAddress[] recipients, InternetAddress[] cclist) throws MessagingException { try { send(subject, message, from, recipients, cclist, null); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void send(String subject, String message, InternetAddress from, InternetAddress[] recipients, InternetAddress[] ccrecipients, File attachedFile) throws MessagingException, IOException { message = "Testing Email Wrapper: redirect email to admin, original email to be sent to:\n" + Arrays.asList(recipients) + "\n=======message=========\n" + message; wrappedEmailService.send("Redirected to: " + finalAdminEmail + ", Subject: " + subject, message, finalAdminEmail, new InternetAddress[] { finalAdminEmail }, null, attachedFile); } }; } else { emailService = (EmailService) getSpringBean("emailService"); } return emailService; } private InternetAddress getAdminEmail() { try { return new InternetAddress(findAdministratorUser().getEmail()); } catch (AddressException e) { throw new IllegalArgumentException("Problem with the admin email: " + printUserInformation(findAdministratorUser()), e); } } }