/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2009-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.javamail;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.Authenticator;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.event.TransportEvent;
import javax.mail.event.TransportListener;
import javax.mail.internet.MimeBodyPart;
import org.opennms.core.utils.ThreadCategory;
import org.springframework.util.StringUtils;
/**
* Sends an email message using the Java Mail API
*
* @author <A HREF="mailto:david@opennms.org">David Hustace </A>
* @version $Id: $
*/
public abstract class JavaMailer2 {
private Session m_session = null;
private Properties m_mailProps;
/**
* <p>Constructor for JavaMailer2.</p>
*
* @param javamailProps a {@link java.util.Properties} object.
* @throws org.opennms.javamail.JavaMailerException if any.
*/
public JavaMailer2(Properties javamailProps) throws JavaMailerException {
}
/**
* Default constructor. Default properties from javamailer-properties are set into session. To change these
* properties, retrieve the current properties from the session and override as needed.
*
* @throws IOException if any.
* @throws org.opennms.javamail.JavaMailerException if any.
*/
public JavaMailer2() throws JavaMailerException {
this(new Properties());
}
/**
* Helper method to create an Authenticator based on Password Authentication
*
* @param user a {@link java.lang.String} object.
* @param password a {@link java.lang.String} object.
* @return a {@link javax.mail.Authenticator} object.
*/
public Authenticator createAuthenticator(final String user, final String password) {
Authenticator auth;
auth = new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user, password);
}
};
return auth;
}
/*
public Message buildMessage(String m_charSet, String m_encoding, String m_contentType) throws JavaMailerException {
try {
String encodedText = MimeUtility.encodeText(getMessageText(), m_charSet, m_encoding);
if (getFileName() == null) {
message.setContent(encodedText, m_contentType+"; charset="+m_charSet);
} else {
BodyPart bp = new MimeBodyPart();
bp.setContent(encodedText, m_contentType+"; charset="+m_charSet);
MimeMultipart mp = new MimeMultipart();
mp.addBodyPart(bp);
mp = new MimeMultipart();
mp.addBodyPart(createFileAttachment(new File(getFileName())));
message.setContent(mp);
}
message.setHeader("X-Mailer", getMailer());
message.setSentDate(new Date());
message.saveChanges();
return message;
} catch (AddressException e) {
log().error("Java Mailer Addressing exception: ", e);
throw new JavaMailerException("Java Mailer Addressing exception: ", e);
} catch (MessagingException e) {
log().error("Java Mailer messaging exception: ", e);
throw new JavaMailerException("Java Mailer messaging exception: ", e);
} catch (UnsupportedEncodingException e) {
log().error("Java Mailer messaging exception: ", e);
throw new JavaMailerException("Java Mailer encoding exception: ", e);
}
}
*/
/**
* Create a file attachment as a MimeBodyPart, checking to see if the file
* exists before we create the attachment.
*
* @param file file to attach
* @return attachment body part
* @throws javax.mail.MessagingException if we can't set the data handler or
* the file name on the MimeBodyPart
* @throws org.opennms.javamail.JavaMailerException if the file does not exist or is not
* readable
*/
public MimeBodyPart createFileAttachment(final File file) throws MessagingException, JavaMailerException {
if (!file.exists()) {
log().error("File attachment '" + file.getAbsolutePath() + "' does not exist.");
throw new JavaMailerException("File attachment '" + file.getAbsolutePath() + "' does not exist.");
}
if (!file.canRead()) {
log().error("File attachment '" + file.getAbsolutePath() + "' is not readable.");
throw new JavaMailerException("File attachment '" + file.getAbsolutePath() + "' is not readable.");
}
MimeBodyPart bodyPart = new MimeBodyPart();
FileDataSource fds = new FileDataSource(file);
bodyPart.setDataHandler(new DataHandler(fds));
bodyPart.setFileName(fds.getName());
return bodyPart;
}
/**
* <p>setDebug</p>
*
* @param debug a boolean.
*/
public void setDebug(boolean debug) {
if (debug) {
m_session.setDebugOut(new PrintStream(new LoggingByteArrayOutputStream(log()), true));
}
m_session.setDebug(debug);
}
/**
* <p>log</p>
*
* @return log4j Category
*/
protected static ThreadCategory log() {
return ThreadCategory.getInstance();
}
public static class LoggingByteArrayOutputStream extends ByteArrayOutputStream {
private ThreadCategory m_category;
public LoggingByteArrayOutputStream(ThreadCategory threadCategory) {
m_category = threadCategory;
}
@Override
public void flush() throws IOException {
super.flush();
String buffer = toString().replaceAll("\n", "");
if (buffer.length() > 0) {
m_category.debug(buffer);
}
reset();
}
}
public static class LoggingTransportListener implements TransportListener {
private ThreadCategory m_category;
private List<Address> m_invalidAddresses = new ArrayList<Address>();
private List<Address> m_validSentAddresses = new ArrayList<Address>();
private List<Address> m_validUnsentAddresses = new ArrayList<Address>();
public LoggingTransportListener(ThreadCategory threadCategory) {
m_category = threadCategory;
}
public void messageDelivered(TransportEvent event) {
logEvent("message delivered", event);
}
public void messageNotDelivered(TransportEvent event) {
logEvent("message not delivered", event);
}
public void messagePartiallyDelivered(TransportEvent event) {
logEvent("message partially delivered", event);
}
private void logEvent(String message, TransportEvent event) {
if (event.getInvalidAddresses() != null && event.getInvalidAddresses().length > 0) {
m_invalidAddresses.addAll(Arrays.asList(event.getInvalidAddresses()));
m_category.error(message + ": invalid addresses: " + StringUtils.arrayToDelimitedString(event.getInvalidAddresses(), ", "));
}
if (event.getValidSentAddresses() != null && event.getValidSentAddresses().length > 0) {
m_validSentAddresses.addAll(Arrays.asList(event.getValidSentAddresses()));
m_category.debug(message + ": valid sent addresses: " + StringUtils.arrayToDelimitedString(event.getValidSentAddresses(), ", "));
}
if (event.getValidUnsentAddresses() != null && event.getValidUnsentAddresses().length > 0) {
m_validUnsentAddresses.addAll(Arrays.asList(event.getValidUnsentAddresses()));
m_category.error(message + ": valid unsent addresses: " + StringUtils.arrayToDelimitedString(event.getValidUnsentAddresses(), ", "));
}
}
public boolean hasAnythingBeenReceived() {
return m_invalidAddresses.size() != 0 || m_validSentAddresses.size() != 0 || m_validUnsentAddresses.size() != 0;
}
/**
* We sleep up to ten times for 10ms, checking to see if anything has
* been received because the notifications are done by a separate
* thread. We also wait another 50ms after we see the first
* notification come in, just to see if anything else trickles in.
* This isn't perfect, but it's somewhat of a shot in the dark to
* hope that we catch most things, to try to catch as many errors
* as possible so we can fairly reliably report if anything had
* problems.
*
* @throws JavaMailerException
*/
public void assertAllMessagesDelivered() throws JavaMailerException {
for (int i = 0; i < 10; i++) {
if (hasAnythingBeenReceived()) {
break;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// Do nothing
}
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// Do nothing
}
if (m_invalidAddresses.size() == 0 && m_validUnsentAddresses.size() == 0) {
// Nothing failed, so just return
return;
}
throw new JavaMailerException("Not all messages delivered:\n"
+ "\t" + m_validSentAddresses.size() + " messages were sent to valid addresses: " + StringUtils.collectionToDelimitedString(m_validSentAddresses, ", ") + "\n"
+ "\t" + m_validUnsentAddresses.size() + " messages were not sent to valid addresses: " + StringUtils.collectionToDelimitedString(m_validUnsentAddresses, ", ") + "\n"
+ "\t" + m_invalidAddresses.size() + " messages had invalid addresses: " + StringUtils.collectionToDelimitedString(m_invalidAddresses, ", "));
}
}
/**
* <p>getSession</p>
*
* @return the session
*/
public Session getSession() {
return m_session;
}
/**
* <p>setSession</p>
*
* @param session the session to set
*/
public void setSession(Session session) {
m_session = session;
}
/**
* This returns the properties configured in the javamail-configuration.properties file.
*
* @return a {@link java.util.Properties} object.
*/
public Properties getMailProps() {
return m_mailProps;
}
}