package org.nlab.smtp.transport.connection; import org.nlab.smtp.exception.MailSendException; import org.nlab.smtp.pool.ObjectPoolAware; import org.nlab.smtp.pool.SmtpConnectionPool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.mail.Address; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.event.TransportListener; import javax.mail.internet.MimeMessage; /** * Created by nlabrot on 30/04/15. */ public class DefaultClosableSmtpConnection implements ClosableSmtpConnection, ObjectPoolAware { private static final Logger LOG = LoggerFactory.getLogger(DefaultClosableSmtpConnection.class); private final Transport delegate; private SmtpConnectionPool objectPool; private boolean invalidateConnectionOnException; private boolean invalidateConnectionOnClose; private final List<TransportListener> transportListeners = new ArrayList<>(); public DefaultClosableSmtpConnection(Transport delegate, boolean invalidateConnectionOnException) { this.delegate = delegate; this.invalidateConnectionOnException = invalidateConnectionOnException; } @Override public void invalidate() { invalidateConnectionOnClose = true; } @Override public void setInvalidateConnectionOnClose(boolean invalidateConnectionOnClose) { this.invalidateConnectionOnClose = invalidateConnectionOnClose; } public void sendMessage(MimeMessage msg, Address[] recipients) throws MessagingException { doSend(msg, recipients); } public void sendMessage(MimeMessage msg) throws MessagingException { doSend(msg, msg.getAllRecipients()); } public void sendMessages(MimeMessage... msgs) throws MailSendException { doSend(msgs); } public void addTransportListener(TransportListener l) { transportListeners.add(l); delegate.addTransportListener(l); } public void removeTransportListener(TransportListener l) { transportListeners.remove(l); delegate.removeTransportListener(l); } public void clearListeners() { for (TransportListener transportListener : transportListeners) { delegate.removeTransportListener(transportListener); } transportListeners.clear(); } public boolean isConnected() { return delegate.isConnected(); } @Override public void close() { if (!invalidateConnectionOnClose) { objectPool.returnObject(this); } else { try { objectPool.invalidateObject(this); } catch (Exception e) { LOG.error("Failed to invalidate object in the pool", e); } } } @Override public void setObjectPool(SmtpConnectionPool objectPool) { this.objectPool = objectPool; } @Override public SmtpConnectionPool getObjectPool() { return objectPool; } @Override public Transport getDelegate() { return delegate; } @Override public Session getSession() { return objectPool.getSession(); } private void doSend(MimeMessage mimeMessage, Address[] recipients) throws MessagingException { try { if (mimeMessage.getSentDate() == null) { mimeMessage.setSentDate(new Date()); } String messageId = mimeMessage.getMessageID(); mimeMessage.saveChanges(); if (messageId != null) { // Preserve explicitly specified message id... mimeMessage.setHeader(HEADER_MESSAGE_ID, messageId); } delegate.sendMessage(mimeMessage, recipients); } catch (Exception e) { // TODO: An exception can be sent because the recipient is invalid, ie. not because the connection is invalid // TODO: Invalidate based on the MessagingException subclass / cause: IOException if (invalidateConnectionOnException) { invalidate(); } throw e; } } private void doSend(MimeMessage... mimeMessages) throws MailSendException { Map<Object, Exception> failedMessages = new LinkedHashMap<>(); for (MimeMessage mimeMessage : mimeMessages) { // Send message via current transport... try { // doSend takes care to invalidate the connection if needed doSend(mimeMessage, mimeMessage.getAllRecipients()); } catch (Exception ex) { failedMessages.put(mimeMessage, ex); } } if (!failedMessages.isEmpty()) { throw new MailSendException(failedMessages); } } }