You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ro...@apache.org on 2017/01/10 14:18:16 UTC
[01/50] [abbrv] james-project git commit: JAMES-1877 RemoteDelivery
should rely on constructor injection
Repository: james-project
Updated Branches:
refs/heads/master 3b6c5e00d -> 131c01148
JAMES-1877 RemoteDelivery should rely on constructor injection
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/788b3931
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/788b3931
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/788b3931
Branch: refs/heads/master
Commit: 788b3931e55d34f422176f6795a2ed707cbd8e87
Parents: 1cb969b
Author: Benoit Tellier <bt...@linagora.com>
Authored: Tue Nov 29 10:50:38 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 11:37:10 2017 +0700
----------------------------------------------------------------------
.../james/transport/mailets/RemoteDelivery.java | 39 ++++++--------------
1 file changed, 11 insertions(+), 28 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/788b3931/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index c4113b5..89a4987 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -164,8 +164,12 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
private static final Pattern PATTERN = Patterns.compilePatternUncheckedException(PATTERN_STRING);
private static final String OUTGOING_MAILS = "outgoingMails";
- @Inject
- private DNSService dnsServer;
+ private final DNSService dnsServer;
+ private final DomainList domainList;
+ private final MailQueueFactory queueFactory;
+ private final Metric outgoingMailsMetric;
+ private final Properties defprops; // Default properties for the JavaMail Session
+ private final Collection<Thread> workersThreads;
/**
* Flag to define verbose logging messages.
@@ -225,11 +229,6 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
private boolean isBindUsed = false;
/**
- * Collection that stores all worker threads.
- */
- private final Collection<Thread> workersThreads = new Vector<Thread>();
-
- /**
* Flag used by 'run' method to end itself.
*/
private volatile boolean destroyed = false;
@@ -239,47 +238,32 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
*/
private String bounceProcessor = null;
- /**
- * Default properties for the JavaMail Session
- */
- private final Properties defprops = new Properties();
/**
* The retry count dnsProblemErrors
*/
private int dnsProblemRetry = 0;
- private MailQueueFactory queueFactory;
-
private MailQueue queue;
private Logger logger;
private boolean usePriority;
- private DomainList domainList;
-
private boolean startTLS = false;
private boolean isSSLEnable = false;
- private MetricFactory metricFactory;
- private Metric outgoingMailsMetric;
private HeloNameProvider heloNameProvider;
@Inject
- public void setDomainList(DomainList domainList) {
+ public RemoteDelivery(DNSService dnsServer, DomainList domainList, MailQueueFactory queueFactory, MetricFactory metricFactory) {
+ this.dnsServer = dnsServer;
this.domainList = domainList;
- }
-
- @Inject
- public void setMailQueueFactory(MailQueueFactory queueFactory) {
this.queueFactory = queueFactory;
- }
-
- @Inject
- public void setMetricFactory(MetricFactory metricFactory) {
- this.metricFactory = metricFactory;
+ this.outgoingMailsMetric = metricFactory.generate(OUTGOING_MAILS);
+ this.defprops = new Properties();
+ this.workersThreads = new Vector<Thread>();
}
/**
@@ -289,7 +273,6 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
* @throws MessagingException on failure to initialize attributes.
*/
public void init() throws MessagingException {
- outgoingMailsMetric = metricFactory.generate(OUTGOING_MAILS);
// Set isDebug flag.
isDebug = (getInitParameter("debug") == null) ? false : Boolean.valueOf(getInitParameter("debug"));
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[14/50] [abbrv] james-project git commit: JAMES-1877 Try to reduce
DeliveryRunnable complexity
Posted by ro...@apache.org.
JAMES-1877 Try to reduce DeliveryRunnable complexity
- Extract log message and bounce message generation
- Do some IDE extraction refactoring
- Simplify remaining debug log computation
- Simplify comments
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/b839f8b0
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/b839f8b0
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/b839f8b0
Branch: refs/heads/master
Commit: b839f8b086941c613eb9a23a9acf5594327e947a
Parents: 6774b87
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 14:09:34 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:48 2017 +0700
----------------------------------------------------------------------
.../remoteDelivery/DeliveryRunnable.java | 979 ++++++++-----------
1 file changed, 383 insertions(+), 596 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/b839f8b0/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index 5a0bdf1..cb189d0 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -20,13 +20,8 @@
package org.apache.james.transport.mailets.remoteDelivery;
import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.net.ConnectException;
-import java.net.SocketException;
-import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -63,6 +58,7 @@ import com.sun.mail.smtp.SMTPTransport;
@SuppressWarnings("deprecation")
public class DeliveryRunnable implements Runnable {
+ public static final boolean PERMANENT_FAILURE = true;
private final MailQueue queue;
private final RemoteDeliveryConfiguration configuration;
private final DNSService dnsServer;
@@ -70,6 +66,7 @@ public class DeliveryRunnable implements Runnable {
private final Logger logger;
private final MailetContext mailetContext;
private final VolatileIsDestroyed volatileIsDestroyed;
+ private final MessageComposer messageComposer;
public DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, DNSService dnsServer, Metric outgoingMailsMetric, Logger logger, MailetContext mailetContext, VolatileIsDestroyed volatileIsDestroyed) {
this.queue = queue;
@@ -79,6 +76,7 @@ public class DeliveryRunnable implements Runnable {
this.logger = logger;
this.mailetContext = mailetContext;
this.volatileIsDestroyed = volatileIsDestroyed;
+ this.messageComposer = new MessageComposer(configuration);
}
/**
@@ -91,81 +89,29 @@ public class DeliveryRunnable implements Runnable {
try {
while (!Thread.interrupted() && !volatileIsDestroyed.isDestroyed()) {
try {
- // Get the 'mail' object that is ready for deliverying. If
- // no
- // message is
+ // Get the 'mail' object that is ready for deliverying. If no message is
// ready, the 'accept' will block until message is ready.
- // The amount
- // of time to block is determined by the 'getWaitTime'
- // method of the
- // MultipleDelayFilter.
+ // The amount of time to block is determined by the 'getWaitTime' method of the MultipleDelayFilter.
MailQueue.MailQueueItem queueItem = queue.deQueue();
Mail mail = queueItem.getMail();
- String key = mail.getName();
-
try {
if (configuration.isDebug()) {
- String message = Thread.currentThread().getName() + " will process mail " + key;
- logger.debug(message);
+ logger.debug(Thread.currentThread().getName() + " will process mail " + mail.getName());
}
- // Deliver message
- if (deliver(mail, session)) {
- // Message was successfully delivered/fully
- // failed...
- // delete it
- LifecycleUtil.dispose(mail);
- // workRepository.remove(key);
- } else {
- // Something happened that will delay delivery.
- // Store it back in the retry repository.
- // workRepository.store(mail);
- int retries = 0;
- try {
- retries = Integer.parseInt(mail.getErrorMessage());
- } catch (NumberFormatException e) {
- // Something strange was happen with the
- // errorMessage..
- }
-
- long delay = getNextDelay(retries);
+ attemptDelivery(session, mail);
- if (configuration.isUsePriority()) {
- // Use lowest priority for retries. See JAMES-1311
- mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY);
- }
- queue.enQueue(mail, delay, TimeUnit.MILLISECONDS);
- LifecycleUtil.dispose(mail);
-
- // This is an update, so we have to unlock and
- // notify or this mail is kept locked by this
- // thread.
- // workRepository.unlock(key);
-
- // Note: We do not notify because we updated an
- // already existing mail and we are now free to
- // handle
- // more mails.
- // Furthermore this mail should not be processed now
- // because we have a retry time scheduling.
- }
-
- // Clear the object handle to make sure it recycles
- // this object.
+ // Clear the object handle to make sure it recycles this object.
mail = null;
queueItem.done(true);
} catch (Exception e) {
- // Prevent unexpected exceptions from causing looping by
- // removing message from outgoing.
- // DO NOT CHANGE THIS to catch Error! For example, if
- // there were an OutOfMemory condition caused because
- // something else in the server was abusing memory, we
- // would
- // not want to start purging the retrying spool!
+ // Prevent unexpected exceptions from causing looping by removing message from outgoing.
+ // DO NOT CHANGE THIS to catch Error!
+ // For example, if there were an OutOfMemory condition caused because
+ // something else in the server was abusing memory, we would not want to start purging the retrying spool!
logger.error("Exception caught in RemoteDelivery.run()", e);
LifecycleUtil.dispose(mail);
- // workRepository.remove(key);
queueItem.done(false);
throw new MailQueue.MailQueueException("Unable to perform dequeue", e);
}
@@ -182,6 +128,30 @@ public class DeliveryRunnable implements Runnable {
}
}
+ private void attemptDelivery(Session session, Mail mail) throws MailQueue.MailQueueException {
+ if (deliver(mail, session)) {
+ // Message was successfully delivered/fully failed... delete it
+ LifecycleUtil.dispose(mail);
+ } else {
+ // Something happened that will delay delivery. Store it back in the retry repository.
+ int retries = 0;
+ try {
+ retries = Integer.parseInt(mail.getErrorMessage());
+ } catch (NumberFormatException e) {
+ // Something strange was happen with the errorMessage..
+ }
+
+ long delay = getNextDelay(retries);
+
+ if (configuration.isUsePriority()) {
+ // Use lowest priority for retries. See JAMES-1311
+ mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY);
+ }
+ queue.enQueue(mail, delay, TimeUnit.MILLISECONDS);
+ LifecycleUtil.dispose(mail);
+ }
+ }
+
/**
* We can assume that the recipients of this message are all going to the
@@ -196,264 +166,43 @@ public class DeliveryRunnable implements Runnable {
*/
private boolean deliver(Mail mail, Session session) {
try {
- if (configuration.isDebug()) {
- logger.debug("Attempting to deliver " + mail.getName());
- }
- MimeMessage message = mail.getMessage();
-
- // Create an array of the recipients as InternetAddress objects
- Collection<MailAddress> recipients = mail.getRecipients();
- InternetAddress addr[] = new InternetAddress[recipients.size()];
- int j = 0;
- for (Iterator<MailAddress> i = recipients.iterator(); i.hasNext(); j++) {
- MailAddress rcpt = i.next();
- addr[j] = rcpt.toInternetAddress();
- }
-
- if (addr.length <= 0) {
- logger.info("No recipients specified... not sure how this could have happened.");
- return true;
- }
-
- // Figure out which servers to try to send to. This collection
- // will hold all the possible target servers
- Iterator<HostAddress> targetServers;
- if (configuration.getGatewayServer().isEmpty()) {
- MailAddress rcpt = recipients.iterator().next();
- String host = rcpt.getDomain();
-
- // Lookup the possible targets
- try {
- targetServers = new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logger);
- } catch (TemporaryResolutionException e) {
- logger.info("Temporary problem looking up mail server for host: " + host);
- String exceptionBuffer = "Temporary problem looking up mail server for host: " + host + ". I cannot determine where to send this message.";
-
- // temporary problems
- return failMessage(mail, new MessagingException(exceptionBuffer), false);
- }
- if (!targetServers.hasNext()) {
- logger.info("No mail server found for: " + host);
- String exceptionBuffer = "There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.";
-
- int retry = 0;
- try {
- retry = Integer.parseInt(mail.getErrorMessage());
- } catch (NumberFormatException e) {
- // Unable to parse retryCount
- }
- if (retry == 0 || retry > configuration.getDnsProblemRetry()) {
- // The domain has no dns entry.. Return a permanent
- // error
- return failMessage(mail, new MessagingException(exceptionBuffer), true);
- } else {
- return failMessage(mail, new MessagingException(exceptionBuffer), false);
- }
- }
- } else {
- targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer());
+ Boolean host = tryDeliver(mail, session);
+ if (host != null) {
+ return host;
}
+ /*
+ * If we get here, we've exhausted the loop of servers without sending
+ * the message or throwing an exception. One case where this might
+ * happen is if we get a MessagingException on each transport.connect(),
+ * e.g., if there is only one server and we get a connect exception.
+ */
+ return failMessage(mail, new MessagingException("No mail server(s) available at this time."), false);
+ } catch (SendFailedException sfe) {
+ return handleSenderFailedException(mail, sfe);
+ } catch (MessagingException ex) {
+ // We should do a better job checking this... if the failure is a general
+ // connect exception, this is less descriptive than more specific SMTP command
+ // failure... have to lookup and see what are the various Exception possibilities
- MessagingException lastError = null;
-
- while (targetServers.hasNext()) {
- try {
-
- Properties props = session.getProperties();
- if (mail.getSender() == null) {
- props.put("mail.smtp.from", "<>");
- } else {
- String sender = mail.getSender().toString();
- props.put("mail.smtp.from", sender);
- }
+ // Unable to deliver message after numerous tries... fail accordingly
- HostAddress outgoingMailServer = targetServers.next();
- StringBuilder logMessageBuffer = new StringBuilder(256).append("Attempting delivery of ").append(mail.getName()).append(" to host ").append(outgoingMailServer.getHostName()).append(" at ").append(outgoingMailServer.getHost()).append(" from ").append(props.get("mail.smtp.from"))
- .append(" for addresses ").append(Arrays.asList(addr));
- logger.debug(logMessageBuffer.toString());
-
- // Many of these properties are only in later JavaMail
- // versions
- // "mail.smtp.ehlo" //default true
- // "mail.smtp.auth" //default false
- // "mail.smtp.dsn.ret" //default to nothing... appended as
- // RET= after MAIL FROM line.
- // "mail.smtp.dsn.notify" //default to nothing...appended as
- // NOTIFY= after RCPT TO line.
-
- SMTPTransport transport = null;
- try {
- transport = (SMTPTransport) session.getTransport(outgoingMailServer);
- transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
- try {
- if (configuration.getAuthUser() != null) {
- transport.connect(outgoingMailServer.getHostName(), configuration.getAuthUser(), configuration.getAuthPass());
- } else {
- transport.connect();
- }
- } catch (MessagingException me) {
- // Any error on connect should cause the mailet to
- // attempt
- // to connect to the next SMTP server associated
- // with this
- // MX record. Just log the exception. We'll worry
- // about
- // failing the message at the end of the loop.
-
- // Also include the stacktrace if debug is enabled. See JAMES-1257
- if (configuration.isDebug()) {
- logger.debug(me.getMessage(), me.getCause());
- } else {
- logger.info(me.getMessage());
- }
- continue;
- }
- // if the transport is a SMTPTransport (from sun) some
- // performance enhancement can be done.
- if (transport.getClass().getName().endsWith(".SMTPTransport")) {
- boolean supports8bitmime = false;
- try {
- Method supportsExtension = transport.getClass().getMethod("supportsExtension", new Class[]{String.class});
- supports8bitmime = (Boolean) supportsExtension.invoke(transport, "8BITMIME");
- } catch (NoSuchMethodException nsme) {
- // An SMTPAddressFailedException with no
- // getAddress method.
- } catch (IllegalAccessException iae) {
- } catch (IllegalArgumentException iae) {
- } catch (InvocationTargetException ite) {
- // Other issues with getAddress invokation.
- }
-
- // if the message is alredy 8bit or binary and the
- // server doesn't support the 8bit extension it has
- // to be converted to 7bit. Javamail api doesn't
- // perform
- // that conversion, but it is required to be a
- // rfc-compliant smtp server.
-
- // Temporarily disabled. See JAMES-638
- if (!supports8bitmime) {
- try {
- convertTo7Bit(message);
- } catch (IOException e) {
- // An error has occured during the 7bit
- // conversion.
- // The error is logged and the message is
- // sent anyway.
-
- logger.error("Error during the conversion to 7 bit.", e);
- }
- }
- } else {
- // If the transport is not the one
- // developed by Sun we are not sure of how it
- // handles the 8 bit mime stuff,
- // so I convert the message to 7bit.
- try {
- convertTo7Bit(message);
- } catch (IOException e) {
- logger.error("Error during the conversion to 7 bit.", e);
- }
- }
- transport.sendMessage(message, addr);
- } finally {
- if (transport != null) {
- try {
- // James-899: transport.close() sends QUIT to
- // the server; if that fails
- // (e.g. because the server has already closed
- // the connection) the message
- // should be considered to be delivered because
- // the error happened outside
- // of the mail transaction (MAIL, RCPT, DATA).
- transport.close();
- } catch (MessagingException e) {
- logger.error("Warning: could not close the SMTP transport after sending mail (" + mail.getName() + ") to " + outgoingMailServer.getHostName() + " at " + outgoingMailServer.getHost() + " for " + mail.getRecipients() + "; probably the server has already closed the "
- + "connection. Message is considered to be delivered. Exception: " + e.getMessage());
- }
- transport = null;
- }
- }
- logMessageBuffer = new StringBuilder(256).append("Mail (").append(mail.getName()).append(") sent successfully to ").append(outgoingMailServer.getHostName()).append(" at ").append(outgoingMailServer.getHost()).append(" from ").append(props.get("mail.smtp.from")).append(" for ")
- .append(mail.getRecipients());
- logger.debug(logMessageBuffer.toString());
- outgoingMailsMetric.increment();
- return true;
- } catch (SendFailedException sfe) {
- logSendFailedException(sfe);
-
- if (sfe.getValidSentAddresses() != null) {
- Address[] validSent = sfe.getValidSentAddresses();
- if (validSent.length > 0) {
- String logMessageBuffer = "Mail (" + mail.getName() + ") sent successfully for " + Arrays.asList(validSent);
- logger.debug(logMessageBuffer);
- }
- }
+ // We check whether this is a 5xx error message, which indicates a permanent failure (like account doesn't exist
+ // or mailbox is full or domain is setup wrong). We fail permanently if this was a 5xx error
+ return failMessage(mail, ex, ('5' == ex.getMessage().charAt(0)));
+ } catch (Exception ex) {
+ logger.error("Generic exception = permanent failure: " + ex.getMessage(), ex);
+ // Generic exception = permanent failure
+ return failMessage(mail, ex, PERMANENT_FAILURE);
+ }
+ }
- /*
- * SMTPSendFailedException introduced in JavaMail 1.3.2, and
- * provides detailed protocol reply code for the operation
- */
- if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
- try {
- int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
- // if 5xx, terminate this delivery attempt by
- // re-throwing the exception.
- if (returnCode >= 500 && returnCode <= 599)
- throw sfe;
- } catch (ClassCastException cce) {
- } catch (IllegalArgumentException iae) {
- }
- }
+ private boolean handleSenderFailedException(Mail mail, SendFailedException sfe) {
+ logSendFailedException(sfe);
- if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) {
- if (configuration.isDebug())
- logger.debug("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers");
- lastError = sfe;
- } else {
- // There are no valid addresses left to send, so rethrow
- throw sfe;
- }
- } catch (MessagingException me) {
- // MessagingException are horribly difficult to figure out
- // what actually happened.
- String exceptionBuffer = "Exception delivering message (" + mail.getName() + ") - " + me.getMessage();
- logger.debug(exceptionBuffer);
- if ((me.getNextException() != null) && (me.getNextException() instanceof java.io.IOException)) {
- // This is more than likely a temporary failure
-
- // If it's an IO exception with no nested exception,
- // it's probably
- // some socket or weird I/O related problem.
- lastError = me;
- continue;
- }
- // This was not a connection or I/O error particular to one
- // SMTP server of an MX set. Instead, it is almost certainly
- // a protocol level error. In this case we assume that this
- // is an error we'd encounter with any of the SMTP servers
- // associated with this MX record, and we pass the exception
- // to the code in the outer block that determines its
- // severity.
- throw me;
- }
- } // end while
- // If we encountered an exception while looping through,
- // throw the last MessagingException we caught. We only
- // do this if we were unable to send the message to any
- // server. If sending eventually succeeded, we exit
- // deliver() though the return at the end of the try
- // block.
- if (lastError != null) {
- throw lastError;
- }
- } catch (SendFailedException sfe) {
- logSendFailedException(sfe);
-
- // Copy the recipients as direct modification may not be possible
- Collection<MailAddress> recipients = new ArrayList<MailAddress>(mail.getRecipients());
+ // Copy the recipients as direct modification may not be possible
+ Collection<MailAddress> recipients = new ArrayList<MailAddress>(mail.getRecipients());
- boolean deleteMessage = false;
+ boolean deleteMessage = false;
/*
* If you send a message that has multiple invalid addresses, you'll
@@ -477,138 +226,339 @@ public class DeliveryRunnable implements Runnable {
* SMTPSendFailedException introduced in JavaMail 1.3.2, and
* provides detailed protocol reply code for the operation
*/
- try {
- if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
- int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
- // If we got an SMTPSendFailedException, use its RetCode to
- // determine default permanent/temporary failure
- deleteMessage = (returnCode >= 500 && returnCode <= 599);
- } else {
- // Sometimes we'll get a normal SendFailedException with
- // nested SMTPAddressFailedException, so use the latter
- // RetCode
- MessagingException me = sfe;
- Exception ne;
- while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
- me = (MessagingException) ne;
- if (me.getClass().getName().endsWith(".SMTPAddressFailedException")) {
- int returnCode = (Integer) invokeGetter(me, "getReturnCode");
- deleteMessage = (returnCode >= 500 && returnCode <= 599);
- }
+ try {
+ if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
+ int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
+ // If we got an SMTPSendFailedException, use its RetCode to
+ // determine default permanent/temporary failure
+ deleteMessage = (returnCode >= 500 && returnCode <= 599);
+ } else {
+ // Sometimes we'll get a normal SendFailedException with
+ // nested SMTPAddressFailedException, so use the latter
+ // RetCode
+ MessagingException me = sfe;
+ Exception ne;
+ while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
+ me = (MessagingException) ne;
+ if (me.getClass().getName().endsWith(".SMTPAddressFailedException")) {
+ int returnCode = (Integer) invokeGetter(me, "getReturnCode");
+ deleteMessage = (returnCode >= 500 && returnCode <= 599);
}
}
- } catch (IllegalStateException ise) {
- // unexpected exception (not a compatible javamail
- // implementation)
- } catch (ClassCastException cce) {
- // unexpected exception (not a compatible javamail
- // implementation)
}
+ } catch (IllegalStateException ise) {
+ // unexpected exception (not a compatible javamail
+ // implementation)
+ } catch (ClassCastException cce) {
+ // unexpected exception (not a compatible javamail
+ // implementation)
+ }
- // log the original set of intended recipients
- if (configuration.isDebug())
- logger.debug("Recipients: " + recipients);
+ // log the original set of intended recipients
+ if (configuration.isDebug())
+ logger.debug("Recipients: " + recipients);
- if (sfe.getInvalidAddresses() != null) {
- Address[] address = sfe.getInvalidAddresses();
- if (address.length > 0) {
- recipients.clear();
- for (Address addres : address) {
- try {
- recipients.add(new MailAddress(addres.toString()));
- } catch (ParseException pe) {
- // this should never happen ... we should have
- // caught malformed addresses long before we
- // got to this code.
- logger.debug("Can't parse invalid address: " + pe.getMessage());
- }
+ if (sfe.getInvalidAddresses() != null) {
+ Address[] address = sfe.getInvalidAddresses();
+ if (address.length > 0) {
+ recipients.clear();
+ for (Address addres : address) {
+ try {
+ recipients.add(new MailAddress(addres.toString()));
+ } catch (ParseException pe) {
+ // this should never happen ... we should have
+ // caught malformed addresses long before we
+ // got to this code.
+ logger.debug("Can't parse invalid address: " + pe.getMessage());
}
- // Set the recipients for the mail
- mail.setRecipients(recipients);
+ }
+ // Set the recipients for the mail
+ mail.setRecipients(recipients);
- if (configuration.isDebug())
- logger.debug("Invalid recipients: " + recipients);
- deleteMessage = failMessage(mail, sfe, true);
+ if (configuration.isDebug())
+ logger.debug("Invalid recipients: " + recipients);
+ deleteMessage = failMessage(mail, sfe, true);
+ }
+ }
+
+ if (sfe.getValidUnsentAddresses() != null) {
+ Address[] address = sfe.getValidUnsentAddresses();
+ if (address.length > 0) {
+ recipients.clear();
+ for (Address addres : address) {
+ try {
+ recipients.add(new MailAddress(addres.toString()));
+ } catch (ParseException pe) {
+ // this should never happen ... we should have
+ // caught malformed addresses long before we
+ // got to this code.
+ logger.debug("Can't parse unsent address: " + pe.getMessage());
+ }
+ }
+ // Set the recipients for the mail
+ mail.setRecipients(recipients);
+ if (configuration.isDebug())
+ logger.debug("Unsent recipients: " + recipients);
+ if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
+ int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
+ deleteMessage = failMessage(mail, sfe, returnCode >= 500 && returnCode <= 599);
+ } else {
+ deleteMessage = failMessage(mail, sfe, false);
}
}
+ }
+
+
+ return deleteMessage;
+ }
+
+ private Boolean tryDeliver(Mail mail, Session session) throws MessagingException {
+ if (configuration.isDebug()) {
+ logger.debug("Attempting to deliver " + mail.getName());
+ }
+ MimeMessage message = mail.getMessage();
+
+ // Create an array of the recipients as InternetAddress objects
+ Collection<MailAddress> recipients = mail.getRecipients();
+ InternetAddress addr[] = new InternetAddress[recipients.size()];
+ int j = 0;
+ for (Iterator<MailAddress> i = recipients.iterator(); i.hasNext(); j++) {
+ MailAddress rcpt = i.next();
+ addr[j] = rcpt.toInternetAddress();
+ }
+
+ if (addr.length <= 0) {
+ logger.info("No recipients specified... not sure how this could have happened.");
+ return true;
+ }
- if (sfe.getValidUnsentAddresses() != null) {
- Address[] address = sfe.getValidUnsentAddresses();
- if (address.length > 0) {
- recipients.clear();
- for (Address addres : address) {
+ // Figure out which servers to try to send to. This collection
+ // will hold all the possible target servers
+ Iterator<HostAddress> targetServers;
+ if (configuration.getGatewayServer().isEmpty()) {
+ MailAddress rcpt = recipients.iterator().next();
+ String host = rcpt.getDomain();
+
+ // Lookup the possible targets
+ try {
+ targetServers = new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logger);
+ } catch (TemporaryResolutionException e) {
+ return handleTemporaryResolutionException(mail, host);
+ }
+ if (!targetServers.hasNext()) {
+ return handleNoTargetServer(mail, host);
+ }
+ } else {
+ targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer());
+ }
+
+ MessagingException lastError = null;
+
+ while (targetServers.hasNext()) {
+ HostAddress outgoingMailServer = targetServers.next();
+ try {
+ Properties props = session.getProperties();
+ if (mail.getSender() == null) {
+ props.put("mail.smtp.from", "<>");
+ } else {
+ String sender = mail.getSender().toString();
+ props.put("mail.smtp.from", sender);
+ }
+ logger.debug("Attempting delivery of " + mail.getName() + " to host " + outgoingMailServer.getHostName()
+ + " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from"));
+
+ // Many of these properties are only in later JavaMail versions
+ // "mail.smtp.ehlo" //default true
+ // "mail.smtp.auth" //default false
+ // "mail.smtp.dsn.ret" //default to nothing... appended as
+ // RET= after MAIL FROM line.
+ // "mail.smtp.dsn.notify" //default to nothing...appended as
+ // NOTIFY= after RCPT TO line.
+
+ SMTPTransport transport = null;
+ try {
+ transport = (SMTPTransport) session.getTransport(outgoingMailServer);
+ transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
+ try {
+ if (configuration.getAuthUser() != null) {
+ transport.connect(outgoingMailServer.getHostName(), configuration.getAuthUser(), configuration.getAuthPass());
+ } else {
+ transport.connect();
+ }
+ } catch (MessagingException me) {
+ // Any error on connect should cause the mailet to attempt
+ // to connect to the next SMTP server associated with this
+ // MX record. Just log the exception. We'll worry about
+ // failing the message at the end of the loop.
+
+ // Also include the stacktrace if debug is enabled. See JAMES-1257
+ if (configuration.isDebug()) {
+ logger.debug(me.getMessage(), me.getCause());
+ } else {
+ logger.info(me.getMessage());
+ }
+ continue;
+ }
+ // if the transport is a SMTPTransport (from sun) some
+ // performance enhancement can be done.
+ if (transport.getClass().getName().endsWith(".SMTPTransport")) {
+ // if the message is alredy 8bit or binary and the server doesn't support the 8bit extension it has
+ // to be converted to 7bit. Javamail api doesn't perform
+ // that conversion, but it is required to be a rfc-compliant smtp server.
+
+ // Temporarily disabled. See JAMES-638
+ if (!isSupports8bitmime(transport)) {
+ try {
+ convertTo7Bit(message);
+ } catch (IOException e) {
+ // An error has occured during the 7bit conversion.
+ // The error is logged and the message is sent anyway.
+
+ logger.error("Error during the conversion to 7 bit.", e);
+ }
+ }
+ } else {
+ // If the transport is not the one developed by Sun we are not sure of how it
+ // handles the 8 bit mime stuff, so I convert the message to 7bit.
try {
- recipients.add(new MailAddress(addres.toString()));
- } catch (ParseException pe) {
- // this should never happen ... we should have
- // caught malformed addresses long before we
- // got to this code.
- logger.debug("Can't parse unsent address: " + pe.getMessage());
+ convertTo7Bit(message);
+ } catch (IOException e) {
+ logger.error("Error during the conversion to 7 bit.", e);
}
}
- // Set the recipients for the mail
- mail.setRecipients(recipients);
- if (configuration.isDebug())
- logger.debug("Unsent recipients: " + recipients);
- if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
+ transport.sendMessage(message, addr);
+ } finally {
+ if (transport != null) {
+ try {
+ // James-899: transport.close() sends QUIT to the server; if that fails
+ // (e.g. because the server has already closed the connection) the message
+ // should be considered to be delivered because the error happened outside
+ // of the mail transaction (MAIL, RCPT, DATA).
+ transport.close();
+ } catch (MessagingException e) {
+ logger.error("Warning: could not close the SMTP transport after sending mail (" + mail.getName() + ") to " + outgoingMailServer.getHostName() + " at " + outgoingMailServer.getHost() + " for " + mail.getRecipients() + "; probably the server has already closed the "
+ + "connection. Message is considered to be delivered. Exception: " + e.getMessage());
+ }
+ transport = null;
+ }
+ }
+ logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() +
+ " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients());
+ outgoingMailsMetric.increment();
+ return true;
+ } catch (SendFailedException sfe) {
+ logSendFailedException(sfe);
+
+ if (sfe.getValidSentAddresses() != null) {
+ Address[] validSent = sfe.getValidSentAddresses();
+ if (validSent.length > 0) {
+ logger.debug( "Mail (" + mail.getName() + ") sent successfully for " + Arrays.asList(validSent));
+ }
+ }
+
+ /*
+ * SMTPSendFailedException introduced in JavaMail 1.3.2, and
+ * provides detailed protocol reply code for the operation
+ */
+ if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
+ try {
int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
- deleteMessage = failMessage(mail, sfe, returnCode >= 500 && returnCode <= 599);
- } else {
- deleteMessage = failMessage(mail, sfe, false);
+ // if 5xx, terminate this delivery attempt by
+ // re-throwing the exception.
+ if (returnCode >= 500 && returnCode <= 599)
+ throw sfe;
+ } catch (ClassCastException cce) {
+ } catch (IllegalArgumentException iae) {
}
}
- }
+ if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) {
+ if (configuration.isDebug())
+ logger.debug("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers");
+ lastError = sfe;
+ } else {
+ // There are no valid addresses left to send, so rethrow
+ throw sfe;
+ }
+ } catch (MessagingException me) {
+ // MessagingException are horribly difficult to figure out what actually happened.
+ logger.debug("Exception delivering message (" + mail.getName() + ") - " + me.getMessage());
+ if ((me.getNextException() != null) && (me.getNextException() instanceof IOException)) {
+ // This is more than likely a temporary failure
+
+ // If it's an IO exception with no nested exception, it's probably
+ // some socket or weird I/O related problem.
+ lastError = me;
+ } else {
+ // This was not a connection or I/O error particular to one
+ // SMTP server of an MX set. Instead, it is almost certainly
+ // a protocol level error. In this case we assume that this
+ // is an error we'd encounter with any of the SMTP servers
+ // associated with this MX record, and we pass the exception
+ // to the code in the outer block that determines its
+ // severity.
+ throw me;
+ }
+ }
+ } // end while
+ // If we encountered an exception while looping through,
+ // throw the last MessagingException we caught. We only
+ // do this if we were unable to send the message to any
+ // server. If sending eventually succeeded, we exit
+ // deliver() though the return at the end of the try
+ // block.
+ if (lastError != null) {
+ throw lastError;
+ }
+ return null;
+ }
- return deleteMessage;
- } catch (MessagingException ex) {
- // We should do a better job checking this... if the failure is a
- // general
- // connect exception, this is less descriptive than more specific
- // SMTP command
- // failure... have to lookup and see what are the various Exception
- // possibilities
-
- // Unable to deliver message after numerous tries... fail
- // accordingly
-
- // We check whether this is a 5xx error message, which
- // indicates a permanent failure (like account doesn't exist
- // or mailbox is full or domain is setup wrong).
- // We fail permanently if this was a 5xx error
- return failMessage(mail, ex, ('5' == ex.getMessage().charAt(0)));
- } catch (Exception ex) {
- logger.error("Generic exception = permanent failure: "+ex.getMessage(), ex);
- // Generic exception = permanent failure
- return failMessage(mail, ex, true);
+ private boolean isSupports8bitmime(SMTPTransport transport) {
+ boolean supports8bitmime = false;
+ try {
+ Method supportsExtension = transport.getClass().getMethod("supportsExtension", new Class[]{String.class});
+ supports8bitmime = (Boolean) supportsExtension.invoke(transport, "8BITMIME");
+ } catch (NoSuchMethodException nsme) {
+ // An SMTPAddressFailedException with no
+ // getAddress method.
+ } catch (IllegalAccessException iae) {
+ } catch (IllegalArgumentException iae) {
+ } catch (InvocationTargetException ite) {
+ // Other issues with getAddress invokation.
}
+ return supports8bitmime;
+ }
- /*
- * If we get here, we've exhausted the loop of servers without sending
- * the message or throwing an exception. One case where this might
- * happen is if we get a MessagingException on each transport.connect(),
- * e.g., if there is only one server and we get a connect exception.
- */
- return failMessage(mail, new MessagingException("No mail server(s) available at this time."), false);
+ private boolean handleTemporaryResolutionException(Mail mail, String host) {
+ logger.info("Temporary problem looking up mail server for host: " + host);
+ // temporary problems
+ return failMessage(mail,
+ new MessagingException("Temporary problem looking up mail server for host: " + host + ". I cannot determine where to send this message."),
+ false);
+ }
+
+ private boolean handleNoTargetServer(Mail mail, String host) {
+ logger.info("No mail server found for: " + host);
+ String exceptionBuffer = "There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.";
+
+ int retry = 0;
+ try {
+ retry = Integer.parseInt(mail.getErrorMessage());
+ } catch (NumberFormatException e) {
+ // Unable to parse retryCount
+ }
+ if (retry == 0 || retry > configuration.getDnsProblemRetry()) {
+ // The domain has no dns entry.. Return a permanent error
+ return failMessage(mail, new MessagingException(exceptionBuffer), true);
+ } else {
+ return failMessage(mail, new MessagingException(exceptionBuffer), false);
+ }
}
- /**
- * Returns the javamail Session object.
- *
- * @param props
- * @return the java mail session
- */
protected Session obtainSession(Properties props) {
return Session.getInstance(props);
}
-
- /**
- * This method returns, given a retry-count, the next delay time to use.
- *
- * @param retry_count the current retry_count.
- * @return the next delay time to use, given the retry count
- */
private long getNextDelay(int retry_count) {
if (retry_count > configuration.getDelayTimes().size()) {
return Delay.DEFAULT_DELAY_TIME;
@@ -617,15 +567,6 @@ public class DeliveryRunnable implements Runnable {
}
- /**
- * Utility method used to invoke getters for javamail implementation
- * specific classes.
- *
- * @param target the object whom method will be invoked
- * @param getter the no argument method name
- * @return the result object
- * @throws IllegalStateException on invocation error
- */
private Object invokeGetter(Object target, String getter) {
try {
Method getAddress = target.getClass().getMethod(getter);
@@ -640,10 +581,6 @@ public class DeliveryRunnable implements Runnable {
return new IllegalStateException("Exception invoking " + getter + " on a " + target.getClass() + " object");
}
- /*
- * private method to log the extended SendFailedException introduced in
- * JavaMail 1.3.2.
- */
private void logSendFailedException(SendFailedException sfe) {
if (configuration.isDebug()) {
MessagingException me = sfe;
@@ -732,28 +669,7 @@ public class DeliveryRunnable implements Runnable {
* @return boolean Whether the message failed fully and can be deleted
*/
private boolean failMessage(Mail mail, Exception ex, boolean permanent) {
- StringWriter sout = new StringWriter();
- PrintWriter out = new PrintWriter(sout, true);
- if (permanent) {
- out.print("Permanent");
- } else {
- out.print("Temporary");
- }
-
- String exceptionLog = exceptionToLogString(ex);
-
- StringBuilder logBuffer = new StringBuilder(64).append(" exception delivering mail (").append(mail.getName());
-
- if (exceptionLog != null) {
- logBuffer.append(". ");
- logBuffer.append(exceptionLog);
- }
-
- logBuffer.append(": ");
- out.print(logBuffer.toString());
- if (configuration.isDebug())
- ex.printStackTrace(out);
- logger.debug(sout.toString());
+ logger.debug(messageComposer.composeFailLogMessage(mail, ex, permanent));
if (!permanent) {
if (!mail.getState().equals(Mail.ERROR)) {
mail.setState(Mail.ERROR);
@@ -769,15 +685,13 @@ public class DeliveryRunnable implements Runnable {
}
if (retries < configuration.getMaxRetries()) {
- logBuffer = new StringBuilder(128).append("Storing message ").append(mail.getName()).append(" into outgoing after ").append(retries).append(" retries");
- logger.debug(logBuffer.toString());
+ logger.debug("Storing message " + mail.getName() + " into outgoing after " + retries + " retries");
++retries;
mail.setErrorMessage(retries + "");
mail.setLastUpdated(new Date());
return false;
} else {
- logBuffer = new StringBuilder(128).append("Bouncing message ").append(mail.getName()).append(" after ").append(retries).append(" retries");
- logger.debug(logBuffer.toString());
+ logger.debug("Bouncing message " + mail.getName() + " after " + retries + " retries");
}
}
@@ -789,22 +703,13 @@ public class DeliveryRunnable implements Runnable {
if (configuration.getBounceProcessor() != null) {
// do the new DSN bounce
// setting attributes for DSN mailet
- String cause;
- if (ex instanceof MessagingException) {
- cause = getErrorMsg((MessagingException) ex);
- } else {
- cause = ex.getMessage();
- }
- mail.setAttribute("delivery-error", cause);
+ mail.setAttribute("delivery-error", messageComposer.getErrorMsg(ex));
mail.setState(configuration.getBounceProcessor());
- // re-insert the mail into the spool for getting it passed to the
- // dsn-processor
- MailetContext mc = mailetContext;
+ // re-insert the mail into the spool for getting it passed to the dsn-processor
try {
- mc.sendMail(mail);
+ mailetContext.sendMail(mail);
} catch (MessagingException e) {
- // we shouldn't get an exception, because the mail was already
- // processed
+ // we shouldn't get an exception, because the mail was already processed
logger.debug("Exception re-inserting failed mail: ", e);
}
} else {
@@ -815,126 +720,10 @@ public class DeliveryRunnable implements Runnable {
}
- /**
- * Try to return a usefull logString created of the Exception which was
- * given. Return null if nothing usefull could be done
- *
- * @param e The MessagingException to use
- * @return logString
- */
- private String exceptionToLogString(Exception e) {
- if (e.getClass().getName().endsWith(".SMTPSendFailedException")) {
- return "RemoteHost said: " + e.getMessage();
- } else if (e instanceof SendFailedException) {
- SendFailedException exception = (SendFailedException) e;
-
- // No error
- if (exception.getInvalidAddresses().length == 0 && exception.getValidUnsentAddresses().length == 0)
- return null;
-
- Exception ex;
- StringBuilder sb = new StringBuilder();
- boolean smtpExFound = false;
- sb.append("RemoteHost said:");
-
- if (e instanceof MessagingException)
- while ((ex = ((MessagingException) e).getNextException()) != null && ex instanceof MessagingException) {
- e = ex;
- if (ex.getClass().getName().endsWith(".SMTPAddressFailedException")) {
- try {
- InternetAddress ia = (InternetAddress) invokeGetter(ex, "getAddress");
- sb.append(" ( ").append(ia).append(" - [").append(ex.getMessage().replaceAll("\\n", "")).append("] )");
- smtpExFound = true;
- } catch (IllegalStateException ise) {
- // Error invoking the getAddress method
- } catch (ClassCastException cce) {
- // The getAddress method returned something
- // different than InternetAddress
- }
- }
- }
- if (!smtpExFound) {
- boolean invalidAddr = false;
- sb.append(" ( ");
-
- if (exception.getInvalidAddresses().length > 0) {
- sb.append(Arrays.toString(exception.getInvalidAddresses()));
- invalidAddr = true;
- }
- if (exception.getValidUnsentAddresses().length > 0) {
- if (invalidAddr)
- sb.append(" ");
- sb.append(Arrays.toString(exception.getValidUnsentAddresses()));
- }
- sb.append(" - [");
- sb.append(exception.getMessage().replaceAll("\\n", ""));
- sb.append("] )");
- }
- return sb.toString();
- }
- return null;
- }
-
- /**
- * Utility method for getting the error message from the (nested) exception.
- *
- * @param me MessagingException
- * @return error message
- */
- protected String getErrorMsg(MessagingException me) {
- if (me.getNextException() == null) {
- return me.getMessage().trim();
- } else {
- Exception ex1 = me.getNextException();
- return ex1.getMessage().trim();
- }
- }
-
private void bounce(Mail mail, Exception ex) {
- StringWriter sout = new StringWriter();
- PrintWriter out = new PrintWriter(sout, true);
- String machine;
- try {
- machine = configuration.getHeloNameProvider().getHeloName();
-
- } catch (Exception e) {
- machine = "[address unknown]";
- }
- String bounceBuffer = "Hi. This is the James mail server at " + machine + ".";
- out.println(bounceBuffer);
- out.println("I'm afraid I wasn't able to deliver your message to the following addresses.");
- out.println("This is a permanent error; I've given up. Sorry it didn't work out. Below");
- out.println("I include the list of recipients and the reason why I was unable to deliver");
- out.println("your message.");
- out.println();
- for (MailAddress mailAddress : mail.getRecipients()) {
- out.println(mailAddress);
- }
- if (ex instanceof MessagingException) {
- if (((MessagingException) ex).getNextException() == null) {
- out.println(ex.getMessage().trim());
- } else {
- Exception ex1 = ((MessagingException) ex).getNextException();
- if (ex1 instanceof SendFailedException) {
- out.println("Remote mail server told me: " + ex1.getMessage().trim());
- } else if (ex1 instanceof UnknownHostException) {
- out.println("Unknown host: " + ex1.getMessage().trim());
- out.println("This could be a DNS server error, a typo, or a problem with the recipient's mail server.");
- } else if (ex1 instanceof ConnectException) {
- // Already formatted as "Connection timed out: connect"
- out.println(ex1.getMessage().trim());
- } else if (ex1 instanceof SocketException) {
- out.println("Socket exception: " + ex1.getMessage().trim());
- } else {
- out.println(ex1.getMessage().trim());
- }
- }
- }
- out.println();
-
logger.debug("Sending failure message " + mail.getName());
try {
- mailetContext.bounce(mail, sout.toString());
+ mailetContext.bounce(mail, messageComposer.composeForBounce(mail, ex));
} catch (MessagingException me) {
logger.debug("Encountered unexpected messaging exception while bouncing message: " + me.getMessage());
} catch (Exception e) {
@@ -956,8 +745,6 @@ public class DeliveryRunnable implements Runnable {
* @since v2.2.0a16-unstable
*/
private Iterator<HostAddress> getGatewaySMTPHostAddresses(Collection<String> gatewayServers) {
- Iterator<String> gateways = gatewayServers.iterator();
-
- return new MXHostAddressIterator(gateways, dnsServer, false, logger);
+ return new MXHostAddressIterator(gatewayServers.iterator(), dnsServer, false, logger);
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[06/50] [abbrv] james-project git commit: JAMES-1877 Refactor Delays
related class
Posted by ro...@apache.org.
JAMES-1877 Refactor Delays related class
- also add support for no unit in TimeConverter
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/61c6309f
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/61c6309f
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/61c6309f
Branch: refs/heads/master
Commit: 61c6309f65d43889f98c1984d3f040603f43d9d0
Parents: 8a8af97
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Nov 30 00:44:17 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 14:40:34 2017 +0700
----------------------------------------------------------------------
.../org/apache/james/util/TimeConverter.java | 3 +-
.../apache/james/util/TimeConverterTest.java | 10 ++
.../james/transport/mailets/RemoteDelivery.java | 7 +-
.../transport/mailets/remoteDelivery/Delay.java | 137 ++++++-------------
.../remoteDelivery/DelaysAndMaxRetry.java | 107 +++++++--------
.../mailets/remoteDelivery/Repeat.java | 37 +++++
.../mailets/remoteDelivery/DelayTest.java | 37 ++---
.../remoteDelivery/DelaysAndMaxRetryTest.java | 4 +-
.../mailets/remoteDelivery/RepeatTest.java | 58 ++++++++
9 files changed, 226 insertions(+), 174 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/61c6309f/server/container/util/src/main/java/org/apache/james/util/TimeConverter.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/TimeConverter.java b/server/container/util/src/main/java/org/apache/james/util/TimeConverter.java
index 2a877b7..162fef5 100644
--- a/server/container/util/src/main/java/org/apache/james/util/TimeConverter.java
+++ b/server/container/util/src/main/java/org/apache/james/util/TimeConverter.java
@@ -27,12 +27,13 @@ public class TimeConverter {
private static final HashMap<String, Integer> multipliers = new HashMap<String, Integer>(10);
- private static final String PATTERN_STRING = "\\s*([0-9]+)\\s*([a-z,A-Z]+)\\s*";
+ private static final String PATTERN_STRING = "\\s*([0-9]+)\\s*([a-z,A-Z]*)\\s*";
private static Pattern PATTERN = null;
static {
// add allowed units and their respective multiplier
+ multipliers.put("", 1);
multipliers.put("ms", 1);
multipliers.put("msec", 1);
multipliers.put("msecs", 1);
http://git-wip-us.apache.org/repos/asf/james-project/blob/61c6309f/server/container/util/src/test/java/org/apache/james/util/TimeConverterTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/TimeConverterTest.java b/server/container/util/src/test/java/org/apache/james/util/TimeConverterTest.java
index b05a935..fc13f58 100644
--- a/server/container/util/src/test/java/org/apache/james/util/TimeConverterTest.java
+++ b/server/container/util/src/test/java/org/apache/james/util/TimeConverterTest.java
@@ -25,6 +25,16 @@ import java.util.concurrent.TimeUnit;
import org.junit.Test;
public class TimeConverterTest {
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenNoUnitAmountAsString() {
+ //Given
+ long expected = 2;
+ //When
+ long actual = TimeConverter.getMilliSeconds("2");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
@Test
public void getMilliSecondsShouldConvertValueWhenMsecUnit() {
http://git-wip-us.apache.org/repos/asf/james-project/blob/61c6309f/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index 9ffd164..88f8ea7 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -33,6 +33,7 @@ import java.util.Collection;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
@@ -166,7 +167,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
/**
* List of Delay Times. Controls frequency of retry attempts.
*/
- private long[] delayTimes;
+ private List<Long> delayTimes;
/**
* Maximum no. of retries (Defaults to 5).
@@ -392,10 +393,10 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
* @return the next delay time to use, given the retry count
*/
private long getNextDelay(int retry_count) {
- if (retry_count > delayTimes.length) {
+ if (retry_count > delayTimes.size()) {
return Delay.DEFAULT_DELAY_TIME;
}
- return delayTimes[retry_count - 1];
+ return delayTimes.get(retry_count - 1);
}
@Override
http://git-wip-us.apache.org/repos/asf/james-project/blob/61c6309f/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Delay.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Delay.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Delay.java
index c066a63..3f50ea7 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Delay.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Delay.java
@@ -19,133 +19,82 @@
package org.apache.james.transport.mailets.remoteDelivery;
-import java.util.Locale;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
import javax.mail.MessagingException;
-import org.apache.james.transport.util.Patterns;
import org.apache.james.util.TimeConverter;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
-/**
- * This class is used to hold a delay time and its corresponding number of
- * retries.
- */
public class Delay {
-
- /**
- * Default Delay Time (Default is 6*60*60*1000 Milliseconds (6 hours)).
- */
- public static final long DEFAULT_DELAY_TIME = 21600000;
- public static final int DEFAULT_ATTEMPTS = 1;
- /**
- * Pattern to match [attempts*]delay[units].
- */
- private static final String PATTERN_STRING = "\\s*([0-9]*\\s*[\\*])?\\s*([0-9]+)\\s*([a-z,A-Z]*)\\s*";
- private static final Pattern PATTERN = Patterns.compilePatternUncheckedException(PATTERN_STRING);
-
- private int attempts = DEFAULT_ATTEMPTS;
-
- private long delayTime = DEFAULT_DELAY_TIME;
-
/**
- * <p>
- * This constructor expects Strings of the form
- * "[attempt\*]delaytime[unit]".
- * </p>
- * <p>
- * The optional attempt is the number of tries this delay should be used
- * (default = 1). The unit, if present, must be one of
- * (msec,sec,minute,hour,day). The default value of unit is 'msec'.
- * </p>
- * <p>
- * The constructor multiplies the delaytime by the relevant multiplier
- * for the unit, so the delayTime instance variable is always in msec.
- * </p>
+ * <p> The optional attempt is the number of tries this delay should be used (default = 1).
+ * The delayTime is parsed by {@link TimeConverter}</p>
*
- * @param initString the string to initialize this Delay object from
+ * @param initString the string to initialize this Delay object from. It has the form "[attempt\*]delaytime[unit]"
*/
- public Delay(String initString) throws MessagingException {
- // Default unit value to 'msec'.
- String unit = "msec";
-
- Matcher res = PATTERN.matcher(initString);
- if (res.matches()) {
- // The capturing groups will now hold:
- // at 1: attempts * (if present)
- // at 2: delaytime
- // at 3: unit (if present)
- if (res.group(1) != null && !res.group(1).equals("")) {
- // We have an attempt *
- String attemptMatch = res.group(1);
-
- // Strip the * and whitespace.
- attemptMatch = attemptMatch.substring(0, attemptMatch.length() - 1).trim();
- attempts = Integer.parseInt(attemptMatch);
- }
-
- delayTime = Long.parseLong(res.group(2));
-
- if (!res.group(3).equals("")) {
- // We have a value for 'unit'.
- unit = res.group(3).toLowerCase(Locale.US);
- }
- } else {
- throw new MessagingException(initString + " does not match " + PATTERN_STRING);
+ public static Delay from(String initString) throws MessagingException {
+ if (Strings.isNullOrEmpty(initString)) {
+ throw new NumberFormatException("Null or Empty strings are not permitted");
}
+ List<String> parts = Splitter.on('*').splitToList(initString);
- // calculate delayTime.
- try {
- delayTime = TimeConverter.getMilliSeconds(delayTime, unit);
- } catch (NumberFormatException e) {
- throw new MessagingException(e.getMessage());
+ if (parts.size() == 1) {
+ return new Delay(DEFAULT_ATTEMPTS, TimeConverter.getMilliSeconds(parts.get(0)));
+ }
+ if (parts.size() == 2) {
+ int attempts = Integer.parseInt(parts.get(0));
+ if (attempts < 0) {
+ throw new MessagingException("Number of attempts negative in " + initString);
+ }
+ return new Delay(attempts, TimeConverter.getMilliSeconds(parts.get(1)));
}
+ throw new MessagingException(initString + " contains too much parts");
}
- /**
- * This constructor makes a default Delay object with attempts = 1 and
- * delayTime = DEFAULT_DELAY_TIME.
- */
+ public static final long DEFAULT_DELAY_TIME = TimeUnit.HOURS.toMillis(6);
+ public static final int DEFAULT_ATTEMPTS = 1;
+
+ private final int attempts;
+ private final long delayTimeInMs;
+
public Delay() {
+ this(DEFAULT_ATTEMPTS, DEFAULT_DELAY_TIME);
}
@VisibleForTesting
Delay(int attempts, long delayTime) {
this.attempts = attempts;
- this.delayTime = delayTime;
+ this.delayTimeInMs = delayTime;
}
- /**
- * @return the delayTime for this Delay
- */
- public long getDelayTime() {
- return delayTime;
+ public long getDelayTimeInMs() {
+ return delayTimeInMs;
}
- /**
- * @return the number attempts this Delay should be used.
- */
public int getAttempts() {
return attempts;
}
- /**
- * Set the number attempts this Delay should be used.
- */
- public void setAttempts(int value) {
- attempts = value;
+ public List<Long> getExpendendDelays() {
+ return Repeat.repeat(delayTimeInMs, attempts);
}
- /**
- * Pretty prints this Delay
- */
@Override
public String toString() {
- return getAttempts() + "*" + getDelayTime() + "msecs";
+ return MoreObjects.toStringHelper(this)
+ .add("attempts", attempts)
+ .add("delayTime", delayTimeInMs)
+ .toString();
}
@Override
@@ -154,13 +103,13 @@ public class Delay {
Delay that = (Delay) o;
return Objects.equal(this.attempts, that.attempts)
- && Objects.equal(this.delayTime, that.delayTime);
+ && Objects.equal(this.delayTimeInMs, that.delayTimeInMs);
}
return false;
}
@Override
public int hashCode() {
- return Objects.hashCode(attempts, delayTime);
+ return Objects.hashCode(attempts, delayTimeInMs);
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/61c6309f/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetry.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetry.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetry.java
index 10b6cca..16ae192 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetry.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetry.java
@@ -19,10 +19,7 @@
package org.apache.james.transport.mailets.remoteDelivery;
-import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
-import java.util.StringTokenizer;
import javax.mail.MessagingException;
@@ -31,72 +28,75 @@ import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Objects;
+import com.google.common.base.Splitter;
+import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
public class DelaysAndMaxRetry {
private static final Logger LOGGER = LoggerFactory.getLogger(DelaysAndMaxRetry.class);
- public static DelaysAndMaxRetry from(int intendedMaxRetries, String delaysAsString) throws MessagingException {
- // Create list of Delay Times.
- ArrayList<Delay> delayTimesList = createDelayList(delaysAsString);
+ public static DelaysAndMaxRetry defaults() {
+ return new DelaysAndMaxRetry(RemoteDeliveryConfiguration.DEFAULT_MAX_RETRY, Repeat.repeat(new Delay(), RemoteDeliveryConfiguration.DEFAULT_MAX_RETRY));
+ }
- // Check consistency of 'maxRetries' with delayTimesList attempts.
- int totalAttempts = calcTotalAttempts(delayTimesList);
+ public static DelaysAndMaxRetry from(int intendedMaxRetries, String delaysAsString) throws MessagingException {
+ List<Delay> delayTimesList = createDelayList(delaysAsString);
+ int totalAttempts = computeTotalAttempts(delayTimesList);
+ return getDelaysAndMaxRetry(intendedMaxRetries, totalAttempts, delayTimesList);
+ }
- // If inconsistency found, fix it.
+ private static DelaysAndMaxRetry getDelaysAndMaxRetry(int intendedMaxRetries, int totalAttempts, List<Delay> delayTimesList) throws MessagingException {
if (totalAttempts > intendedMaxRetries) {
- LOGGER.warn("Total number of delayTime attempts exceeds maxRetries specified. " + " Increasing maxRetries from " + intendedMaxRetries + " to " + totalAttempts);
+ LOGGER.warn("Total number of delayTime attempts exceeds maxRetries specified. Increasing maxRetries from {} to {}", intendedMaxRetries, totalAttempts);
return new DelaysAndMaxRetry(totalAttempts, delayTimesList);
} else {
int extra = intendedMaxRetries - totalAttempts;
- if (extra != 0) {
- LOGGER.warn("maxRetries is larger than total number of attempts specified. " + "Increasing last delayTime with " + extra + " attempts ");
-
- // Add extra attempts to the last delayTime.
- if (delayTimesList.size() != 0) {
- // Get the last delayTime.
- Delay delay = delayTimesList.get(delayTimesList.size() - 1);
-
- // Increase no. of attempts.
- delay.setAttempts(delay.getAttempts() + extra);
- LOGGER.warn("Delay of " + delay.getDelayTime() + " msecs is now attempted: " + delay.getAttempts() + " times");
- } else {
- throw new MessagingException("No delaytimes, cannot continue");
- }
+ if (extra > 0) {
+ LOGGER.warn("maxRetries is larger than total number of attempts specified. Increasing last delayTime with {} attempts ", extra);
+ return addExtraAttemptToLastDelay(intendedMaxRetries, extra, delayTimesList);
}
return new DelaysAndMaxRetry(intendedMaxRetries, delayTimesList);
}
}
- private static ArrayList<Delay> createDelayList(String delaysAsString) {
- ArrayList<Delay> delayTimesList = new ArrayList<Delay>();
+ private static DelaysAndMaxRetry addExtraAttemptToLastDelay(int intendedMaxRetries, int extra, List<Delay> delayTimesList) throws MessagingException {
+ if (delayTimesList.size() != 0) {
+ Delay lastDelay = delayTimesList.get(delayTimesList.size() - 1);
+ LOGGER.warn("Delay of {} msecs is now attempted: {} times", lastDelay.getDelayTimeInMs(), lastDelay.getAttempts());
+ return new DelaysAndMaxRetry(intendedMaxRetries,
+ ImmutableList.copyOf(
+ Iterables.concat(
+ Iterables.limit(delayTimesList, delayTimesList.size() - 1),
+ ImmutableList.of(new Delay(lastDelay.getAttempts() + extra, lastDelay.getDelayTimeInMs())))));
+ } else {
+ throw new MessagingException("No delaytimes, cannot continue");
+ }
+ }
+
+ private static List<Delay> createDelayList(String delaysAsString) {
+ if (delaysAsString == null) {
+ // Use default delayTime.
+ return ImmutableList.of(new Delay());
+ }
+ ImmutableList<String> delayStrings = FluentIterable.from(Splitter.on(',')
+ .omitEmptyStrings()
+ .split(delaysAsString))
+ .toList();
+ ImmutableList.Builder<Delay> builder = ImmutableList.builder();
try {
- if (delaysAsString != null) {
-
- // Split on commas
- StringTokenizer st = new StringTokenizer(delaysAsString, ",");
- while (st.hasMoreTokens()) {
- String delayTime = st.nextToken();
- delayTimesList.add(new Delay(delayTime));
- }
- } else {
- // Use default delayTime.
- delayTimesList.add(new Delay());
+ for (String s : delayStrings) {
+ builder.add(Delay.from(s));
}
+ return builder.build();
} catch (Exception e) {
- LOGGER.warn("Invalid delayTime setting: " + delaysAsString);
+ LOGGER.warn("Invalid delayTime setting: {}", delaysAsString);
+ return builder.build();
}
- return delayTimesList;
}
- /**
- * Calculates Total no. of attempts for the specified delayList.
- *
- * @param delayList list of 'Delay' objects
- * @return total no. of retry attempts
- */
- private static int calcTotalAttempts(List<Delay> delayList) {
+ private static int computeTotalAttempts(List<Delay> delayList) {
int sum = 0;
for (Delay delay : delayList) {
sum += delay.getAttempts();
@@ -136,17 +136,12 @@ public class DelaysAndMaxRetry {
* @param list the list to expand
* @return the expanded list
*/
- public long[] getExpendedDelays() {
- long[] delaysAsLong = new long[calcTotalAttempts(delays)];
- Iterator<Delay> i = delays.iterator();
- int idx = 0;
- while (i.hasNext()) {
- Delay delay = i.next();
- for (int j = 0; j < delay.getAttempts(); j++) {
- delaysAsLong[idx++] = delay.getDelayTime();
- }
+ public List<Long> getExpendedDelays() {
+ ImmutableList.Builder<Long> builder = ImmutableList.builder();
+ for (Delay delay: delays) {
+ builder.addAll(delay.getExpendendDelays());
}
- return delaysAsLong;
+ return builder.build();
}
@Override
http://git-wip-us.apache.org/repos/asf/james-project/blob/61c6309f/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Repeat.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Repeat.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Repeat.java
new file mode 100644
index 0000000..0252214
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Repeat.java
@@ -0,0 +1,37 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.util.List;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class Repeat {
+
+ public static <T> List<T> repeat(T element, int times) {
+ Preconditions.checkArgument(times > 0, "Times argument should be strictly positive");
+ return ImmutableList.copyOf(
+ Iterables.limit(
+ Iterables.cycle(element), times));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/61c6309f/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
index f23c918..b940c3e 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
@@ -40,78 +40,79 @@ public class DelayTest {
@Test
public void stringConstructorShouldWorkForNumbers() throws Exception {
- assertThat(new Delay("36")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 36));
+ assertThat(Delay.from("36")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 36));
}
@Test
public void stringConstructorShouldWorkForZero() throws Exception {
- assertThat(new Delay("0")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 0));
+ assertThat(Delay.from("0")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 0));
}
@Test
- public void stringConstructorShouldDefaultToZeroForNegatives() throws Exception {
- assertThat(new Delay("0")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 0));
+ public void stringConstructorShouldThrowOnNegativeNumbers() throws Exception {
+ expectedException.expect(NumberFormatException.class);
+ assertThat(Delay.from("-1s")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 0));
}
@Test
public void stringConstructorShouldWorkForNumberAndSecond() throws Exception {
- assertThat(new Delay("1s")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 1000));
+ assertThat(Delay.from("1s")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 1000));
}
@Test
public void stringConstructorShouldWorkForNumberAndAttempts() throws Exception {
- assertThat(new Delay("2*36")).isEqualTo(new Delay(2, 36));
+ assertThat(Delay.from("2*36")).isEqualTo(new Delay(2, 36));
}
@Test
public void stringConstructorShouldWorkForNumberAndZeroAttempts() throws Exception {
- assertThat(new Delay("0*36")).isEqualTo(new Delay(0, 36));
+ assertThat(Delay.from("0*36")).isEqualTo(new Delay(0, 36));
}
@Test
public void stringConstructorShouldThrowOnNegativeAttempts() throws Exception {
expectedException.expect(MessagingException.class);
- new Delay("-1*36");
+ Delay.from("-1*36");
}
@Test
public void stringConstructorShouldThrowWhenAttemptsOmitted() throws Exception {
expectedException.expect(NumberFormatException.class);
- new Delay("*36");
+ Delay.from("*36");
}
@Test
public void stringConstructorShouldThrowWhenDelayOmitted() throws Exception {
- expectedException.expect(MessagingException.class);
+ expectedException.expect(NumberFormatException.class);
- new Delay("2*");
+ Delay.from("2*");
}
@Test
public void stringConstructorShouldWorkForNumberAttemptsAndUnit() throws Exception {
- assertThat(new Delay("2*36s")).isEqualTo(new Delay(2, 36000));
+ assertThat(Delay.from("2*36s")).isEqualTo(new Delay(2, 36000));
}
@Test
public void stringConstructorShouldThrowOnInvalidInput() throws Exception {
- expectedException.expect(MessagingException.class);
+ expectedException.expect(NumberFormatException.class);
- new Delay("invalid");
+ Delay.from("invalid");
}
@Test
public void stringConstructorShouldThrowOnInvalidUnit() throws Exception {
- expectedException.expect(MessagingException.class);
+ expectedException.expect(NumberFormatException.class);
- new Delay("36invalid");
+ Delay.from("36invalid");
}
@Test
public void stringConstructorShouldThrowOnEmptyString() throws Exception {
- expectedException.expect(MessagingException.class);
+ expectedException.expect(NumberFormatException.class);
- new Delay("");
+ Delay.from("");
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/61c6309f/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetryTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetryTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetryTest.java
index da4ecda..dbab3c4 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetryTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetryTest.java
@@ -124,13 +124,13 @@ public class DelaysAndMaxRetryTest {
public void getExpendedDelaysShouldExpandSingleDelays() throws Exception {
DelaysAndMaxRetry testee = DelaysAndMaxRetry.from(3, "1*1S,1*2S,1*5S");
- assertThat(testee.getExpendedDelays()).containsExactly(1000, 2000, 5000);
+ assertThat(testee.getExpendedDelays()).containsExactly(1000L, 2000L, 5000L);
}
@Test
public void getExpendedDelaysShouldExpandMultipleDelays() throws Exception {
DelaysAndMaxRetry testee = DelaysAndMaxRetry.from(3, "1*1S,2*2S,2*5S");
- assertThat(testee.getExpendedDelays()).containsExactly(1000, 2000, 2000, 5000, 5000);
+ assertThat(testee.getExpendedDelays()).containsExactly(1000L, 2000L, 2000L, 5000L, 5000L);
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/61c6309f/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RepeatTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RepeatTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RepeatTest.java
new file mode 100644
index 0000000..13b9968
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RepeatTest.java
@@ -0,0 +1,58 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class RepeatTest {
+
+ public static final String ELEMENT = "a";
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void repeatShouldThrowOnNegativeTimes() {
+ expectedException.expect(IllegalArgumentException.class);
+
+ Repeat.repeat(new Object(), -1);
+ }
+
+ @Test
+ public void repeatShouldThrowOnZeroTimes() {
+ expectedException.expect(IllegalArgumentException.class);
+
+ Repeat.repeat(new Object(), 0);
+ }
+
+ @Test
+ public void repeatShouldWorkWithOneElement() {
+ assertThat(Repeat.repeat(ELEMENT, 1)).containsExactly(ELEMENT);
+ }
+
+ @Test
+ public void repeatShouldWorkWithTwoElements() {
+ assertThat(Repeat.repeat(ELEMENT, 2)).containsExactly(ELEMENT, ELEMENT);
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[11/50] [abbrv] james-project git commit: JAMES-1877 Tests then
refactoring for RemoteDelivery
Posted by ro...@apache.org.
JAMES-1877 Tests then refactoring for RemoteDelivery
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/6774b877
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/6774b877
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/6774b877
Branch: refs/heads/master
Commit: 6774b8775e8ce5d81dc72b4c15dc9109f3300e67
Parents: 4a5a4ba
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 11:05:13 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:39 2017 +0700
----------------------------------------------------------------------
mailet/base/pom.xml | 11 +
.../org/apache/mailet/base/test/FakeMail.java | 56 +++++
.../apache/mailet/base/test/FakeMailTest.java | 41 ++++
.../transport/mailets/ToProcessorTest.java | 12 +-
.../james/transport/mailets/RemoteDelivery.java | 143 ++++++-------
.../remoteDelivery/RemoteDeliveryTest.java | 208 +++++++++++++++++++
6 files changed, 390 insertions(+), 81 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/6774b877/mailet/base/pom.xml
----------------------------------------------------------------------
diff --git a/mailet/base/pom.xml b/mailet/base/pom.xml
index 0c47808..fdec517 100644
--- a/mailet/base/pom.xml
+++ b/mailet/base/pom.xml
@@ -71,6 +71,17 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>nl.jqno.equalsverifier</groupId>
+ <artifactId>equalsverifier</artifactId>
+ <version>1.7.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
http://git-wip-us.apache.org/repos/asf/james-project/blob/6774b877/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java
index acccec3..661882a 100644
--- a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java
+++ b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java
@@ -38,9 +38,12 @@ import javax.mail.internet.MimeMessage;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -176,6 +179,14 @@ public class FakeMail implements Mail {
return FakeMail.builder().build();
}
+ private static Map<String, Serializable> attributes(Mail mail) {
+ ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.builder();
+ for (String attributeName: ImmutableList.copyOf(mail.getAttributeNames())) {
+ builder.put(attributeName, mail.getAttribute(attributeName));
+ }
+ return builder.build();
+ }
+
private MimeMessage msg;
private Collection<MailAddress> recipients;
private String name;
@@ -201,6 +212,11 @@ public class FakeMail implements Mail {
this.remoteAddr = remoteAddr;
}
+ public FakeMail(Mail mail) throws MessagingException {
+ this(mail.getMessage(), Lists.newArrayList(mail.getRecipients()), mail.getName(), mail.getSender(), mail.getState(), mail.getErrorMessage(),
+ mail.getLastUpdated(), attributes(mail), mail.getMessageSize(), mail.getRemoteAddr());
+ }
+
@Override
public String getName() {
return name;
@@ -322,4 +338,44 @@ public class FakeMail implements Mail {
public void setMessageSize(long size) {
this.size = size;
}
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof FakeMail) {
+ FakeMail that = (FakeMail) o;
+
+ return Objects.equal(this.size, that.size)
+ && Objects.equal(this.msg, that.msg)
+ && Objects.equal(this.recipients, that.recipients)
+ && Objects.equal(this.name, that.name)
+ && Objects.equal(this.sender, that.sender)
+ && Objects.equal(this.state, that.state)
+ && Objects.equal(this.errorMessage, that.errorMessage)
+ && Objects.equal(this.lastUpdated, that.lastUpdated)
+ && Objects.equal(this.attributes, that.attributes)
+ && Objects.equal(this.remoteAddr, that.remoteAddr);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hashCode(msg, name, sender, recipients, state, errorMessage, lastUpdated, attributes, size, recipients, remoteAddr);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("msg", msg)
+ .add("recipients", recipients)
+ .add("name", name)
+ .add("sender", sender)
+ .add("state", state)
+ .add("errorMessage", errorMessage)
+ .add("lastUpdated", lastUpdated)
+ .add("attributes", attributes)
+ .add("size", size)
+ .add("remoteAddr", remoteAddr)
+ .toString();
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/6774b877/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailTest.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailTest.java b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailTest.java
new file mode 100644
index 0000000..fc0c03c
--- /dev/null
+++ b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailTest.java
@@ -0,0 +1,41 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.mailet.base.test;
+
+import static org.mockito.Mockito.mock;
+
+import javax.mail.internet.MimeMessage;
+
+import org.junit.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+import nl.jqno.equalsverifier.Warning;
+
+public class FakeMailTest {
+
+ @Test
+ public void beanShouldRespectBeanContract() {
+ EqualsVerifier.forClass(FakeMail.class)
+ .suppress(Warning.NONFINAL_FIELDS)
+ .withPrefabValues(MimeMessage.class, mock(MimeMessage.class), mock(MimeMessage.class))
+ .verify();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/6774b877/mailet/standard/src/test/java/org/apache/james/transport/mailets/ToProcessorTest.java
----------------------------------------------------------------------
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/ToProcessorTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/ToProcessorTest.java
index 3db12fd..35175a5 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/ToProcessorTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/ToProcessorTest.java
@@ -21,6 +21,7 @@
package org.apache.james.transport.mailets;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -30,6 +31,7 @@ import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
import org.apache.mailet.Mailet;
import org.apache.mailet.MailetException;
+import org.apache.mailet.base.MailAddressFixture;
import org.apache.mailet.base.test.FakeMail;
import org.apache.mailet.base.test.FakeMailContext;
import org.apache.mailet.base.test.FakeMailetConfig;
@@ -143,13 +145,13 @@ public class ToProcessorTest {
.build();
mailet.init(mailetConfig);
- Mail mail = FakeMail.builder()
- .recipients(new MailAddress("test@james.apache.org"), new MailAddress("test2@james.apache.org"))
- .build();
String initialErrorMessage = "first";
- mail.setErrorMessage(initialErrorMessage);
+ Mail mail = FakeMail.builder()
+ .recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES)
+ .errorMessage(initialErrorMessage)
+ .build();
mailet.service(mail);
- verify(logger).info("Sending mail " + mail +" to error");
+ verify(logger).info(anyString());
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/6774b877/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index e7db2c8..8a40298 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -20,9 +20,7 @@
package org.apache.james.transport.mailets;
import java.net.UnknownHostException;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;
import java.util.Vector;
@@ -47,6 +45,8 @@ import org.apache.mailet.MailAddress;
import org.apache.mailet.base.GenericMailet;
import org.slf4j.Logger;
+import com.google.common.collect.HashMultimap;
+
/**
* <p>The RemoteDelivery mailet delivers messages to a remote SMTP server able to deliver or forward messages to their final
* destination.
@@ -120,6 +120,8 @@ import org.slf4j.Logger;
public class RemoteDelivery extends GenericMailet {
private static final String OUTGOING_MAILS = "outgoingMails";
+ private static final boolean DEFAULT_START_THREADS = true;
+ public static final String NAME_JUNCTION = "-to-";
private final DNSService dnsServer;
private final DomainList domainList;
@@ -127,6 +129,7 @@ public class RemoteDelivery extends GenericMailet {
private final Metric outgoingMailsMetric;
private final Collection<Thread> workersThreads;
private final VolatileIsDestroyed volatileIsDestroyed;
+ private final boolean startThreads;
private MailQueue queue;
private Logger logger;
@@ -134,31 +137,32 @@ public class RemoteDelivery extends GenericMailet {
@Inject
public RemoteDelivery(DNSService dnsServer, DomainList domainList, MailQueueFactory queueFactory, MetricFactory metricFactory) {
+ this(dnsServer, domainList, queueFactory, metricFactory, DEFAULT_START_THREADS);
+ }
+
+ public RemoteDelivery(DNSService dnsServer, DomainList domainList, MailQueueFactory queueFactory, MetricFactory metricFactory, boolean startThreads) {
this.dnsServer = dnsServer;
this.domainList = domainList;
this.queueFactory = queueFactory;
this.outgoingMailsMetric = metricFactory.generate(OUTGOING_MAILS);
- this.workersThreads = new Vector<Thread>();
this.volatileIsDestroyed = new VolatileIsDestroyed();
+ this.workersThreads = new Vector<Thread>();
+ this.startThreads = startThreads;
}
- /**
- * Initializes all arguments based on configuration values specified in the
- * James configuration file.
- *
- * @throws MessagingException on failure to initialize attributes.
- */
public void init() throws MessagingException {
logger = getMailetContext().getLogger();
configuration = new RemoteDeliveryConfiguration(getMailetConfig(), domainList);
queue = queueFactory.getQueue(configuration.getOutGoingQueueName());
- initDeliveryThreads();
try {
if (configuration.isBindUsed())
RemoteDeliverySocketFactory.setBindAdress(configuration.getBindAddress());
} catch (UnknownHostException e) {
log("Invalid bind setting (" + configuration.getBindAddress() + "): " + e.toString());
}
+ if (startThreads) {
+ initDeliveryThreads();
+ }
}
private void initDeliveryThreads() {
@@ -183,80 +187,65 @@ public class RemoteDelivery extends GenericMailet {
return "RemoteDelivery Mailet";
}
- /**
- * For this message, we take the list of recipients, organize these into
- * distinct servers, and duplicate the message for each of these servers,
- * and then call the deliver (messagecontainer) method for each
- * server-specific messagecontainer ... that will handle storing it in the
- * outgoing queue if needed.
- *
- * @param mail org.apache.mailet.Mail
- */
@Override
public void service(Mail mail) throws MessagingException {
- // Do I want to give the internal key, or the message's Message ID
if (configuration.isDebug()) {
log("Remotely delivering mail " + mail.getName());
}
- Collection<MailAddress> recipients = mail.getRecipients();
-
if (configuration.isUsePriority()) {
-
- // Use highest prio for new emails. See JAMES-1311
mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.HIGH_PRIORITY);
}
- if (configuration.getGatewayServer() == null) {
- // Must first organize the recipients into distinct servers (name
- // made case insensitive)
- Hashtable<String, Collection<MailAddress>> targets = new Hashtable<String, Collection<MailAddress>>();
- for (MailAddress target : recipients) {
- String targetServer = target.getDomain().toLowerCase(Locale.US);
- Collection<MailAddress> temp = targets.get(targetServer);
- if (temp == null) {
- temp = new ArrayList<MailAddress>();
- targets.put(targetServer, temp);
- }
- temp.add(target);
+ if (!mail.getRecipients().isEmpty()) {
+ if (configuration.getGatewayServer().isEmpty()) {
+ serviceNoGateway(mail);
+ } else {
+ serviceWithGateway(mail);
}
+ } else {
+ log("Mail " + mail.getName() + " from " + mail.getSender() + " has no recipients and can not be remotely delivered");
+ }
+ mail.setState(Mail.GHOST);
+ }
- // We have the recipients organized into distinct servers... put
- // them into the
- // delivery store organized like this... this is ultra inefficient I
- // think...
+ private void serviceWithGateway(Mail mail) {
+ if (configuration.isDebug()) {
+ log("Sending mail to " + mail.getRecipients() + " via " + configuration.getGatewayServer());
+ }
+ try {
+ queue.enQueue(mail);
+ } catch (MailQueueException e) {
+ log("Unable to queue mail " + mail.getName() + " for recipients + " + mail.getRecipients().toString(), e);
+ }
+ }
- // Store the new message containers, organized by server, in the
- // outgoing mail repository
- String name = mail.getName();
- for (Map.Entry<String, Collection<MailAddress>> entry : targets.entrySet()) {
- if (configuration.isDebug()) {
- String logMessageBuffer = "Sending mail to " + entry.getValue() + " on host " + entry.getKey();
- log(logMessageBuffer);
- }
- mail.setRecipients(entry.getValue());
- String nameBuffer = name + "-to-" + entry.getKey();
- mail.setName(nameBuffer);
- try {
- queue.enQueue(mail);
- } catch (MailQueueException e) {
- log("Unable to queue mail " + mail.getName() + " for recipients + " + mail.getRecipients().toString(), e);
- }
- }
- } else {
- // Store the mail unaltered for processing by the gateway server(s)
- if (configuration.isDebug()) {
- String logMessageBuffer = "Sending mail to " + mail.getRecipients() + " via " + configuration.getGatewayServer();
- log(logMessageBuffer);
- }
+ private void serviceNoGateway(Mail mail) {
+ String mailName = mail.getName();
+ Map<String, Collection<MailAddress>> targets = groupByServer(mail.getRecipients());
+ for (Map.Entry<String, Collection<MailAddress>> entry : targets.entrySet()) {
+ serviceSingleServer(mail, mailName, entry);
+ }
+ }
- // Set it to try to deliver (in a separate thread) immediately
- // (triggered by storage)
- try {
- queue.enQueue(mail);
- } catch (MailQueueException e) {
- log("Unable to queue mail " + mail.getName() + " for recipients + " + mail.getRecipients().toString(), e);
- }
+ private void serviceSingleServer(Mail mail, String originalName, Map.Entry<String, Collection<MailAddress>> entry) {
+ if (configuration.isDebug()) {
+ log("Sending mail to " + entry.getValue() + " on host " + entry.getKey());
+ }
+ mail.setRecipients(entry.getValue());
+ mail.setName(originalName + NAME_JUNCTION + entry.getKey());
+ try {
+ queue.enQueue(mail);
+ } catch (MailQueueException e) {
+ log("Unable to queue mail " + mail.getName() + " for recipients + " + mail.getRecipients().toString(), e);
}
- mail.setState(Mail.GHOST);
+ }
+
+ private Map<String, Collection<MailAddress>> groupByServer(Collection<MailAddress> recipients) {
+ // Must first organize the recipients into distinct servers (name made case insensitive)
+ HashMultimap<String, MailAddress> groupByServerMultimap = HashMultimap.create();
+ for (MailAddress recipient : recipients) {
+ groupByServerMultimap.put(recipient.getDomain().toLowerCase(Locale.US), recipient);
+ }
+ return groupByServerMultimap.asMap();
}
/**
@@ -266,12 +255,14 @@ public class RemoteDelivery extends GenericMailet {
*/
@Override
public synchronized void destroy() {
- volatileIsDestroyed.markAsDestroyed();
- // Wake up all threads from waiting for an accept
- for (Thread t : workersThreads) {
- t.interrupt();
+ if (startThreads) {
+ volatileIsDestroyed.markAsDestroyed();
+ // Wake up all threads from waiting for an accept
+ for (Thread t : workersThreads) {
+ t.interrupt();
+ }
+ notifyAll();
}
- notifyAll();
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/6774b877/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryTest.java
new file mode 100644
index 0000000..2012a2e
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryTest.java
@@ -0,0 +1,208 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import javax.mail.MessagingException;
+
+import org.apache.commons.lang.NotImplementedException;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.queue.api.MailPrioritySupport;
+import org.apache.james.queue.api.MailQueue;
+import org.apache.james.queue.api.MailQueueFactory;
+import org.apache.james.transport.mailets.RemoteDelivery;
+import org.apache.mailet.Mail;
+import org.apache.mailet.base.MailAddressFixture;
+import org.apache.mailet.base.test.FakeMail;
+import org.apache.mailet.base.test.FakeMailetConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+public class RemoteDeliveryTest {
+
+ public static final String MAIL_NAME = "mail_name";
+
+ private static class FakeMailQueue implements MailQueue {
+ private final List<Mail> enqueuedMail;
+
+ private FakeMailQueue() {
+ this.enqueuedMail = Lists.newArrayList();
+ }
+
+ @Override
+ public void enQueue(Mail mail, long delay, TimeUnit unit) throws MailQueueException {
+ enQueue(mail);
+ }
+
+ @Override
+ public void enQueue(Mail mail) throws MailQueueException {
+ try {
+ enqueuedMail.add(new FakeMail(mail));
+ } catch (MessagingException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ @Override
+ public MailQueueItem deQueue() throws MailQueueException, InterruptedException {
+ throw new NotImplementedException();
+ }
+
+ public List<Mail> getEnqueuedMail() {
+ return ImmutableList.copyOf(enqueuedMail);
+ }
+ }
+
+ public static final boolean DONT_START_THREADS = false;
+ private RemoteDelivery remoteDelivery;
+ private FakeMailQueue mailQueue;
+
+ @Before
+ public void setUp() {
+ MailQueueFactory queueFactory = mock(MailQueueFactory.class);
+ mailQueue = new FakeMailQueue();
+ when(queueFactory.getQueue(RemoteDeliveryConfiguration.OUTGOING)).thenReturn(mailQueue);
+ remoteDelivery = new RemoteDelivery(mock(DNSService.class), mock(DomainList.class), queueFactory, mock(MetricFactory.class), DONT_START_THREADS);
+ }
+
+ @Test
+ public void remoteDeliveryShouldAddEmailToSpool() throws Exception{
+ remoteDelivery.init(FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build());
+
+ Mail mail = FakeMail.builder().name(MAIL_NAME).recipients(MailAddressFixture.ANY_AT_JAMES).build();
+ remoteDelivery.service(mail);
+
+ assertThat(mailQueue.getEnqueuedMail()).containsOnly(FakeMail.builder()
+ .name(MAIL_NAME + RemoteDelivery.NAME_JUNCTION + MailAddressFixture.JAMES_APACHE_ORG)
+ .recipient(MailAddressFixture.ANY_AT_JAMES)
+ .build());
+ }
+
+ @Test
+ public void remoteDeliveryShouldSplitMailsByServerWhenNoGateway() throws Exception{
+ remoteDelivery.init(FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build());
+
+ Mail mail = FakeMail.builder()
+ .name(MAIL_NAME)
+ .recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.ANY_AT_JAMES2, MailAddressFixture.OTHER_AT_JAMES)
+ .build();
+ remoteDelivery.service(mail);
+
+ assertThat(mailQueue.getEnqueuedMail()).containsOnly(
+ FakeMail.builder()
+ .name(MAIL_NAME + RemoteDelivery.NAME_JUNCTION + MailAddressFixture.JAMES_APACHE_ORG)
+ .recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES)
+ .build(),
+ FakeMail.builder()
+ .name(MAIL_NAME + RemoteDelivery.NAME_JUNCTION + MailAddressFixture.JAMES2_APACHE_ORG)
+ .recipients(MailAddressFixture.ANY_AT_JAMES2)
+ .build());
+ }
+
+ @Test
+ public void remoteDeliveryShouldNotSplitMailsByServerWhenGateway() throws Exception{
+ remoteDelivery.init(FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY, MailAddressFixture.JAMES_LOCAL)
+ .build());
+
+ Mail mail = FakeMail.builder()
+ .name(MAIL_NAME)
+ .recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.ANY_AT_JAMES2, MailAddressFixture.OTHER_AT_JAMES)
+ .build();
+ remoteDelivery.service(mail);
+
+ assertThat(mailQueue.getEnqueuedMail()).containsOnly(
+ FakeMail.builder()
+ .name(MAIL_NAME)
+ .recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.ANY_AT_JAMES2, MailAddressFixture.OTHER_AT_JAMES)
+ .build());
+ }
+
+ @Test
+ public void remoteDeliveryShouldGhostMails() throws Exception{
+ remoteDelivery.init(FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build());
+
+ Mail mail = FakeMail.builder().name(MAIL_NAME).recipients(MailAddressFixture.ANY_AT_JAMES).build();
+ remoteDelivery.service(mail);
+
+ assertThat(mail.getState()).isEqualTo(Mail.GHOST);
+ }
+
+ @Test
+ public void remoteDeliveryShouldAddPriorityIfSpecified() throws Exception{
+ remoteDelivery.init(FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.USE_PRIORITY, "true")
+ .build());
+
+ Mail mail = FakeMail.builder().name(MAIL_NAME).recipients(MailAddressFixture.ANY_AT_JAMES).build();
+ remoteDelivery.service(mail);
+
+ assertThat(mailQueue.getEnqueuedMail()).containsOnly(FakeMail.builder()
+ .name(MAIL_NAME + RemoteDelivery.NAME_JUNCTION + MailAddressFixture.JAMES_APACHE_ORG)
+ .attribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.HIGH_PRIORITY)
+ .recipient(MailAddressFixture.ANY_AT_JAMES)
+ .build());
+ }
+
+ @Test
+ public void remoteDeliveryShouldNotForwardMailsWithNoRecipients() throws Exception{
+ remoteDelivery.init(FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build());
+
+ Mail mail = FakeMail.builder().name(MAIL_NAME).build();
+ remoteDelivery.service(mail);
+
+ assertThat(mailQueue.getEnqueuedMail()).isEmpty();
+ }
+
+ @Test
+ public void remoteDeliveryShouldNotForwardMailsWithNoRecipientsWithGateway() throws Exception{
+ remoteDelivery.init(FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY, MailAddressFixture.JAMES_LOCAL)
+ .build());
+
+ Mail mail = FakeMail.builder().name(MAIL_NAME).build();
+ remoteDelivery.service(mail);
+
+ assertThat(mailQueue.getEnqueuedMail()).isEmpty();
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[34/50] [abbrv] james-project git commit: JAMES-1877 Add tests for
running RemoteDelivery
Posted by ro...@apache.org.
JAMES-1877 Add tests for running RemoteDelivery
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/9b59d55e
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/9b59d55e
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/9b59d55e
Branch: refs/heads/master
Commit: 9b59d55e0d21754d14e6e3da331404c7d0eb6197
Parents: dbeea26
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 8 14:45:21 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:52 2017 +0700
----------------------------------------------------------------------
.../RemoteDeliveryRunningTest.java | 85 ++++++++++++++++++++
1 file changed, 85 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/9b59d55e/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryRunningTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryRunningTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryRunningTest.java
new file mode 100644
index 0000000..5c6abf7
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryRunningTest.java
@@ -0,0 +1,85 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.queue.api.MailQueue;
+import org.apache.james.queue.api.MailQueueFactory;
+import org.apache.james.transport.mailets.RemoteDelivery;
+import org.apache.mailet.base.test.FakeMailetConfig;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class RemoteDeliveryRunningTest {
+
+ public static final String QUEUE_NAME = "queueName";
+ private RemoteDelivery remoteDelivery;
+ private MailQueue mailQueue;
+ private CountDownLatch countDownLatch;
+
+ @Before
+ public void setUp() throws Exception {
+ countDownLatch = new CountDownLatch(1);
+ MailQueueFactory mailQueueFactory = mock(MailQueueFactory.class);
+ remoteDelivery = new RemoteDelivery(mock(DNSService.class), mock(DomainList.class), mailQueueFactory,
+ mock(MetricFactory.class), RemoteDelivery.THREAD_STATE.START_THREADS);
+
+ mailQueue = mock(MailQueue.class);
+ when(mailQueueFactory.getQueue(QUEUE_NAME)).thenReturn(mailQueue);
+ }
+
+ @Test
+ public void remoteDeliveryShouldStart() throws Exception {
+ when(mailQueue.deQueue()).thenAnswer(new Answer<MailQueue.MailQueueItem>() {
+ @Override
+ public MailQueue.MailQueueItem answer(InvocationOnMock invocation) throws Throwable {
+ countDownLatch.countDown();
+ Thread.sleep(TimeUnit.SECONDS.toMillis(20));
+ return null;
+ }
+ });
+ remoteDelivery.init(FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.OUTGOING, QUEUE_NAME)
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, "Hello_name")
+ .build());
+
+ countDownLatch.await();
+ verify(mailQueue).deQueue();
+ }
+
+ @After
+ public void tearDown() throws InterruptedException {
+ remoteDelivery.destroy();
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[33/50] [abbrv] james-project git commit: JAMES-1877 Refactor
decision making upon SFE exception
Posted by ro...@apache.org.
JAMES-1877 Refactor decision making upon SFE exception
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/1c6d1d06
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/1c6d1d06
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/1c6d1d06
Branch: refs/heads/master
Commit: 1c6d1d06c60c911a59f43df50e233e1319796587
Parents: 6a2fe8a
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Dec 7 09:16:44 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:52 2017 +0700
----------------------------------------------------------------------
.../mailets/remoteDelivery/ExecutionResult.java | 16 ++
.../mailets/remoteDelivery/MailDelivrer.java | 125 ++++---------
.../mailets/remoteDelivery/SFEHelper.java | 66 +++++++
.../remoteDelivery/MailDelivrerTest.java | 183 +++++++++++++++++++
4 files changed, 297 insertions(+), 93 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/1c6d1d06/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/ExecutionResult.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/ExecutionResult.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/ExecutionResult.java
index f984fd1..b408159 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/ExecutionResult.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/ExecutionResult.java
@@ -19,6 +19,7 @@
package org.apache.james.transport.mailets.remoteDelivery;
+import com.google.common.base.Objects;
import com.google.common.base.Optional;
public class ExecutionResult {
@@ -72,5 +73,20 @@ public class ExecutionResult {
public boolean isPermanent() {
return executionState == ExecutionState.PERMANENT_FAILURE;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof ExecutionResult) {
+ ExecutionResult that = (ExecutionResult) o;
+ return Objects.equal(this.executionState, that.executionState)
+ && Objects.equal(this.exception, that.exception);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(executionState, exception);
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/1c6d1d06/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
index df77eb8..c89a2a0 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
@@ -20,17 +20,15 @@
package org.apache.james.transport.mailets.remoteDelivery;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.SendFailedException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
-import javax.mail.internet.ParseException;
import org.apache.james.dnsservice.api.DNSService;
import org.apache.james.dnsservice.api.TemporaryResolutionException;
@@ -39,7 +37,7 @@ import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
import org.slf4j.Logger;
-import com.google.common.base.Optional;
+import com.google.common.annotations.VisibleForTesting;
public class MailDelivrer {
@@ -177,105 +175,46 @@ public class MailDelivrer {
}
}
- private ExecutionResult handleSenderFailedException(Mail mail, SendFailedException sfe) {
+ @VisibleForTesting
+ ExecutionResult handleSenderFailedException(Mail mail, SendFailedException sfe) {
logSendFailedException(sfe);
-
- // Copy the recipients as direct modification may not be possible
- Collection<MailAddress> recipients = new ArrayList<MailAddress>(mail.getRecipients());
-
- ExecutionResult deleteMessage = ExecutionResult.temporaryFailure();
EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
-
- /*
- * If you send a message that has multiple invalid addresses, you'll
- * get a top-level SendFailedException that that has the valid,
- * valid-unsent, and invalid address lists, with all of the server
- * response messages will be contained within the nested exceptions.
- * [Note: the content of the nested exceptions is implementation
- * dependent.]
- *
- * sfe.getInvalidAddresses() should be considered permanent.
- * sfe.getValidUnsentAddresses() should be considered temporary.
- *
- * JavaMail v1.3 properly populates those collections based upon the
- * 4xx and 5xx response codes to RCPT TO. Some servers, such as
- * Yahoo! don't respond to the RCPT TO, and provide a 5xx reply
- * after DATA. In that case, we will pick up the failure from
- * SMTPSendFailedException.
- */
-
- /*
- * SMTPSendFailedException introduced in JavaMail 1.3.2, and
- * provides detailed protocol reply code for the operation
- */
- if (enhancedMessagingException.hasReturnCode() || enhancedMessagingException.hasNestedReturnCode()) {
- if (enhancedMessagingException.isServerError()) {
- deleteMessage = ExecutionResult.permanentFailure(sfe);
- } else {
- deleteMessage = ExecutionResult.temporaryFailure(sfe);
+ List<MailAddress> invalidAddresses = SFEHelper.getAddressesAsMailAddress(sfe.getInvalidAddresses(), logger);
+ List<MailAddress> validUnsentAddresses = SFEHelper.getAddressesAsMailAddress(sfe.getValidUnsentAddresses(), logger);
+ if (configuration.isDebug()) {
+ logger.debug("Mail " + mail.getName() + " has initially recipients: " + mail.getRecipients());
+ if (!invalidAddresses.isEmpty()) {
+ logger.debug("Invalid recipients: " + invalidAddresses);
+ }
+ if (!validUnsentAddresses.isEmpty()) {
+ logger.debug("Unsent recipients: " + validUnsentAddresses);
}
}
-
- // log the original set of intended recipients
- if (configuration.isDebug())
- logger.debug("Recipients: " + recipients);
-
- if (sfe.getInvalidAddresses() != null) {
- Address[] address = sfe.getInvalidAddresses();
- if (address.length > 0) {
- recipients.clear();
- for (Address addres : address) {
- try {
- recipients.add(new MailAddress(addres.toString()));
- } catch (ParseException pe) {
- // this should never happen ... we should have
- // caught malformed addresses long before we
- // got to this code.
- logger.debug("Can't parse invalid address: " + pe.getMessage());
- }
- }
- // Set the recipients for the mail
- mail.setRecipients(recipients);
-
- if (configuration.isDebug())
- logger.debug("Invalid recipients: " + recipients);
- deleteMessage = ExecutionResult.permanentFailure(sfe);
- logger.debug(messageComposer.composeFailLogMessage(mail, deleteMessage));
+ if (!validUnsentAddresses.isEmpty()) {
+ mail.setRecipients(validUnsentAddresses);
+ if (enhancedMessagingException.hasReturnCode()) {
+ boolean isPermanent = enhancedMessagingException.isServerError();
+ return logAndReturn(mail, ExecutionResult.onFailure(isPermanent, sfe));
+ } else {
+ return logAndReturn(mail, ExecutionResult.temporaryFailure(sfe));
}
}
+ if (!invalidAddresses.isEmpty()) {
+ mail.setRecipients(invalidAddresses);
+ return logAndReturn(mail, ExecutionResult.permanentFailure(sfe));
+ }
- if (sfe.getValidUnsentAddresses() != null) {
- Address[] address = sfe.getValidUnsentAddresses();
- if (address.length > 0) {
- recipients.clear();
- for (Address addres : address) {
- try {
- recipients.add(new MailAddress(addres.toString()));
- } catch (ParseException pe) {
- // this should never happen ... we should have
- // caught malformed addresses long before we
- // got to this code.
- logger.debug("Can't parse unsent address: " + pe.getMessage());
- }
- }
- // Set the recipients for the mail
- mail.setRecipients(recipients);
- if (configuration.isDebug())
- logger.debug("Unsent recipients: " + recipients);
-
- if (enhancedMessagingException.hasReturnCode()) {
- boolean isPermanent = enhancedMessagingException.isServerError();
- deleteMessage = ExecutionResult.onFailure(isPermanent, sfe);
- logger.debug(messageComposer.composeFailLogMessage(mail, deleteMessage));
- } else {
- deleteMessage = ExecutionResult.temporaryFailure(sfe);
- logger.debug(messageComposer.composeFailLogMessage(mail, deleteMessage));
- }
+ if (enhancedMessagingException.hasReturnCode() || enhancedMessagingException.hasNestedReturnCode()) {
+ if (enhancedMessagingException.isServerError()) {
+ return ExecutionResult.permanentFailure(sfe);
}
}
+ return ExecutionResult.temporaryFailure(sfe);
+ }
-
- return deleteMessage;
+ private ExecutionResult logAndReturn(Mail mail, ExecutionResult executionResult) {
+ logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
+ return executionResult;
}
private MessagingException handleSendFailException(Mail mail, SendFailedException sfe) throws SendFailedException {
http://git-wip-us.apache.org/repos/asf/james-project/blob/1c6d1d06/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/SFEHelper.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/SFEHelper.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/SFEHelper.java
new file mode 100644
index 0000000..a9650d3
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/SFEHelper.java
@@ -0,0 +1,66 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.mail.Address;
+import javax.mail.internet.AddressException;
+
+import org.apache.mailet.MailAddress;
+import org.slf4j.Logger;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+
+public class SFEHelper {
+
+ public static List<MailAddress> getAddressesAsMailAddress(Address[] addresses, final Logger logger) {
+ if (addresses == null) {
+ return ImmutableList.of();
+ }
+ return FluentIterable.from(Arrays.asList(addresses)).transform(new Function<Address, Optional<MailAddress>>() {
+ @Override
+ public Optional<MailAddress> apply(Address input) {
+ try {
+ return Optional.of(new MailAddress(input.toString()));
+ } catch (AddressException e) {
+ logger.debug("Can't parse unsent address: " + e.getMessage());
+ return Optional.absent();
+ }
+ }
+ }).filter(new Predicate<Optional<MailAddress>>() {
+ @Override
+ public boolean apply(Optional<MailAddress> input) {
+ return input.isPresent();
+ }
+ }).transform(new Function<Optional<MailAddress>, MailAddress>() {
+ @Override
+ public MailAddress apply(Optional<MailAddress> input) {
+ return input.get();
+ }
+ }).toList();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/1c6d1d06/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
new file mode 100644
index 0000000..9c5fe69
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
@@ -0,0 +1,183 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.mockito.Mockito.mock;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import javax.mail.Address;
+import javax.mail.SendFailedException;
+import javax.mail.internet.InternetAddress;
+
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.mailet.Mail;
+import org.apache.mailet.base.MailAddressFixture;
+import org.apache.mailet.base.test.FakeMail;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.mail.smtp.SMTPSenderFailedException;
+
+public class MailDelivrerTest {
+ private static final Logger LOGGER = LoggerFactory.getLogger(MailDelivrerTest.class);
+
+ private MailDelivrer testee;
+
+ @Before
+ public void setUp() {
+ testee = new MailDelivrer(mock(RemoteDeliveryConfiguration.class), mock(MailDelivrerToHost.class), mock(DNSService.class), LOGGER);
+ }
+
+ @Test
+ public void handleSenderFailedExceptionShouldReturnTemporaryFailureByDefault() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ SendFailedException sfe = new SendFailedException();
+ ExecutionResult executionResult = testee.handleSenderFailedException(mail, sfe);
+
+ assertThat(executionResult).isEqualTo(ExecutionResult.temporaryFailure(sfe));
+ }
+
+ @Test
+ public void handleSenderFailedExceptionShouldReturnTemporaryFailureWhenNotServerException() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ SendFailedException sfe = new SMTPSenderFailedException(new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString()), "Comand", 400, "An temporary error");
+ ExecutionResult executionResult = testee.handleSenderFailedException(mail, sfe);
+
+ assertThat(executionResult).isEqualTo(ExecutionResult.temporaryFailure(sfe));
+ }
+
+ @Ignore("Return code is always ignored")
+ @Test
+ public void handleSenderFailedExceptionShouldReturnPermanentFailureWhenServerException() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ SendFailedException sfe = new SMTPSenderFailedException(new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString()), "Comand", 505, "An temporary error");
+ ExecutionResult executionResult = testee.handleSenderFailedException(mail, sfe);
+
+ assertThat(executionResult).isEqualTo(ExecutionResult.permanentFailure(sfe));
+ }
+
+ @Test
+ public void handleSenderFailedExceptionShouldReturnPermanentFailureWhenInvalidAndNotValidUnsent() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ Address[] validSent = {};
+ Address[] validUnsent = {};
+ Address[] invalid = {new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString())};
+ SendFailedException sfe = new SendFailedException("Message",
+ new Exception(),
+ validSent,
+ validUnsent,
+ invalid);
+ ExecutionResult executionResult = testee.handleSenderFailedException(mail, sfe);
+
+ assertThat(executionResult).isEqualTo(ExecutionResult.permanentFailure(sfe));
+ }
+
+ @Test
+ public void handleSenderFailedExceptionShouldReturnTemporaryFailureWhenValidUnsent() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ Address[] validSent = {};
+ Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+ Address[] invalid = {};
+ SendFailedException sfe = new SendFailedException("Message",
+ new Exception(),
+ validSent,
+ validUnsent,
+ invalid);
+ ExecutionResult executionResult = testee.handleSenderFailedException(mail, sfe);
+
+ assertThat(executionResult).isEqualTo(ExecutionResult.temporaryFailure(sfe));
+ }
+
+ @Test
+ public void handleSenderFailedExceptionShouldReturnTemporaryFailureWhenInvalidAndValidUnsent() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ Address[] validSent = {};
+ Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+ Address[] invalid = {new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString())};
+ SendFailedException sfe = new SendFailedException("Message",
+ new Exception(),
+ validSent,
+ validUnsent,
+ invalid);
+ ExecutionResult executionResult = testee.handleSenderFailedException(mail, sfe);
+
+ assertThat(executionResult).isEqualTo(ExecutionResult.temporaryFailure(sfe));
+ }
+
+ @Test
+ public void handleSenderFailedExceptionShouldSetRecipientToInvalidWhenOnlyInvalid() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ Address[] validSent = {};
+ Address[] validUnsent = {};
+ Address[] invalid = {new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString())};
+ SendFailedException sfe = new SendFailedException("Message",
+ new Exception(),
+ validSent,
+ validUnsent,
+ invalid);
+ testee.handleSenderFailedException(mail, sfe);
+
+ assertThat(mail.getRecipients()).containsOnly(MailAddressFixture.ANY_AT_JAMES);
+ }
+
+ @Test
+ public void handleSenderFailedExceptionShouldSetRecipientToValidUnsentWhenOnlyValidUnsent() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ Address[] validSent = {};
+ Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+ Address[] invalid = {};
+ SendFailedException sfe = new SendFailedException("Message",
+ new Exception(),
+ validSent,
+ validUnsent,
+ invalid);
+ testee.handleSenderFailedException(mail, sfe);
+
+ assertThat(mail.getRecipients()).containsOnly(MailAddressFixture.OTHER_AT_JAMES);
+ }
+
+ @Test
+ public void handleSenderFailedExceptionShouldSetRecipientToValidUnsentWhenValidUnsentAndInvalid() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ Address[] validSent = {};
+ Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+ Address[] invalid = {new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString())};
+ SendFailedException sfe = new SendFailedException("Message",
+ new Exception(),
+ validSent,
+ validUnsent,
+ invalid);
+ testee.handleSenderFailedException(mail, sfe);
+
+ assertThat(mail.getRecipients()).containsOnly(MailAddressFixture.OTHER_AT_JAMES);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[16/50] [abbrv] james-project git commit: MAILET-119 Don't count
retry using errorMessage
Posted by ro...@apache.org.
MAILET-119 Don't count retry using errorMessage
Use Attribute for that
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/2e60b2dc
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/2e60b2dc
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/2e60b2dc
Branch: refs/heads/master
Commit: 2e60b2dcced3a90bbe408414f5a1f91df0d010c2
Parents: b563349
Author: Benoit Tellier <bt...@linagora.com>
Authored: Fri Dec 2 13:37:30 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:49 2017 +0700
----------------------------------------------------------------------
.../remoteDelivery/DeliveryRetriesHelper.java | 17 ++++++++++++-----
.../remoteDelivery/DeliveryRetryHelperTest.java | 4 ++--
2 files changed, 14 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/2e60b2dc/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetriesHelper.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetriesHelper.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetriesHelper.java
index 485127e..81e5c8c 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetriesHelper.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetriesHelper.java
@@ -19,25 +19,32 @@
package org.apache.james.transport.mailets.remoteDelivery;
+import java.io.Serializable;
+
import org.apache.mailet.Mail;
public class DeliveryRetriesHelper {
+ public static final String DELIVERY_RETRY_COUNT = "delivery_retry_count";
+
public static int retrieveRetries(Mail mail) {
try {
- return Integer.parseInt(mail.getErrorMessage());
- } catch (NumberFormatException e) {
- // Something strange was happen with the errorMessage..
+ Serializable value = mail.getAttribute(DELIVERY_RETRY_COUNT);
+ if (value != null) {
+ return (Integer) value;
+ }
+ return 0;
+ } catch (ClassCastException e) {
return 0;
}
}
public static void initRetries(Mail mail) {
- mail.setErrorMessage("0");
+ mail.setAttribute(DELIVERY_RETRY_COUNT, 0);
}
public static void incrementRetries(Mail mail) {
- mail.setErrorMessage(String.valueOf(retrieveRetries(mail) + 1));
+ mail.setAttribute(DELIVERY_RETRY_COUNT, retrieveRetries(mail) + 1);
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/2e60b2dc/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetryHelperTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetryHelperTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetryHelperTest.java
index 72ad294..406cd31 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetryHelperTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetryHelperTest.java
@@ -65,7 +65,7 @@ public class DeliveryRetryHelperTest {
@Test
public void retrieveRetriesShouldBeZeroOnInvalidValue() throws Exception {
- FakeMail mail = FakeMail.builder().errorMessage("invalid").build();
+ FakeMail mail = FakeMail.builder().attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, "invalid").build();
assertThat(DeliveryRetriesHelper.retrieveRetries(mail))
.isEqualTo(0);
@@ -73,7 +73,7 @@ public class DeliveryRetryHelperTest {
@Test
public void incrementRetriesShouldWorkOnInvalidMails() throws Exception {
- FakeMail mail = FakeMail.builder().errorMessage("invalid").build();
+ FakeMail mail = FakeMail.builder().attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, "invalid").build();
DeliveryRetriesHelper.incrementRetries(mail);
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[40/50] [abbrv] james-project git commit: JAMES-1877
VolatileIsDestroyed is not needed
Posted by ro...@apache.org.
JAMES-1877 VolatileIsDestroyed is not needed
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/1f01e8ad
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/1f01e8ad
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/1f01e8ad
Branch: refs/heads/master
Commit: 1f01e8ad204e7b1620457e77026b510066f74b68
Parents: 9646571
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 8 09:59:02 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 18:14:26 2017 +0700
----------------------------------------------------------------------
.../james/transport/mailets/RemoteDelivery.java | 10 ++---
.../remoteDelivery/DeliveryRunnable.java | 15 +++----
.../remoteDelivery/VolatileIsDestroyed.java | 36 -----------------
.../remoteDelivery/VolatileIsDestroyedTest.java | 41 --------------------
4 files changed, 13 insertions(+), 89 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/1f01e8ad/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index 3a1f17d..006c6bc 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -25,6 +25,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
import javax.mail.MessagingException;
@@ -41,7 +42,6 @@ import org.apache.james.transport.mailets.remoteDelivery.Bouncer;
import org.apache.james.transport.mailets.remoteDelivery.DeliveryRunnable;
import org.apache.james.transport.mailets.remoteDelivery.RemoteDeliveryConfiguration;
import org.apache.james.transport.mailets.remoteDelivery.RemoteDeliverySocketFactory;
-import org.apache.james.transport.mailets.remoteDelivery.VolatileIsDestroyed;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
import org.apache.mailet.base.GenericMailet;
@@ -133,7 +133,7 @@ public class RemoteDelivery extends GenericMailet {
private final DomainList domainList;
private final MailQueueFactory queueFactory;
private final Metric outgoingMailsMetric;
- private final VolatileIsDestroyed volatileIsDestroyed;
+ private final AtomicBoolean isDestroyed;
private final THREAD_STATE startThreads;
private MailQueue queue;
@@ -151,7 +151,7 @@ public class RemoteDelivery extends GenericMailet {
this.domainList = domainList;
this.queueFactory = queueFactory;
this.outgoingMailsMetric = metricFactory.generate(OUTGOING_MAILS);
- this.volatileIsDestroyed = new VolatileIsDestroyed();
+ this.isDestroyed = new AtomicBoolean(false);
this.startThreads = startThreads;
}
@@ -181,7 +181,7 @@ public class RemoteDelivery extends GenericMailet {
logger,
getMailetContext(),
new Bouncer(configuration, getMailetContext(), logger),
- volatileIsDestroyed));
+ isDestroyed));
}
}
@@ -259,7 +259,7 @@ public class RemoteDelivery extends GenericMailet {
@Override
public synchronized void destroy() {
if (startThreads == THREAD_STATE.START_THREADS) {
- volatileIsDestroyed.markAsDestroyed();
+ isDestroyed.set(true);
executor.shutdown();
notifyAll();
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/1f01e8ad/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index 7af269b..4841402 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -21,6 +21,7 @@ package org.apache.james.transport.mailets.remoteDelivery;
import java.util.Date;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.james.dnsservice.api.DNSService;
import org.apache.james.lifecycle.api.LifecycleUtil;
@@ -50,33 +51,33 @@ public class DeliveryRunnable implements Runnable {
private final Logger logger;
private final Bouncer bouncer;
private final MailDelivrer mailDelivrer;
- private final VolatileIsDestroyed volatileIsDestroyed;
+ private final AtomicBoolean isDestroyed;
private final Supplier<Date> dateSupplier;
public DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, DNSService dnsServer, Metric outgoingMailsMetric,
- Logger logger, MailetContext mailetContext, Bouncer bouncer, VolatileIsDestroyed volatileIsDestroyed) {
+ Logger logger, MailetContext mailetContext, Bouncer bouncer, AtomicBoolean isDestroyed) {
this(queue, configuration, outgoingMailsMetric, logger, bouncer,
new MailDelivrer(configuration, new MailDelivrerToHost(configuration, mailetContext, logger), dnsServer, bouncer, logger),
- volatileIsDestroyed, CURRENT_DATE_SUPPLIER);
+ isDestroyed, CURRENT_DATE_SUPPLIER);
}
@VisibleForTesting
DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, Metric outgoingMailsMetric, Logger logger, Bouncer bouncer,
- MailDelivrer mailDelivrer, VolatileIsDestroyed volatileIsDestroyed, Supplier<Date> dateSupplier) {
+ MailDelivrer mailDelivrer, AtomicBoolean isDestroyeds, Supplier<Date> dateSupplier) {
this.queue = queue;
this.configuration = configuration;
this.outgoingMailsMetric = outgoingMailsMetric;
this.logger = logger;
this.bouncer = bouncer;
this.mailDelivrer = mailDelivrer;
- this.volatileIsDestroyed = volatileIsDestroyed;
+ this.isDestroyed = isDestroyeds;
this.dateSupplier = dateSupplier;
}
@Override
public void run() {
try {
- while (!Thread.interrupted() && !volatileIsDestroyed.isDestroyed()) {
+ while (!Thread.interrupted() && !isDestroyed.get()) {
runStep();
}
} finally {
@@ -112,7 +113,7 @@ public class DeliveryRunnable implements Runnable {
}
} catch (Throwable e) {
- if (!volatileIsDestroyed.isDestroyed()) {
+ if (!isDestroyed.get()) {
logger.error("Exception caught in RemoteDelivery.run()", e);
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/1f01e8ad/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyed.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyed.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyed.java
deleted file mode 100644
index 19d4b36..0000000
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyed.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you under the Apache License, Version 2.0 (the *
- * "License"); you may not use this file except in compliance *
- * with the License. You may obtain a copy of the License at *
- * *
- * http://www.apache.org/licenses/LICENSE-2.0 *
- * *
- * Unless required by applicable law or agreed to in writing, *
- * software distributed under the License is distributed on an *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
- * KIND, either express or implied. See the License for the *
- * specific language governing permissions and limitations *
- * under the License. *
- ****************************************************************/
-
-package org.apache.james.transport.mailets.remoteDelivery;
-
-public class VolatileIsDestroyed {
- private volatile boolean isDestroyed;
-
- public VolatileIsDestroyed() {
- this.isDestroyed = false;
- }
-
- public boolean isDestroyed() {
- return isDestroyed;
- }
-
- public void markAsDestroyed() {
- isDestroyed = true;
- }
-}
http://git-wip-us.apache.org/repos/asf/james-project/blob/1f01e8ad/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyedTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyedTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyedTest.java
deleted file mode 100644
index dd10c8c..0000000
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyedTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you under the Apache License, Version 2.0 (the *
- * "License"); you may not use this file except in compliance *
- * with the License. You may obtain a copy of the License at *
- * *
- * http://www.apache.org/licenses/LICENSE-2.0 *
- * *
- * Unless required by applicable law or agreed to in writing, *
- * software distributed under the License is distributed on an *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
- * KIND, either express or implied. See the License for the *
- * specific language governing permissions and limitations *
- * under the License. *
- ****************************************************************/
-
-package org.apache.james.transport.mailets.remoteDelivery;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.junit.Test;
-
-public class VolatileIsDestroyedTest {
-
- @Test
- public void isDestroyedShouldBeFalseByDefault() {
- assertThat(new VolatileIsDestroyed().isDestroyed()).isFalse();
- }
-
- @Test
- public void isDestroyedShouldBeTrueWhenMarkedAsDestroyed() {
- VolatileIsDestroyed volatileIsDestroyed = new VolatileIsDestroyed();
-
- volatileIsDestroyed.markAsDestroyed();
-
- assertThat(volatileIsDestroyed.isDestroyed()).isTrue();
- }
-}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[43/50] [abbrv] james-project git commit: JAMES-1877 Correct DNS
error handling
Posted by ro...@apache.org.
JAMES-1877 Correct DNS error handling
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/d004e6ec
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/d004e6ec
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/d004e6ec
Branch: refs/heads/master
Commit: d004e6ec653156da13742248ed2e6c36786b650e
Parents: 9898e18
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Dec 7 10:54:10 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 18:14:27 2017 +0700
----------------------------------------------------------------------
.../james/transport/mailets/remoteDelivery/MailDelivrer.java | 2 +-
.../james/transport/mailets/remoteDelivery/MailDelivrerTest.java | 3 ---
2 files changed, 1 insertion(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/d004e6ec/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
index 27f66aa..1dfc81b 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
@@ -263,7 +263,7 @@ public class MailDelivrer {
MessagingException messagingException = new MessagingException("There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.");
int retry = DeliveryRetriesHelper.retrieveRetries(mail);
System.out.println("retyry " + retry);
- if (retry == 0 || retry > configuration.getDnsProblemRetry()) {
+ if (retry >= configuration.getDnsProblemRetry()) {
return logAndReturn(mail, ExecutionResult.permanentFailure(messagingException));
} else {
return logAndReturn(mail, ExecutionResult.temporaryFailure(messagingException));
http://git-wip-us.apache.org/repos/asf/james-project/blob/d004e6ec/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
index 27de817..3f7b726 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
@@ -37,7 +37,6 @@ import org.apache.mailet.base.MailAddressFixture;
import org.apache.mailet.base.test.FakeMail;
import org.apache.mailet.base.test.FakeMailetConfig;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -223,7 +222,6 @@ public class MailDelivrerTest {
@SuppressWarnings("deprecation")
@Test
- @Ignore("Fails if first delivery attempt")
public void deliverShouldReturnTemporaryErrorWhenFirstDNSProblem() throws Exception {
Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
@@ -261,7 +259,6 @@ public class MailDelivrerTest {
@SuppressWarnings("deprecation")
@Test
- @Ignore("One more failure is tolerated than specified by the configuration")
public void deliverShouldReturnPermanentErrorWhenLimitDNSProblemReached() throws Exception {
Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[17/50] [abbrv] james-project git commit: JAMES-1877 Extract helper
for counting delivery retries of a mail
Posted by ro...@apache.org.
JAMES-1877 Extract helper for counting delivery retries of a mail
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/b5633492
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/b5633492
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/b5633492
Branch: refs/heads/master
Commit: b5633492b792ed4c86560e598dce492b033549b6
Parents: a62e460
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 15:57:56 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:49 2017 +0700
----------------------------------------------------------------------
.../remoteDelivery/DeliveryRetriesHelper.java | 43 ++++++++++
.../remoteDelivery/DeliveryRunnable.java | 31 ++------
.../remoteDelivery/DeliveryRetryHelperTest.java | 83 ++++++++++++++++++++
3 files changed, 131 insertions(+), 26 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/b5633492/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetriesHelper.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetriesHelper.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetriesHelper.java
new file mode 100644
index 0000000..485127e
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetriesHelper.java
@@ -0,0 +1,43 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import org.apache.mailet.Mail;
+
+public class DeliveryRetriesHelper {
+
+ public static int retrieveRetries(Mail mail) {
+ try {
+ return Integer.parseInt(mail.getErrorMessage());
+ } catch (NumberFormatException e) {
+ // Something strange was happen with the errorMessage..
+ return 0;
+ }
+ }
+
+ public static void initRetries(Mail mail) {
+ mail.setErrorMessage("0");
+ }
+
+ public static void incrementRetries(Mail mail) {
+ mail.setErrorMessage(String.valueOf(retrieveRetries(mail) + 1));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/b5633492/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index d9db12c..75fb3e2 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -136,14 +136,7 @@ public class DeliveryRunnable implements Runnable {
LifecycleUtil.dispose(mail);
} else {
// Something happened that will delay delivery. Store it back in the retry repository.
- int retries = 0;
- try {
- retries = Integer.parseInt(mail.getErrorMessage());
- } catch (NumberFormatException e) {
- // Something strange was happen with the errorMessage..
- }
-
- long delay = getNextDelay(retries);
+ long delay = getNextDelay(DeliveryRetriesHelper.retrieveRetries(mail));
if (configuration.isUsePriority()) {
// Use lowest priority for retries. See JAMES-1311
@@ -154,7 +147,6 @@ public class DeliveryRunnable implements Runnable {
}
}
-
/**
* We can assume that the recipients of this message are all going to the
* same mail server. We will now rely on the DNS server to do DNS MX record
@@ -558,12 +550,7 @@ public class DeliveryRunnable implements Runnable {
logger.info("No mail server found for: " + host);
String exceptionBuffer = "There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.";
- int retry = 0;
- try {
- retry = Integer.parseInt(mail.getErrorMessage());
- } catch (NumberFormatException e) {
- // Unable to parse retryCount
- }
+ int retry = DeliveryRetriesHelper.retrieveRetries(mail);
if (retry == 0 || retry > configuration.getDnsProblemRetry()) {
// The domain has no dns entry.. Return a permanent error
return failMessage(mail, new MessagingException(exceptionBuffer), true);
@@ -647,8 +634,6 @@ public class DeliveryRunnable implements Runnable {
}
/**
- * Insert the method's description here.
- *
* @param mail org.apache.james.core.MailImpl
* @param ex javax.mail.MessagingException
* @param permanent
@@ -659,21 +644,15 @@ public class DeliveryRunnable implements Runnable {
if (!permanent) {
if (!mail.getState().equals(Mail.ERROR)) {
mail.setState(Mail.ERROR);
- mail.setErrorMessage("0");
+ DeliveryRetriesHelper.initRetries(mail);
mail.setLastUpdated(new Date());
}
- int retries = 0;
- try {
- retries = Integer.parseInt(mail.getErrorMessage());
- } catch (NumberFormatException e) {
- // Something strange was happen with the errorMessage..
- }
+ int retries = DeliveryRetriesHelper.retrieveRetries(mail);
if (retries < configuration.getMaxRetries()) {
logger.debug("Storing message " + mail.getName() + " into outgoing after " + retries + " retries");
- ++retries;
- mail.setErrorMessage(retries + "");
+ DeliveryRetriesHelper.incrementRetries(mail);
mail.setLastUpdated(new Date());
return false;
} else {
http://git-wip-us.apache.org/repos/asf/james-project/blob/b5633492/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetryHelperTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetryHelperTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetryHelperTest.java
new file mode 100644
index 0000000..72ad294
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRetryHelperTest.java
@@ -0,0 +1,83 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.mailet.base.test.FakeMail;
+import org.junit.Test;
+
+public class DeliveryRetryHelperTest {
+
+ @Test
+ public void retrieveRetriesShouldBeZeroByDefault() throws Exception {
+ assertThat(DeliveryRetriesHelper.retrieveRetries(FakeMail.defaultFakeMail()))
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void retrieveRetriesShouldBeZeroAfterInit() throws Exception {
+ FakeMail mail = FakeMail.defaultFakeMail();
+
+ DeliveryRetriesHelper.initRetries(mail);
+
+ assertThat(DeliveryRetriesHelper.retrieveRetries(mail))
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void retrieveRetriesShouldBeOneAfterIncrement() throws Exception {
+ FakeMail mail = FakeMail.defaultFakeMail();
+
+ DeliveryRetriesHelper.initRetries(mail);
+ DeliveryRetriesHelper.incrementRetries(mail);
+
+ assertThat(DeliveryRetriesHelper.retrieveRetries(mail))
+ .isEqualTo(1);
+ }
+
+ @Test
+ public void incrementRetriesShouldWorkOnNonInitializedMails() throws Exception {
+ FakeMail mail = FakeMail.defaultFakeMail();
+
+ DeliveryRetriesHelper.incrementRetries(mail);
+
+ assertThat(DeliveryRetriesHelper.retrieveRetries(mail))
+ .isEqualTo(1);
+ }
+
+ @Test
+ public void retrieveRetriesShouldBeZeroOnInvalidValue() throws Exception {
+ FakeMail mail = FakeMail.builder().errorMessage("invalid").build();
+
+ assertThat(DeliveryRetriesHelper.retrieveRetries(mail))
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void incrementRetriesShouldWorkOnInvalidMails() throws Exception {
+ FakeMail mail = FakeMail.builder().errorMessage("invalid").build();
+
+ DeliveryRetriesHelper.incrementRetries(mail);
+
+ assertThat(DeliveryRetriesHelper.retrieveRetries(mail))
+ .isEqualTo(1);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[39/50] [abbrv] james-project git commit: JAMES-1877 Make naming on
Error management clearer
Posted by ro...@apache.org.
JAMES-1877 Make naming on Error management clearer
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/70ad2337
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/70ad2337
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/70ad2337
Branch: refs/heads/master
Commit: 70ad2337775d27557fada77d6d0cc9258b57ed2e
Parents: aec9b2f
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Dec 7 10:19:03 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 18:14:26 2017 +0700
----------------------------------------------------------------------
.../james/transport/mailets/remoteDelivery/MailDelivrer.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/70ad2337/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
index bb03b62..e6f1ec3 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
@@ -135,7 +135,7 @@ public class MailDelivrer {
return ExecutionResult.success();
}
} catch (SendFailedException sfe) {
- lastError = handleSendFailException(mail, sfe);
+ lastError = handleSendFailExceptionOnMxIteration(mail, sfe);
} catch (MessagingException me) {
lastError = handleMessagingException(mail, me);
if (configuration.isDebug()) {
@@ -223,7 +223,7 @@ public class MailDelivrer {
return executionResult;
}
- private MessagingException handleSendFailException(Mail mail, SendFailedException sfe) throws SendFailedException {
+ private MessagingException handleSendFailExceptionOnMxIteration(Mail mail, SendFailedException sfe) throws SendFailedException {
logSendFailedException(sfe);
if (sfe.getValidSentAddresses() != null) {
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[21/50] [abbrv] james-project git commit: JAMES-1877 Extract a
utility for sending bounce
Posted by ro...@apache.org.
JAMES-1877 Extract a utility for sending bounce
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/26c6d9c4
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/26c6d9c4
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/26c6d9c4
Branch: refs/heads/master
Commit: 26c6d9c4d1d332642a78464a386308f2c6846746
Parents: bc52f33
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 18:18:30 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:50 2017 +0700
----------------------------------------------------------------------
.../mailet/base/test/FakeMailContext.java | 112 +++--
.../mailets/remoteDelivery/Bouncer.java | 124 ++++++
.../remoteDelivery/DeliveryRunnable.java | 41 +-
.../mailets/remoteDelivery/MessageComposer.java | 48 ---
.../mailets/remoteDelivery/BouncerTest.java | 425 +++++++++++++++++++
5 files changed, 641 insertions(+), 109 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/26c6d9c4/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java
index 6296e94..23188ea 100644
--- a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java
+++ b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java
@@ -56,6 +56,25 @@ public class FakeMailContext implements MailetContext {
return new SentMail.Builder();
}
+ public static SentMail fromMail(Mail mail ) throws MessagingException {
+ return sentMailBuilder()
+ .sender(mail.getSender())
+ .recipients(mail.getRecipients())
+ .message(mail.getMessage())
+ .state(mail.getState())
+ .attributes(buildAttributesMap(mail))
+ .build();
+ }
+
+ private static ImmutableMap<String, Serializable> buildAttributesMap(Mail mail) {
+ Map<String, Serializable> result = new HashMap<String, Serializable>();
+ List<String> attributesNames = Lists.newArrayList(mail.getAttributeNames());
+ for (String attributeName: attributesNames) {
+ result.put(attributeName, mail.getAttribute(attributeName));
+ }
+ return ImmutableMap.copyOf(result);
+ }
+
public static FakeMailContext defaultContext() {
return builder().build();
}
@@ -80,7 +99,7 @@ public class FakeMailContext implements MailetContext {
private MailAddress sender;
private Optional<Collection<MailAddress>> recipients = Optional.absent();
private MimeMessage msg;
- private Optional<Map<String, Serializable>> attributes = Optional.absent();
+ private Map<String, Serializable> attributes = new HashMap<String, Serializable>();
private Optional<String> state = Optional.absent();
public Builder sender(MailAddress sender) {
@@ -104,7 +123,12 @@ public class FakeMailContext implements MailetContext {
}
public Builder attributes(Map<String, Serializable> attributes) {
- this.attributes = Optional.of(attributes);
+ this.attributes.putAll(attributes);
+ return this;
+ }
+
+ public Builder attribute(String key, Serializable value) {
+ this.attributes.put(key, value);
return this;
}
@@ -115,7 +139,7 @@ public class FakeMailContext implements MailetContext {
public SentMail build() {
return new SentMail(sender, recipients.or(ImmutableList.<MailAddress>of()), msg,
- attributes.or(ImmutableMap.<String, Serializable>of()), state.or(Mail.DEFAULT));
+ ImmutableMap.copyOf(attributes), state.or(Mail.DEFAULT));
}
}
@@ -179,22 +203,73 @@ public class FakeMailContext implements MailetContext {
}
}
+ public static class BouncedMail {
+ private final SentMail sentMail;
+ private final String message;
+ private final Optional<MailAddress> bouncer;
+
+ public BouncedMail(SentMail sentMail, String message, Optional<MailAddress> bouncer) {
+ this.sentMail = sentMail;
+ this.message = message;
+ this.bouncer = bouncer;
+ }
+
+ public SentMail getSentMail() {
+ return sentMail;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public Optional<MailAddress> getBouncer() {
+ return bouncer;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BouncedMail) {
+ BouncedMail that = (BouncedMail) o;
+ return Objects.equal(this.sentMail, that.sentMail)
+ && Objects.equal(this.message, that.message)
+ && Objects.equal(this.bouncer, that.bouncer);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(sentMail, message, bouncer);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("sentMail", sentMail)
+ .add("message", message)
+ .add("bouncer", bouncer)
+ .toString();
+ }
+ }
+
private final HashMap<String, Object> attributes;
private final List<SentMail> sentMails;
+ private final List<BouncedMail> bouncedMails;
private final Optional<Logger> logger;
private FakeMailContext(Optional<Logger> logger) {
attributes = new HashMap<String, Object>();
sentMails = new ArrayList<SentMail>();
+ bouncedMails = new ArrayList<BouncedMail>();
this.logger = logger;
}
public void bounce(Mail mail, String message) throws MessagingException {
- // trivial implementation
+ bouncedMails.add(new BouncedMail(fromMail(mail), message, Optional.<MailAddress>absent()));
}
public void bounce(Mail mail, String message, MailAddress bouncer) throws MessagingException {
- // trivial implementation
+ bouncedMails.add(new BouncedMail(fromMail(mail), message, Optional.fromNullable(bouncer)));
}
/**
@@ -263,13 +338,13 @@ public class FakeMailContext implements MailetContext {
}
public void sendMail(MimeMessage mimemessage) throws MessagingException {
- sentMails.add(new SentMail.Builder()
+ sentMails.add(sentMailBuilder()
.message(mimemessage)
.build());
}
public void sendMail(MailAddress sender, Collection<MailAddress> recipients, MimeMessage msg) throws MessagingException {
- sentMails.add(new SentMail.Builder()
+ sentMails.add(sentMailBuilder()
.recipients(recipients)
.sender(sender)
.message(msg)
@@ -277,7 +352,7 @@ public class FakeMailContext implements MailetContext {
}
public void sendMail(MailAddress sender, Collection<MailAddress> recipients, MimeMessage msg, String state) throws MessagingException {
- sentMails.add(new SentMail.Builder()
+ sentMails.add(sentMailBuilder()
.recipients(recipients)
.message(msg)
.state(state)
@@ -286,22 +361,7 @@ public class FakeMailContext implements MailetContext {
}
public void sendMail(Mail mail) throws MessagingException {
- sentMails.add(new SentMail.Builder()
- .sender(mail.getSender())
- .recipients(mail.getRecipients())
- .message(mail.getMessage())
- .state(mail.getState())
- .attributes(buildAttributesMap(mail))
- .build());
- }
-
- private ImmutableMap<String, Serializable> buildAttributesMap(Mail mail) {
- Map<String, Serializable> result = new HashMap<String, Serializable>();
- List<String> attributesNames = Lists.newArrayList(mail.getAttributeNames());
- for (String attributeName: attributesNames) {
- result.put(attributeName, mail.getAttribute(attributeName));
- }
- return ImmutableMap.copyOf(result);
+ sentMails.add(fromMail(mail));
}
public void setAttribute(String name, Serializable object) {
@@ -372,6 +432,10 @@ public class FakeMailContext implements MailetContext {
return sentMails;
}
+ public List<BouncedMail> getBouncedMails() {
+ return bouncedMails;
+ }
+
@Override
public Logger getLogger() {
return logger.orNull();
http://git-wip-us.apache.org/repos/asf/james-project/blob/26c6d9c4/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
new file mode 100644
index 0000000..feebf84
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
@@ -0,0 +1,124 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.ConnectException;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+
+import javax.mail.MessagingException;
+import javax.mail.SendFailedException;
+
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+import org.apache.mailet.MailetContext;
+import org.slf4j.Logger;
+
+public class Bouncer {
+
+ public static final String DELIVERY_ERROR = "delivery-error";
+ private final RemoteDeliveryConfiguration configuration;
+ private final MessageComposer messageComposer;
+ private final MailetContext mailetContext;
+ private final Logger logger;
+
+ public Bouncer(RemoteDeliveryConfiguration configuration, MessageComposer messageComposer, MailetContext mailetContext, Logger logger) {
+ this.configuration = configuration;
+ this.messageComposer = messageComposer;
+ this.mailetContext = mailetContext;
+ this.logger = logger;
+ }
+
+ public void bounce(Mail mail, Exception ex) {
+ if (mail.getSender() == null) {
+ logger.debug("Null Sender: no bounce will be generated for " + mail.getName());
+ } else {
+ if (configuration.getBounceProcessor() != null) {
+ mail.setAttribute(DELIVERY_ERROR, messageComposer.getErrorMsg(ex));
+ mail.setState(configuration.getBounceProcessor());
+ try {
+ mailetContext.sendMail(mail);
+ } catch (MessagingException e) {
+ logger.debug("Exception re-inserting failed mail: ", e);
+ }
+ } else {
+ bounceWithMailetContext(mail, ex);
+ }
+ }
+ }
+
+
+ private void bounceWithMailetContext(Mail mail, Exception ex) {
+ logger.debug("Sending failure message " + mail.getName());
+ try {
+ mailetContext.bounce(mail, explanationText(mail, ex));
+ } catch (MessagingException me) {
+ logger.debug("Encountered unexpected messaging exception while bouncing message: " + me.getMessage());
+ } catch (Exception e) {
+ logger.debug("Encountered unexpected exception while bouncing message: " + e.getMessage());
+ }
+ }
+
+ public String explanationText(Mail mail, Exception ex) {
+ StringWriter sout = new StringWriter();
+ PrintWriter out = new PrintWriter(sout, true);
+ String machine;
+ try {
+ machine = configuration.getHeloNameProvider().getHeloName();
+
+ } catch (Exception e) {
+ machine = "[address unknown]";
+ }
+ String bounceBuffer = "Hi. This is the James mail server at " + machine + ".";
+ out.println(bounceBuffer);
+ out.println("I'm afraid I wasn't able to deliver your message to the following addresses.");
+ out.println("This is a permanent error; I've given up. Sorry it didn't work out. Below");
+ out.println("I include the list of recipients and the reason why I was unable to deliver");
+ out.println("your message.");
+ out.println();
+ for (MailAddress mailAddress : mail.getRecipients()) {
+ out.println(mailAddress);
+ }
+ if (ex instanceof MessagingException) {
+ if (((MessagingException) ex).getNextException() == null) {
+ out.println(ex.getMessage().trim());
+ } else {
+ Exception ex1 = ((MessagingException) ex).getNextException();
+ if (ex1 instanceof SendFailedException) {
+ out.println("Remote mail server told me: " + ex1.getMessage().trim());
+ } else if (ex1 instanceof UnknownHostException) {
+ out.println("Unknown host: " + ex1.getMessage().trim());
+ out.println("This could be a DNS server error, a typo, or a problem with the recipient's mail server.");
+ } else if (ex1 instanceof ConnectException) {
+ // Already formatted as "Connection timed out: connect"
+ out.println(ex1.getMessage().trim());
+ } else if (ex1 instanceof SocketException) {
+ out.println("Socket exception: " + ex1.getMessage().trim());
+ } else {
+ out.println(ex1.getMessage().trim());
+ }
+ }
+ }
+ out.println();
+ return sout.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/26c6d9c4/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index a3e08ef..39b38d0 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -116,7 +116,7 @@ public class DeliveryRunnable implements Runnable {
private final DNSService dnsServer;
private final Metric outgoingMailsMetric;
private final Logger logger;
- private final MailetContext mailetContext;
+ private final Bouncer bouncer;
private final VolatileIsDestroyed volatileIsDestroyed;
private final MessageComposer messageComposer;
private final Converter7Bit converter7Bit;
@@ -127,10 +127,10 @@ public class DeliveryRunnable implements Runnable {
this.dnsServer = dnsServer;
this.outgoingMailsMetric = outgoingMailsMetric;
this.logger = logger;
- this.mailetContext = mailetContext;
this.volatileIsDestroyed = volatileIsDestroyed;
this.messageComposer = new MessageComposer(configuration);
this.converter7Bit = new Converter7Bit(mailetContext);
+ this.bouncer = new Bouncer(configuration, messageComposer, mailetContext, logger);
}
/**
@@ -189,7 +189,7 @@ public class DeliveryRunnable implements Runnable {
handleTemporaryFailure(mail, executionResult);
break;
case PERMANENT_FAILURE:
- bounce(mail, executionResult.getException().orNull());
+ bouncer.bounce(mail, executionResult.getException().orNull());
break;
}
}
@@ -206,7 +206,7 @@ public class DeliveryRunnable implements Runnable {
reAttemptDelivery(mail, retries);
} else {
logger.debug("Bouncing message " + mail.getName() + " after " + retries + " retries");
- bounce(mail, new Exception("Too many retries failure. Bouncing after " + retries + " retries.", executionResult.getException().orNull()));
+ bouncer.bounce(mail, new Exception("Too many retries failure. Bouncing after " + retries + " retries.", executionResult.getException().orNull()));
}
}
@@ -711,39 +711,6 @@ public class DeliveryRunnable implements Runnable {
}
}
- private void bounce(Mail mail, Exception ex) {
- if (mail.getSender() == null) {
- logger.debug("Null Sender: no bounce will be generated for " + mail.getName());
- }
-
- if (configuration.getBounceProcessor() != null) {
- // do the new DSN bounce setting attributes for DSN mailet
- mail.setAttribute("delivery-error", messageComposer.getErrorMsg(ex));
- mail.setState(configuration.getBounceProcessor());
- // re-insert the mail into the spool for getting it passed to the dsn-processor
- try {
- mailetContext.sendMail(mail);
- } catch (MessagingException e) {
- // we shouldn't get an exception, because the mail was already processed
- logger.debug("Exception re-inserting failed mail: ", e);
- }
- } else {
- bounceWithMailetContext(mail, ex);
- }
- }
-
-
- private void bounceWithMailetContext(Mail mail, Exception ex) {
- logger.debug("Sending failure message " + mail.getName());
- try {
- mailetContext.bounce(mail, messageComposer.composeForBounce(mail, ex));
- } catch (MessagingException me) {
- logger.debug("Encountered unexpected messaging exception while bouncing message: " + me.getMessage());
- } catch (Exception e) {
- logger.debug("Encountered unexpected exception while bouncing message: " + e.getMessage());
- }
- }
-
/**
* Returns an Iterator over org.apache.mailet.HostAddress, a specialized
* subclass of javax.mail.URLName, which provides location information for
http://git-wip-us.apache.org/repos/asf/james-project/blob/26c6d9c4/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
index a57b496..a323ba9 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
@@ -23,9 +23,6 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.net.ConnectException;
-import java.net.SocketException;
-import java.net.UnknownHostException;
import java.util.Arrays;
import javax.mail.MessagingException;
@@ -33,7 +30,6 @@ import javax.mail.SendFailedException;
import javax.mail.internet.InternetAddress;
import org.apache.mailet.Mail;
-import org.apache.mailet.MailAddress;
public class MessageComposer {
@@ -43,50 +39,6 @@ public class MessageComposer {
this.configuration = configuration;
}
- public String composeForBounce(Mail mail, Exception ex) {
- StringWriter sout = new StringWriter();
- PrintWriter out = new PrintWriter(sout, true);
- String machine;
- try {
- machine = configuration.getHeloNameProvider().getHeloName();
-
- } catch (Exception e) {
- machine = "[address unknown]";
- }
- String bounceBuffer = "Hi. This is the James mail server at " + machine + ".";
- out.println(bounceBuffer);
- out.println("I'm afraid I wasn't able to deliver your message to the following addresses.");
- out.println("This is a permanent error; I've given up. Sorry it didn't work out. Below");
- out.println("I include the list of recipients and the reason why I was unable to deliver");
- out.println("your message.");
- out.println();
- for (MailAddress mailAddress : mail.getRecipients()) {
- out.println(mailAddress);
- }
- if (ex instanceof MessagingException) {
- if (((MessagingException) ex).getNextException() == null) {
- out.println(ex.getMessage().trim());
- } else {
- Exception ex1 = ((MessagingException) ex).getNextException();
- if (ex1 instanceof SendFailedException) {
- out.println("Remote mail server told me: " + ex1.getMessage().trim());
- } else if (ex1 instanceof UnknownHostException) {
- out.println("Unknown host: " + ex1.getMessage().trim());
- out.println("This could be a DNS server error, a typo, or a problem with the recipient's mail server.");
- } else if (ex1 instanceof ConnectException) {
- // Already formatted as "Connection timed out: connect"
- out.println(ex1.getMessage().trim());
- } else if (ex1 instanceof SocketException) {
- out.println("Socket exception: " + ex1.getMessage().trim());
- } else {
- out.println(ex1.getMessage().trim());
- }
- }
- }
- out.println();
- return sout.toString();
- }
-
/**
* Try to return a usefull logString created of the Exception which was
* given. Return null if nothing usefull could be done
http://git-wip-us.apache.org/repos/asf/james-project/blob/26c6d9c4/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/BouncerTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/BouncerTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/BouncerTest.java
new file mode 100644
index 0000000..de683c0
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/BouncerTest.java
@@ -0,0 +1,425 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.apache.james.transport.mailets.remoteDelivery.Bouncer.DELIVERY_ERROR;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+import java.net.ConnectException;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+
+import javax.mail.MessagingException;
+import javax.mail.SendFailedException;
+
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+import org.apache.mailet.base.MailAddressFixture;
+import org.apache.mailet.base.test.FakeMail;
+import org.apache.mailet.base.test.FakeMailContext;
+import org.apache.mailet.base.test.FakeMailetConfig;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class BouncerTest {
+ private static final Logger LOGGER = LoggerFactory.getLogger(BouncerTest.class);
+ public static final String HELLO_NAME = "hello_name";
+ public static final String BOUNCE_PROCESSOR = "bounce_processor";
+
+ private FakeMailContext mailetContext;
+
+ @Before
+ public void setUp() {
+ mailetContext = FakeMailContext.defaultContext();
+ }
+
+ @Test
+ public void bounceShouldCallMailetContextBounceByDefault() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .build();
+ testee.bounce(mail, new Exception("Exception message"));
+
+ FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
+ "Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
+ "I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "I include the list of recipients and the reason why I was unable to deliver\n" +
+ "your message.\n\n\n",
+ Optional.<MailAddress>absent());
+ assertThat(mailetContext.getSentMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).containsOnly(expected);
+ }
+
+ @Test
+ public void bounceShouldIncludeMessagingExceptionMessageByDefault() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .build();
+ String exceptionMessage = "Exception message";
+ testee.bounce(mail, new MessagingException(exceptionMessage));
+
+ FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
+ "Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
+ "I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "I include the list of recipients and the reason why I was unable to deliver\n" +
+ "your message.\n" +
+ "\n" +
+ exceptionMessage + "\n\n",
+ Optional.<MailAddress>absent());
+ assertThat(mailetContext.getSentMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).containsOnly(expected);
+ }
+
+ @Test
+ public void bounceShouldCustomizeSendFailedExceptionByDefault() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .build();
+ String exceptionMessage = "Error from remote server";
+ testee.bounce(mail, new MessagingException("Exception message", new SendFailedException(exceptionMessage)));
+
+ FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
+ "Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
+ "I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "I include the list of recipients and the reason why I was unable to deliver\n" +
+ "your message.\n" +
+ "\n" +
+ "Remote mail server told me: " + exceptionMessage + "\n\n",
+ Optional.<MailAddress>absent());
+ assertThat(mailetContext.getSentMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).containsOnly(expected);
+ }
+
+ @Test
+ public void bounceShouldCustomizeUnknownHostExceptionByDefault() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .build();
+ String exceptionMessage = "I don't know him";
+ testee.bounce(mail, new MessagingException("Exception message", new UnknownHostException(exceptionMessage)));
+
+ FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
+ "Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
+ "I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "I include the list of recipients and the reason why I was unable to deliver\n" +
+ "your message.\n" +
+ "\n" +
+ "Unknown host: " + exceptionMessage + "\n" +
+ "This could be a DNS server error, a typo, or a problem with the recipient's mail server.\n\n",
+ Optional.<MailAddress>absent());
+ assertThat(mailetContext.getSentMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).containsOnly(expected);
+ }
+
+ @Test
+ public void bounceShouldCustomizeConnectionExceptionByDefault() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .build();
+ String exceptionMessage = "Can not connect";
+ testee.bounce(mail, new MessagingException("Exception message", new ConnectException(exceptionMessage)));
+
+ FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
+ "Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
+ "I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "I include the list of recipients and the reason why I was unable to deliver\n" +
+ "your message.\n" +
+ "\n" +
+ exceptionMessage + "\n\n",
+ Optional.<MailAddress>absent());
+ assertThat(mailetContext.getSentMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).containsOnly(expected);
+ }
+
+ @Test
+ public void bounceShouldCustomizeSocketExceptionByDefault() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .build();
+ String exceptionMessage = "Can not connect";
+ testee.bounce(mail, new MessagingException("Exception message", new SocketException(exceptionMessage)));
+
+ FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
+ "Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
+ "I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "I include the list of recipients and the reason why I was unable to deliver\n" +
+ "your message.\n" +
+ "\n" +
+ "Socket exception: " + exceptionMessage + "\n\n",
+ Optional.<MailAddress>absent());
+ assertThat(mailetContext.getSentMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).containsOnly(expected);
+ }
+
+ @Test
+ public void bounceShouldCustomizeNestedMessagingExceptionByDefault() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .build();
+ String exceptionMessage = "Can not connect";
+ testee.bounce(mail, new MessagingException("Exception message", new MessagingException(exceptionMessage)));
+
+ FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
+ "Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
+ "I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "I include the list of recipients and the reason why I was unable to deliver\n" +
+ "your message.\n" +
+ "\n" +
+ exceptionMessage + "\n\n",
+ Optional.<MailAddress>absent());
+ assertThat(mailetContext.getSentMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).containsOnly(expected);
+ }
+
+ @Test
+ public void bounceShouldNotBounceWithNoSenderByDefault() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .build();
+ String exceptionMessage = "Can not connect";
+ testee.bounce(mail, new MessagingException("Exception message", new ConnectException(exceptionMessage)));
+
+ assertThat(mailetContext.getSentMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).isEmpty();
+ }
+
+ @Test
+ public void bounceShouldSupportExceptionWithoutMessagesByDefaultByDefault() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .build();
+ testee.bounce(mail, new Exception("Exception message"));
+
+ FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
+ "Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
+ "I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "I include the list of recipients and the reason why I was unable to deliver\n" +
+ "your message.\n\n\n",
+ Optional.<MailAddress>absent());
+ assertThat(mailetContext.getSentMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).containsOnly(expected);
+ }
+
+ @Test
+ public void bounceShouldNotSupportMessagingExceptionWithoutMessagesByDefaultByDefault() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .build();
+ testee.bounce(mail, new MessagingException());
+
+ assertThat(mailetContext.getSentMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).isEmpty();
+ }
+
+ @Test
+ public void bounceShouldWorkWhenProcessorSpecified() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .build();
+ String errorMessage = "message";
+ testee.bounce(mail, new MessagingException(errorMessage));
+
+ FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder()
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .attribute(DELIVERY_ERROR, errorMessage)
+ .state(BOUNCE_PROCESSOR)
+ .build();
+ assertThat(mailetContext.getSentMails()).containsOnly(expected);
+ assertThat(mailetContext.getBouncedMails()).isEmpty();
+ }
+
+ @Test
+ public void bounceShouldNotBounceWhenNoSenderWhenProcessorSpecified() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .build();
+ testee.bounce(mail, new MessagingException("message"));
+
+ assertThat(mailetContext.getSentMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).isEmpty();
+ }
+
+ @Test
+ public void bounceShouldDisplayAddressByDefaultByDefault() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .recipient(MailAddressFixture.ANY_AT_JAMES2)
+ .build();
+ testee.bounce(mail, new Exception("Exception message"));
+
+ FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
+ "Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
+ "I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "I include the list of recipients and the reason why I was unable to deliver\n" +
+ "your message.\n\n" +
+ MailAddressFixture.ANY_AT_JAMES2.asString() + "\n\n",
+ Optional.<MailAddress>absent());
+ assertThat(mailetContext.getSentMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).containsOnly(expected);
+ }
+
+ @Test
+ public void bounceShouldDisplayAddressesByDefaultByDefault() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .recipients(MailAddressFixture.ANY_AT_JAMES2, MailAddressFixture.OTHER_AT_JAMES2)
+ .build();
+ testee.bounce(mail, new Exception("Exception message"));
+
+ FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
+ "Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
+ "I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "I include the list of recipients and the reason why I was unable to deliver\n" +
+ "your message.\n\n" +
+ MailAddressFixture.ANY_AT_JAMES2.asString() + "\n" +
+ MailAddressFixture.OTHER_AT_JAMES2.asString() + "\n\n",
+ Optional.<MailAddress>absent());
+ assertThat(mailetContext.getSentMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).containsOnly(expected);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[03/50] [abbrv] james-project git commit: JAMES-1877 Improve
TimeConverter
Posted by ro...@apache.org.
JAMES-1877 Improve TimeConverter
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/03fc53a4
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/03fc53a4
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/03fc53a4
Branch: refs/heads/master
Commit: 03fc53a4760e2d28a312fd57f9768f4ef54e3264
Parents: 788b393
Author: Benoit Tellier <bt...@linagora.com>
Authored: Tue Nov 29 11:23:48 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 14:35:27 2017 +0700
----------------------------------------------------------------------
.../org/apache/james/util/TimeConverter.java | 8 +-
.../apache/james/util/TimeConverterTest.java | 242 +++++++++++++++++--
2 files changed, 229 insertions(+), 21 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/03fc53a4/server/container/util/src/main/java/org/apache/james/util/TimeConverter.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/TimeConverter.java b/server/container/util/src/main/java/org/apache/james/util/TimeConverter.java
index 6709de0..2a877b7 100644
--- a/server/container/util/src/main/java/org/apache/james/util/TimeConverter.java
+++ b/server/container/util/src/main/java/org/apache/james/util/TimeConverter.java
@@ -19,6 +19,7 @@
package org.apache.james.util;
import java.util.HashMap;
+import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -32,14 +33,19 @@ public class TimeConverter {
static {
// add allowed units and their respective multiplier
+ multipliers.put("ms", 1);
multipliers.put("msec", 1);
multipliers.put("msecs", 1);
+ multipliers.put("s", 1000);
multipliers.put("sec", 1000);
multipliers.put("secs", 1000);
+ multipliers.put("m", 1000 * 60);
multipliers.put("minute", 1000 * 60);
multipliers.put("minutes", 1000 * 60);
+ multipliers.put("h", 1000 * 60 * 60);
multipliers.put("hour", 1000 * 60 * 60);
multipliers.put("hours", 1000 * 60 * 60);
+ multipliers.put("d", 1000 * 60 * 60 * 24);
multipliers.put("day", 1000 * 60 * 60 * 24);
multipliers.put("days", 1000 * 60 * 60 * 24);
@@ -63,7 +69,7 @@ public class TimeConverter {
* Get thrown if an illegal unit was used
*/
public static long getMilliSeconds(long amount, String unit) throws NumberFormatException {
- Object multiplierObject = multipliers.get(unit);
+ Object multiplierObject = multipliers.get(unit.toLowerCase(Locale.US));
if (multiplierObject == null) {
throw new NumberFormatException("Unknown unit: " + unit);
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/03fc53a4/server/container/util/src/test/java/org/apache/james/util/TimeConverterTest.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/test/java/org/apache/james/util/TimeConverterTest.java b/server/container/util/src/test/java/org/apache/james/util/TimeConverterTest.java
index adf620f..b05a935 100644
--- a/server/container/util/src/test/java/org/apache/james/util/TimeConverterTest.java
+++ b/server/container/util/src/test/java/org/apache/james/util/TimeConverterTest.java
@@ -20,6 +20,8 @@ package org.apache.james.util;
import static org.assertj.core.api.Assertions.assertThat;
+import java.util.concurrent.TimeUnit;
+
import org.junit.Test;
public class TimeConverterTest {
@@ -33,8 +35,8 @@ public class TimeConverterTest {
//Then
assertThat(actual).isEqualTo(expected);
}
-
- @Test
+
+ @Test
public void getMilliSecondsShouldConvertValueWhenMsecAmountAsString() {
//Given
long expected = 2;
@@ -43,6 +45,46 @@ public class TimeConverterTest {
//Then
assertThat(actual).isEqualTo(expected);
}
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenMsUnit() {
+ //Given
+ long expected = 2;
+ //When
+ long actual = TimeConverter.getMilliSeconds(2, "ms");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenMsAmountAsString() {
+ //Given
+ long expected = 2;
+ //When
+ long actual = TimeConverter.getMilliSeconds("2 ms");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenMsUnitCapital() {
+ //Given
+ long expected = 2;
+ //When
+ long actual = TimeConverter.getMilliSeconds(2, "Ms");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenMsCapitalAmountAsString() {
+ //Given
+ long expected = 2;
+ //When
+ long actual = TimeConverter.getMilliSeconds("2 Ms");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
@Test
public void getMilliSecondsShouldConvertValueWhenMsecsUnit() {
@@ -63,11 +105,31 @@ public class TimeConverterTest {
//Then
assertThat(actual).isEqualTo(expected);
}
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenSUnit() {
+ //Given
+ long expected = TimeUnit.SECONDS.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds(2, "s");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenSAmountAsString() {
+ //Given
+ long expected = TimeUnit.SECONDS.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds("2 s");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
@Test
public void getMilliSecondsShouldConvertValueWhenSecUnit() {
//Given
- long expected = 2000;
+ long expected = TimeUnit.SECONDS.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds(2, "sec");
//Then
@@ -77,16 +139,36 @@ public class TimeConverterTest {
@Test
public void getMilliSecondsShouldConvertValueWhenSecAmountAsString() {
//Given
- long expected = 2000;
+ long expected = TimeUnit.SECONDS.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds("2 sec");
//Then
assertThat(actual).isEqualTo(expected);
}
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenSecCapitalUnit() {
+ //Given
+ long expected = TimeUnit.SECONDS.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds(2, "Sec");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenSecCapitalAmountAsString() {
+ //Given
+ long expected = TimeUnit.SECONDS.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds("2 Sec");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
@Test
public void getMilliSecondsShouldConvertValueWhenSecsUnit() {
- long expected = 2000;
+ long expected = TimeUnit.SECONDS.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds(2, "secs");
//Then
@@ -96,17 +178,37 @@ public class TimeConverterTest {
@Test
public void getMilliSecondsShouldConvertValueWhenSecsAmountAsString() {
//Given
- long expected = 2000;
+ long expected = TimeUnit.SECONDS.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds("2 secs");
//Then
assertThat(actual).isEqualTo(expected);
}
-
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenMUnit() {
+ //Given
+ long expected = TimeUnit.MINUTES.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds(2, "m");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenMAmountAsString() {
+ //Given
+ long expected = TimeUnit.MINUTES.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds("2 m");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
@Test
public void getMilliSecondsShouldConvertValueWhenMinuteUnit() {
//Given
- long expected = 120000;
+ long expected = TimeUnit.MINUTES.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds(2, "minute");
//Then
@@ -116,7 +218,7 @@ public class TimeConverterTest {
@Test
public void getMilliSecondsShouldConvertValueWhenMinuteAmountAsString() {
//Given
- long expected = 120000;
+ long expected = TimeUnit.MINUTES.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds("2 minute");
//Then
@@ -124,9 +226,29 @@ public class TimeConverterTest {
}
@Test
+ public void getMilliSecondsShouldConvertValueWhenMinuteCapitalUnit() {
+ //Given
+ long expected = TimeUnit.MINUTES.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds(2, "Minute");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenMinuteCapitalAmountAsString() {
+ //Given
+ long expected = TimeUnit.MINUTES.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds("2 Minute");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
public void getMilliSecondsShouldConvertValueWhenMinutesUnit() {
//Given
- long expected = 120000;
+ long expected = TimeUnit.MINUTES.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds(2, "minutes");
//Then
@@ -136,17 +258,37 @@ public class TimeConverterTest {
@Test
public void getMilliSecondsShouldConvertValueWhenMinutesAmountAsString() {
//Given
- long expected = 120000;
+ long expected = TimeUnit.MINUTES.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds("2 minutes");
//Then
assertThat(actual).isEqualTo(expected);
}
-
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenHUnit() {
+ //Given
+ long expected = TimeUnit.HOURS.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds(2, "h");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenHAmountAsString() {
+ //Given
+ long expected = TimeUnit.HOURS.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds("2 h");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
@Test
public void getMilliSecondsShouldConvertValueWhenHourUnit() {
//Given
- long expected = 7200000;
+ long expected = TimeUnit.HOURS.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds(2, "hour");
//Then
@@ -156,17 +298,37 @@ public class TimeConverterTest {
@Test
public void getMilliSecondsShouldConvertValueWhenHourAmountAsString() {
//Given
- long expected = 7200000;
+ long expected = TimeUnit.HOURS.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds("2 hour");
//Then
assertThat(actual).isEqualTo(expected);
}
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenHourCapitalUnit() {
+ //Given
+ long expected = TimeUnit.HOURS.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds(2, "Hour");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenHourCapitalAmountAsString() {
+ //Given
+ long expected = TimeUnit.HOURS.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds("2 Hour");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
@Test
public void getMilliSecondsShouldConvertValueWhenHoursUnit() {
//Given
- long expected = 7200000;
+ long expected = TimeUnit.HOURS.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds(2, "hours");
//Then
@@ -176,17 +338,37 @@ public class TimeConverterTest {
@Test
public void getMilliSecondsShouldConvertValueWhenHoursAmountAsString() {
//Given
- long expected = 7200000;
+ long expected = TimeUnit.HOURS.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds("2 hours");
//Then
assertThat(actual).isEqualTo(expected);
}
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenDUnit() {
+ //Given
+ long expected = TimeUnit.DAYS.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds(2, "d");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenDAmountAsString() {
+ //Given
+ long expected = TimeUnit.DAYS.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds("2 d");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
@Test
public void getMilliSecondsShouldConvertValueWhenDayUnit() {
//Given
- long expected = 172800000;
+ long expected = TimeUnit.DAYS.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds(2, "day");
//Then
@@ -196,17 +378,37 @@ public class TimeConverterTest {
@Test
public void getMilliSecondsShouldConvertValueWhenDayAmountAsString() {
//Given
- long expected = 172800000;
+ long expected = TimeUnit.DAYS.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds("2 day");
//Then
assertThat(actual).isEqualTo(expected);
}
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenDayCapitalUnit() {
+ //Given
+ long expected = TimeUnit.DAYS.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds(2, "Day");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void getMilliSecondsShouldConvertValueWhenDayCapitalAmountAsString() {
+ //Given
+ long expected = TimeUnit.DAYS.toMillis(2);
+ //When
+ long actual = TimeConverter.getMilliSeconds("2 Day");
+ //Then
+ assertThat(actual).isEqualTo(expected);
+ }
@Test
public void getMilliSecondsShouldConvertValueWhenDaysUnit() {
//Given
- long expected = 172800000;
+ long expected = TimeUnit.DAYS.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds(2, "days");
//Then
@@ -216,7 +418,7 @@ public class TimeConverterTest {
@Test
public void getMilliSecondsShouldConvertValueWhenDaysAmountAsString() {
//Given
- long expected = 172800000;
+ long expected = TimeUnit.DAYS.toMillis(2);
//When
long actual = TimeConverter.getMilliSeconds("2 days");
//Then
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[18/50] [abbrv] james-project git commit: JAMES-1877 Continue to
flatten DeliveryRunnable
Posted by ro...@apache.org.
JAMES-1877 Continue to flatten DeliveryRunnable
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/5742cbf0
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/5742cbf0
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/5742cbf0
Branch: refs/heads/master
Commit: 5742cbf0839e3213a6ef34ef4f8da00660e975dd
Parents: 80039f1
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 14:43:07 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:49 2017 +0700
----------------------------------------------------------------------
.../remoteDelivery/DeliveryRunnable.java | 234 ++++++++++---------
1 file changed, 130 insertions(+), 104 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/5742cbf0/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index ea35f7c..c917f19 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -314,30 +314,19 @@ public class DeliveryRunnable implements Runnable {
}
private Boolean tryDeliver(Mail mail, Session session) throws MessagingException {
- if (configuration.isDebug()) {
- logger.debug("Attempting to deliver " + mail.getName());
- }
- MimeMessage message = mail.getMessage();
-
- // Create an array of the recipients as InternetAddress objects
- Collection<MailAddress> recipients = mail.getRecipients();
- InternetAddress addr[] = new InternetAddress[recipients.size()];
- int j = 0;
- for (Iterator<MailAddress> i = recipients.iterator(); i.hasNext(); j++) {
- MailAddress rcpt = i.next();
- addr[j] = rcpt.toInternetAddress();
- }
-
- if (addr.length <= 0) {
+ if (mail.getRecipients().isEmpty()) {
logger.info("No recipients specified... not sure how this could have happened.");
return true;
}
+ if (configuration.isDebug()) {
+ logger.debug("Attempting to deliver " + mail.getName());
+ }
// Figure out which servers to try to send to. This collection
// will hold all the possible target servers
Iterator<HostAddress> targetServers;
if (configuration.getGatewayServer().isEmpty()) {
- MailAddress rcpt = recipients.iterator().next();
+ MailAddress rcpt = mail.getRecipients().iterator().next();
String host = rcpt.getDomain();
// Lookup the possible targets
@@ -353,100 +342,18 @@ public class DeliveryRunnable implements Runnable {
targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer());
}
+ return doDeliver(mail, session, mail.getMessage(), convertToInetAddr(mail.getRecipients()), targetServers);
+ }
+
+ private Boolean doDeliver(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException {
MessagingException lastError = null;
while (targetServers.hasNext()) {
HostAddress outgoingMailServer = targetServers.next();
try {
- Properties props = session.getProperties();
- if (mail.getSender() == null) {
- props.put("mail.smtp.from", "<>");
- } else {
- String sender = mail.getSender().toString();
- props.put("mail.smtp.from", sender);
+ if (tryDeliveryToHost(mail, session, message, addr, outgoingMailServer)) {
+ return true;
}
- logger.debug("Attempting delivery of " + mail.getName() + " to host " + outgoingMailServer.getHostName()
- + " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from"));
-
- // Many of these properties are only in later JavaMail versions
- // "mail.smtp.ehlo" //default true
- // "mail.smtp.auth" //default false
- // "mail.smtp.dsn.ret" //default to nothing... appended as
- // RET= after MAIL FROM line.
- // "mail.smtp.dsn.notify" //default to nothing...appended as
- // NOTIFY= after RCPT TO line.
-
- SMTPTransport transport = null;
- try {
- transport = (SMTPTransport) session.getTransport(outgoingMailServer);
- transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
- try {
- if (configuration.getAuthUser() != null) {
- transport.connect(outgoingMailServer.getHostName(), configuration.getAuthUser(), configuration.getAuthPass());
- } else {
- transport.connect();
- }
- } catch (MessagingException me) {
- // Any error on connect should cause the mailet to attempt
- // to connect to the next SMTP server associated with this
- // MX record. Just log the exception. We'll worry about
- // failing the message at the end of the loop.
-
- // Also include the stacktrace if debug is enabled. See JAMES-1257
- if (configuration.isDebug()) {
- logger.debug(me.getMessage(), me.getCause());
- } else {
- logger.info(me.getMessage());
- }
- continue;
- }
- // if the transport is a SMTPTransport (from sun) some
- // performance enhancement can be done.
- if (transport.getClass().getName().endsWith(".SMTPTransport")) {
- // if the message is alredy 8bit or binary and the server doesn't support the 8bit extension it has
- // to be converted to 7bit. Javamail api doesn't perform
- // that conversion, but it is required to be a rfc-compliant smtp server.
-
- // Temporarily disabled. See JAMES-638
- if (!transport.supportsExtension(BIT_MIME_8)) {
- try {
- convertTo7Bit(message);
- } catch (IOException e) {
- // An error has occured during the 7bit conversion.
- // The error is logged and the message is sent anyway.
-
- logger.error("Error during the conversion to 7 bit.", e);
- }
- }
- } else {
- // If the transport is not the one developed by Sun we are not sure of how it
- // handles the 8 bit mime stuff, so I convert the message to 7bit.
- try {
- convertTo7Bit(message);
- } catch (IOException e) {
- logger.error("Error during the conversion to 7 bit.", e);
- }
- }
- transport.sendMessage(message, addr);
- } finally {
- if (transport != null) {
- try {
- // James-899: transport.close() sends QUIT to the server; if that fails
- // (e.g. because the server has already closed the connection) the message
- // should be considered to be delivered because the error happened outside
- // of the mail transaction (MAIL, RCPT, DATA).
- transport.close();
- } catch (MessagingException e) {
- logger.error("Warning: could not close the SMTP transport after sending mail (" + mail.getName() + ") to " + outgoingMailServer.getHostName() + " at " + outgoingMailServer.getHost() + " for " + mail.getRecipients() + "; probably the server has already closed the "
- + "connection. Message is considered to be delivered. Exception: " + e.getMessage());
- }
- transport = null;
- }
- }
- logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() +
- " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients());
- outgoingMailsMetric.increment();
- return true;
} catch (SendFailedException sfe) {
logSendFailedException(sfe);
@@ -514,6 +421,125 @@ public class DeliveryRunnable implements Runnable {
return null;
}
+ private InternetAddress[] convertToInetAddr(Collection<MailAddress> recipients) {
+ InternetAddress addr[] = new InternetAddress[recipients.size()];
+ int j = 0;
+ for (Iterator<MailAddress> i = recipients.iterator(); i.hasNext(); j++) {
+ MailAddress rcpt = i.next();
+ addr[j] = rcpt.toInternetAddress();
+ }
+ return addr;
+ }
+
+ private boolean tryDeliveryToHost(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException {
+ boolean success = false;
+ Properties props = session.getProperties();
+ if (mail.getSender() == null) {
+ props.put("mail.smtp.from", "<>");
+ } else {
+ String sender = mail.getSender().toString();
+ props.put("mail.smtp.from", sender);
+ }
+ logger.debug("Attempting delivery of " + mail.getName() + " to host " + outgoingMailServer.getHostName()
+ + " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from"));
+
+ // Many of these properties are only in later JavaMail versions
+ // "mail.smtp.ehlo" //default true
+ // "mail.smtp.auth" //default false
+ // "mail.smtp.dsn.ret" //default to nothing... appended as
+ // RET= after MAIL FROM line.
+ // "mail.smtp.dsn.notify" //default to nothing...appended as
+ // NOTIFY= after RCPT TO line.
+
+ SMTPTransport transport = null;
+ try {
+ transport = (SMTPTransport) session.getTransport(outgoingMailServer);
+ transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
+ if (!connect(outgoingMailServer, transport)) {
+ success = false;
+ }
+ transport.sendMessage(adaptToTransport(message, transport), addr);
+ success = true;
+ logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() +
+ " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients());
+ outgoingMailsMetric.increment();
+ } finally {
+ closeTransport(mail, outgoingMailServer, transport);
+ }
+ return success;
+ }
+
+ private MimeMessage adaptToTransport(MimeMessage message, SMTPTransport transport) throws MessagingException {
+ // if the transport is a SMTPTransport (from sun) some
+ // performance enhancement can be done.
+ if (transport.getClass().getName().endsWith(".SMTPTransport")) {
+ // if the message is alredy 8bit or binary and the server doesn't support the 8bit extension it has
+ // to be converted to 7bit. Javamail api doesn't perform
+ // that conversion, but it is required to be a rfc-compliant smtp server.
+
+ // Temporarily disabled. See JAMES-638
+ if (!transport.supportsExtension(BIT_MIME_8)) {
+ try {
+ convertTo7Bit(message);
+ } catch (IOException e) {
+ // An error has occured during the 7bit conversion.
+ // The error is logged and the message is sent anyway.
+
+ logger.error("Error during the conversion to 7 bit.", e);
+ }
+ }
+ } else {
+ // If the transport is not the one developed by Sun we are not sure of how it
+ // handles the 8 bit mime stuff, so I convert the message to 7bit.
+ try {
+ convertTo7Bit(message);
+ } catch (IOException e) {
+ logger.error("Error during the conversion to 7 bit.", e);
+ }
+ }
+ return message;
+ }
+
+ private void closeTransport(Mail mail, HostAddress outgoingMailServer, SMTPTransport transport) {
+ if (transport != null) {
+ try {
+ // James-899: transport.close() sends QUIT to the server; if that fails
+ // (e.g. because the server has already closed the connection) the message
+ // should be considered to be delivered because the error happened outside
+ // of the mail transaction (MAIL, RCPT, DATA).
+ transport.close();
+ } catch (MessagingException e) {
+ logger.error("Warning: could not close the SMTP transport after sending mail (" + mail.getName() + ") to " + outgoingMailServer.getHostName() + " at " + outgoingMailServer.getHost() + " for " + mail.getRecipients() + "; probably the server has already closed the "
+ + "connection. Message is considered to be delivered. Exception: " + e.getMessage());
+ }
+ transport = null;
+ }
+ }
+
+ private boolean connect(HostAddress outgoingMailServer, SMTPTransport transport) {
+ try {
+ if (configuration.getAuthUser() != null) {
+ transport.connect(outgoingMailServer.getHostName(), configuration.getAuthUser(), configuration.getAuthPass());
+ } else {
+ transport.connect();
+ }
+ return true;
+ } catch (MessagingException me) {
+ // Any error on connect should cause the mailet to attempt
+ // to connect to the next SMTP server associated with this
+ // MX record. Just log the exception. We'll worry about
+ // failing the message at the end of the loop.
+
+ // Also include the stacktrace if debug is enabled. See JAMES-1257
+ if (configuration.isDebug()) {
+ logger.debug(me.getMessage(), me.getCause());
+ } else {
+ logger.info(me.getMessage());
+ }
+ return false;
+ }
+ }
+
private boolean handleTemporaryResolutionException(Mail mail, String host) {
logger.info("Temporary problem looking up mail server for host: " + host);
// temporary problems
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[42/50] [abbrv] james-project git commit: JAMES-1877 Avoid inspection
for SFE known and present on the ClassPath
Posted by ro...@apache.org.
JAMES-1877 Avoid inspection for SFE known and present on the ClassPath
This actually should improve the way return code is handled
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/aec9b2fc
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/aec9b2fc
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/aec9b2fc
Branch: refs/heads/master
Commit: aec9b2fc40b3f508c926a4432197a00a4aa0c540
Parents: b299e32
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Dec 7 10:02:52 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 18:14:26 2017 +0700
----------------------------------------------------------------------
.../remoteDelivery/EnhancedMessagingException.java | 15 +++++++++++++++
.../mailets/remoteDelivery/MailDelivrerTest.java | 2 --
2 files changed, 15 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/aec9b2fc/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/EnhancedMessagingException.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/EnhancedMessagingException.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/EnhancedMessagingException.java
index 44b40bd..61a7152 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/EnhancedMessagingException.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/EnhancedMessagingException.java
@@ -28,6 +28,9 @@ import javax.mail.internet.InternetAddress;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import com.sun.mail.smtp.SMTPAddressFailedException;
+import com.sun.mail.smtp.SMTPSendFailedException;
+import com.sun.mail.smtp.SMTPSenderFailedException;
public class EnhancedMessagingException {
@@ -76,6 +79,18 @@ public class EnhancedMessagingException {
}
private Optional<Integer> computeReturnCode() {
+ if (messagingException instanceof SMTPAddressFailedException) {
+ SMTPAddressFailedException addressFailedException = (SMTPAddressFailedException) this.messagingException;
+ return Optional.of(addressFailedException.getReturnCode());
+ }
+ if (messagingException instanceof SMTPSendFailedException) {
+ SMTPSendFailedException sendFailedException = (SMTPSendFailedException) this.messagingException;
+ return Optional.of(sendFailedException.getReturnCode());
+ }
+ if (messagingException instanceof SMTPSenderFailedException) {
+ SMTPSenderFailedException senderFailedException = (SMTPSenderFailedException) this.messagingException;
+ return Optional.of(senderFailedException.getReturnCode());
+ }
if (messagingException.getClass().getName().endsWith(".SMTPSendFailedException")
|| messagingException.getClass().getName().endsWith(".SMTPAddressSucceededException")) {
try {
http://git-wip-us.apache.org/repos/asf/james-project/blob/aec9b2fc/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
index c96e9a1..477d945 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
@@ -33,7 +33,6 @@ import org.apache.mailet.Mail;
import org.apache.mailet.base.MailAddressFixture;
import org.apache.mailet.base.test.FakeMail;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -72,7 +71,6 @@ public class MailDelivrerTest {
assertThat(executionResult).isEqualTo(ExecutionResult.temporaryFailure(sfe));
}
- @Ignore("Return code is always ignored")
@Test
public void handleSenderFailedExceptionShouldReturnPermanentFailureWhenServerException() throws Exception {
Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[20/50] [abbrv] james-project git commit: JAMES-1877 Finish flatten
DeliveryRunnable
Posted by ro...@apache.org.
JAMES-1877 Finish flatten DeliveryRunnable
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/3b02d3f3
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/3b02d3f3
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/3b02d3f3
Branch: refs/heads/master
Commit: 3b02d3f32f7d69593593acdb7c6a2ea4f7bcd386
Parents: 5742cbf
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 15:46:40 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:49 2017 +0700
----------------------------------------------------------------------
.../remoteDelivery/DeliveryRunnable.java | 282 ++++++++++---------
1 file changed, 144 insertions(+), 138 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/3b02d3f3/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index c917f19..9c31696 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -53,6 +53,7 @@ import org.apache.mailet.MailAddress;
import org.apache.mailet.MailetContext;
import org.slf4j.Logger;
+import com.google.common.base.Optional;
import com.sun.mail.smtp.SMTPTransport;
@SuppressWarnings("deprecation")
@@ -167,17 +168,14 @@ public class DeliveryRunnable implements Runnable {
*/
private boolean deliver(Mail mail, Session session) {
try {
- Boolean host = tryDeliver(mail, session);
- if (host != null) {
- return host;
- }
+ return Optional.fromNullable(tryDeliver(mail, session))
+ .or(failMessage(mail, new MessagingException("No mail server(s) available at this time."), false));
/*
* If we get here, we've exhausted the loop of servers without sending
* the message or throwing an exception. One case where this might
* happen is if we get a MessagingException on each transport.connect(),
* e.g., if there is only one server and we get a connect exception.
*/
- return failMessage(mail, new MessagingException("No mail server(s) available at this time."), false);
} catch (SendFailedException sfe) {
return handleSenderFailedException(mail, sfe);
} catch (MessagingException ex) {
@@ -197,6 +195,124 @@ public class DeliveryRunnable implements Runnable {
}
}
+ private Boolean tryDeliver(Mail mail, Session session) throws MessagingException {
+ if (mail.getRecipients().isEmpty()) {
+ logger.info("No recipients specified... not sure how this could have happened.");
+ return true;
+ }
+ if (configuration.isDebug()) {
+ logger.debug("Attempting to deliver " + mail.getName());
+ }
+
+ // Figure out which servers to try to send to. This collection
+ // will hold all the possible target servers
+ Iterator<HostAddress> targetServers;
+ if (configuration.getGatewayServer().isEmpty()) {
+ MailAddress rcpt = mail.getRecipients().iterator().next();
+ String host = rcpt.getDomain();
+
+ // Lookup the possible targets
+ try {
+ targetServers = new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logger);
+ } catch (TemporaryResolutionException e) {
+ return handleTemporaryResolutionException(mail, host);
+ }
+ if (!targetServers.hasNext()) {
+ return handleNoTargetServer(mail, host);
+ }
+ } else {
+ targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer());
+ }
+
+ return doDeliver(mail, session, mail.getMessage(), convertToInetAddr(mail.getRecipients()), targetServers);
+ }
+
+ private Boolean doDeliver(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException {
+ MessagingException lastError = null;
+
+ while (targetServers.hasNext()) {
+ try {
+ if (tryDeliveryToHost(mail, session, message, addr, targetServers.next())) {
+ return true;
+ }
+ } catch (SendFailedException sfe) {
+ lastError = handleSendFailException(mail, sfe);
+ } catch (MessagingException me) {
+ lastError = handleMessagingException(mail, me);
+ }
+ } // end while
+ // If we encountered an exception while looping through,
+ // throw the last MessagingException we caught. We only
+ // do this if we were unable to send the message to any
+ // server. If sending eventually succeeded, we exit
+ // deliver() though the return at the end of the try
+ // block.
+ if (lastError != null) {
+ throw lastError;
+ }
+ return null;
+ }
+
+ private boolean tryDeliveryToHost(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException {
+ boolean success = false;
+ Properties props = session.getProperties();
+ if (mail.getSender() == null) {
+ props.put("mail.smtp.from", "<>");
+ } else {
+ String sender = mail.getSender().toString();
+ props.put("mail.smtp.from", sender);
+ }
+ logger.debug("Attempting delivery of " + mail.getName() + " to host " + outgoingMailServer.getHostName()
+ + " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from"));
+
+ // Many of these properties are only in later JavaMail versions
+ // "mail.smtp.ehlo" //default true
+ // "mail.smtp.auth" //default false
+ // "mail.smtp.dsn.ret" //default to nothing... appended as
+ // RET= after MAIL FROM line.
+ // "mail.smtp.dsn.notify" //default to nothing...appended as
+ // NOTIFY= after RCPT TO line.
+
+ SMTPTransport transport = null;
+ try {
+ transport = (SMTPTransport) session.getTransport(outgoingMailServer);
+ transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
+ if (!connect(outgoingMailServer, transport)) {
+ success = false;
+ }
+ transport.sendMessage(adaptToTransport(message, transport), addr);
+ success = true;
+ logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() +
+ " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients());
+ outgoingMailsMetric.increment();
+ } finally {
+ closeTransport(mail, outgoingMailServer, transport);
+ }
+ return success;
+ }
+
+ private MessagingException handleMessagingException(Mail mail, MessagingException me) throws MessagingException {
+ MessagingException lastError;// MessagingException are horribly difficult to figure out what actually happened.
+ logger.debug("Exception delivering message (" + mail.getName() + ") - " + me.getMessage());
+ if ((me.getNextException() != null) && (me.getNextException() instanceof IOException)) {
+ // This is more than likely a temporary failure
+
+ // If it's an IO exception with no nested exception, it's probably
+ // some socket or weird I/O related problem.
+ lastError = me;
+ } else {
+ // This was not a connection or I/O error particular to one
+ // SMTP server of an MX set. Instead, it is almost certainly
+ // a protocol level error. In this case we assume that this
+ // is an error we'd encounter with any of the SMTP servers
+ // associated with this MX record, and we pass the exception
+ // to the code in the outer block that determines its
+ // severity.
+ throw me;
+ }
+ return lastError;
+ }
+
private boolean handleSenderFailedException(Mail mail, SendFailedException sfe) {
logSendFailedException(sfe);
@@ -313,112 +429,40 @@ public class DeliveryRunnable implements Runnable {
return deleteMessage;
}
- private Boolean tryDeliver(Mail mail, Session session) throws MessagingException {
- if (mail.getRecipients().isEmpty()) {
- logger.info("No recipients specified... not sure how this could have happened.");
- return true;
- }
- if (configuration.isDebug()) {
- logger.debug("Attempting to deliver " + mail.getName());
- }
-
- // Figure out which servers to try to send to. This collection
- // will hold all the possible target servers
- Iterator<HostAddress> targetServers;
- if (configuration.getGatewayServer().isEmpty()) {
- MailAddress rcpt = mail.getRecipients().iterator().next();
- String host = rcpt.getDomain();
+ private MessagingException handleSendFailException(Mail mail, SendFailedException sfe) throws SendFailedException {
+ logSendFailedException(sfe);
- // Lookup the possible targets
- try {
- targetServers = new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logger);
- } catch (TemporaryResolutionException e) {
- return handleTemporaryResolutionException(mail, host);
+ if (sfe.getValidSentAddresses() != null) {
+ Address[] validSent = sfe.getValidSentAddresses();
+ if (validSent.length > 0) {
+ logger.debug( "Mail (" + mail.getName() + ") sent successfully for " + Arrays.asList(validSent));
}
- if (!targetServers.hasNext()) {
- return handleNoTargetServer(mail, host);
- }
- } else {
- targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer());
}
- return doDeliver(mail, session, mail.getMessage(), convertToInetAddr(mail.getRecipients()), targetServers);
- }
-
- private Boolean doDeliver(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException {
- MessagingException lastError = null;
-
- while (targetServers.hasNext()) {
- HostAddress outgoingMailServer = targetServers.next();
- try {
- if (tryDeliveryToHost(mail, session, message, addr, outgoingMailServer)) {
- return true;
- }
- } catch (SendFailedException sfe) {
- logSendFailedException(sfe);
-
- if (sfe.getValidSentAddresses() != null) {
- Address[] validSent = sfe.getValidSentAddresses();
- if (validSent.length > 0) {
- logger.debug( "Mail (" + mail.getName() + ") sent successfully for " + Arrays.asList(validSent));
- }
- }
-
/*
* SMTPSendFailedException introduced in JavaMail 1.3.2, and
* provides detailed protocol reply code for the operation
*/
- if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
- try {
- int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
- // if 5xx, terminate this delivery attempt by
- // re-throwing the exception.
- if (returnCode >= 500 && returnCode <= 599)
- throw sfe;
- } catch (ClassCastException cce) {
- } catch (IllegalArgumentException iae) {
- }
- }
-
- if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) {
- if (configuration.isDebug())
- logger.debug("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers");
- lastError = sfe;
- } else {
- // There are no valid addresses left to send, so rethrow
+ if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
+ try {
+ int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
+ // if 5xx, terminate this delivery attempt by
+ // re-throwing the exception.
+ if (returnCode >= 500 && returnCode <= 599)
throw sfe;
- }
- } catch (MessagingException me) {
- // MessagingException are horribly difficult to figure out what actually happened.
- logger.debug("Exception delivering message (" + mail.getName() + ") - " + me.getMessage());
- if ((me.getNextException() != null) && (me.getNextException() instanceof IOException)) {
- // This is more than likely a temporary failure
-
- // If it's an IO exception with no nested exception, it's probably
- // some socket or weird I/O related problem.
- lastError = me;
- } else {
- // This was not a connection or I/O error particular to one
- // SMTP server of an MX set. Instead, it is almost certainly
- // a protocol level error. In this case we assume that this
- // is an error we'd encounter with any of the SMTP servers
- // associated with this MX record, and we pass the exception
- // to the code in the outer block that determines its
- // severity.
- throw me;
- }
+ } catch (ClassCastException cce) {
+ } catch (IllegalArgumentException iae) {
}
- } // end while
- // If we encountered an exception while looping through,
- // throw the last MessagingException we caught. We only
- // do this if we were unable to send the message to any
- // server. If sending eventually succeeded, we exit
- // deliver() though the return at the end of the try
- // block.
- if (lastError != null) {
- throw lastError;
}
- return null;
+
+ if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) {
+ if (configuration.isDebug())
+ logger.debug("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers");
+ return sfe;
+ } else {
+ // There are no valid addresses left to send, so rethrow
+ throw sfe;
+ }
}
private InternetAddress[] convertToInetAddr(Collection<MailAddress> recipients) {
@@ -431,44 +475,6 @@ public class DeliveryRunnable implements Runnable {
return addr;
}
- private boolean tryDeliveryToHost(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException {
- boolean success = false;
- Properties props = session.getProperties();
- if (mail.getSender() == null) {
- props.put("mail.smtp.from", "<>");
- } else {
- String sender = mail.getSender().toString();
- props.put("mail.smtp.from", sender);
- }
- logger.debug("Attempting delivery of " + mail.getName() + " to host " + outgoingMailServer.getHostName()
- + " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from"));
-
- // Many of these properties are only in later JavaMail versions
- // "mail.smtp.ehlo" //default true
- // "mail.smtp.auth" //default false
- // "mail.smtp.dsn.ret" //default to nothing... appended as
- // RET= after MAIL FROM line.
- // "mail.smtp.dsn.notify" //default to nothing...appended as
- // NOTIFY= after RCPT TO line.
-
- SMTPTransport transport = null;
- try {
- transport = (SMTPTransport) session.getTransport(outgoingMailServer);
- transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
- if (!connect(outgoingMailServer, transport)) {
- success = false;
- }
- transport.sendMessage(adaptToTransport(message, transport), addr);
- success = true;
- logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() +
- " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients());
- outgoingMailsMetric.increment();
- } finally {
- closeTransport(mail, outgoingMailServer, transport);
- }
- return success;
- }
-
private MimeMessage adaptToTransport(MimeMessage message, SMTPTransport transport) throws MessagingException {
// if the transport is a SMTPTransport (from sun) some
// performance enhancement can be done.
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[41/50] [abbrv] james-project git commit: JAMES-1877 Refactor
DnsHelper
Posted by ro...@apache.org.
JAMES-1877 Refactor DnsHelper
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/b299e326
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/b299e326
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/b299e326
Branch: refs/heads/master
Commit: b299e3265423bcd64a3be52e0cc10d4f02c75120
Parents: 1f01e8a
Author: Benoit Tellier <bt...@linagora.com>
Authored: Fri Dec 2 14:38:00 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 18:14:26 2017 +0700
----------------------------------------------------------------------
.../mailets/remoteDelivery/DnsHelper.java | 23 +++-----------------
1 file changed, 3 insertions(+), 20 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/b299e326/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DnsHelper.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DnsHelper.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DnsHelper.java
index 5e92040..6d396be 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DnsHelper.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DnsHelper.java
@@ -19,7 +19,6 @@
package org.apache.james.transport.mailets.remoteDelivery;
-import java.util.Collection;
import java.util.Iterator;
import org.apache.james.dnsservice.api.DNSService;
@@ -31,6 +30,7 @@ import org.slf4j.Logger;
@SuppressWarnings("deprecation")
public class DnsHelper {
+ public static final boolean USE_SEVERAL_IP = false;
private final DNSService dnsServer;
private final RemoteDeliveryConfiguration configuration;
private final Logger logger;
@@ -43,27 +43,10 @@ public class DnsHelper {
public Iterator<HostAddress> retrieveHostAddressIterator(String host) throws TemporaryResolutionException {
if (configuration.getGatewayServer().isEmpty()) {
- return new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logger);
+ return new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, USE_SEVERAL_IP, logger);
} else {
- return getGatewaySMTPHostAddresses(configuration.getGatewayServer());
+ return new MXHostAddressIterator(configuration.getGatewayServer().iterator(), dnsServer, USE_SEVERAL_IP, logger);
}
}
- /**
- * Returns an Iterator over org.apache.mailet.HostAddress, a specialized
- * subclass of javax.mail.URLName, which provides location information for
- * servers that are specified as mail handlers for the given hostname. If no
- * host is found, the Iterator returned will be empty and the first call to
- * hasNext() will return false. The Iterator is a nested iterator: the outer
- * iteration is over each gateway, and the inner iteration is over
- * potentially multiple A records for each gateway.
- *
- * @param gatewayServers - Collection of host[:port] Strings
- * @return an Iterator over HostAddress instances, sorted by priority
- * @since v2.2.0a16-unstable
- */
- private Iterator<HostAddress> getGatewaySMTPHostAddresses(Collection<String> gatewayServers) {
- return new MXHostAddressIterator(gatewayServers.iterator(), dnsServer, false, logger);
- }
-
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[09/50] [abbrv] james-project git commit: JAMES-1877 Extract
DeliveryRunnable from RemoteDelivery
Posted by ro...@apache.org.
JAMES-1877 Extract DeliveryRunnable from RemoteDelivery
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/4a5a4ba6
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/4a5a4ba6
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/4a5a4ba6
Branch: refs/heads/master
Commit: 4a5a4ba660ebb8e9a6f1e2446a65527e1fa8fd37
Parents: 69f66c7
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Nov 30 19:30:37 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:04:32 2017 +0700
----------------------------------------------------------------------
.../james/transport/mailets/RemoteDelivery.java | 931 +-----------------
.../remoteDelivery/DeliveryRunnable.java | 963 +++++++++++++++++++
.../remoteDelivery/VolatileIsDestroyed.java | 36 +
.../remoteDelivery/VolatileIsDestroyedTest.java | 41 +
4 files changed, 1055 insertions(+), 916 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/4a5a4ba6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index c4c18d2..e7db2c8 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -19,61 +19,34 @@
package org.apache.james.transport.mailets;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.ConnectException;
-import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
-import java.util.Date;
import java.util.Hashtable;
-import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
-import java.util.Properties;
import java.util.Vector;
-import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
-import javax.mail.Address;
import javax.mail.MessagingException;
-import javax.mail.SendFailedException;
-import javax.mail.Session;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMultipart;
-import javax.mail.internet.MimePart;
-import javax.mail.internet.ParseException;
import org.apache.james.dnsservice.api.DNSService;
-import org.apache.james.dnsservice.api.TemporaryResolutionException;
-import org.apache.james.dnsservice.library.MXHostAddressIterator;
import org.apache.james.domainlist.api.DomainList;
-import org.apache.james.lifecycle.api.LifecycleUtil;
import org.apache.james.metrics.api.Metric;
import org.apache.james.metrics.api.MetricFactory;
import org.apache.james.queue.api.MailPrioritySupport;
import org.apache.james.queue.api.MailQueue;
import org.apache.james.queue.api.MailQueue.MailQueueException;
-import org.apache.james.queue.api.MailQueue.MailQueueItem;
import org.apache.james.queue.api.MailQueueFactory;
-import org.apache.james.transport.mailets.remoteDelivery.Delay;
+import org.apache.james.transport.mailets.remoteDelivery.DeliveryRunnable;
import org.apache.james.transport.mailets.remoteDelivery.RemoteDeliveryConfiguration;
import org.apache.james.transport.mailets.remoteDelivery.RemoteDeliverySocketFactory;
-import org.apache.mailet.HostAddress;
+import org.apache.james.transport.mailets.remoteDelivery.VolatileIsDestroyed;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
-import org.apache.mailet.MailetContext;
import org.apache.mailet.base.GenericMailet;
import org.slf4j.Logger;
-import com.sun.mail.smtp.SMTPTransport;
-
/**
* <p>The RemoteDelivery mailet delivers messages to a remote SMTP server able to deliver or forward messages to their final
* destination.
@@ -144,8 +117,7 @@ import com.sun.mail.smtp.SMTPTransport;
* <li><b>debug</b> (optional) - a Boolean (true/false) indicating whether debugging is on. Default is false.</li>
* </ul>
*/
-@SuppressWarnings("deprecation")
-public class RemoteDelivery extends GenericMailet implements Runnable {
+public class RemoteDelivery extends GenericMailet {
private static final String OUTGOING_MAILS = "outgoingMails";
@@ -154,16 +126,12 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
private final MailQueueFactory queueFactory;
private final Metric outgoingMailsMetric;
private final Collection<Thread> workersThreads;
+ private final VolatileIsDestroyed volatileIsDestroyed;
private MailQueue queue;
private Logger logger;
private RemoteDeliveryConfiguration configuration;
- /**
- * Flag used by 'run' method to end itself.
- */
- private volatile boolean destroyed = false;
-
@Inject
public RemoteDelivery(DNSService dnsServer, DomainList domainList, MailQueueFactory queueFactory, MetricFactory metricFactory) {
this.dnsServer = dnsServer;
@@ -171,6 +139,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
this.queueFactory = queueFactory;
this.outgoingMailsMetric = metricFactory.generate(OUTGOING_MAILS);
this.workersThreads = new Vector<Thread>();
+ this.volatileIsDestroyed = new VolatileIsDestroyed();
}
/**
@@ -195,25 +164,20 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
private void initDeliveryThreads() {
for (int a = 0; a < configuration.getWorkersThreadCount(); a++) {
String threadName = "Remote delivery thread (" + a + ")";
- Thread t = new Thread(this, threadName);
+ Thread t = new Thread(
+ new DeliveryRunnable(queue,
+ configuration,
+ dnsServer,
+ outgoingMailsMetric,
+ logger,
+ getMailetContext(),
+ volatileIsDestroyed),
+ threadName);
t.start();
workersThreads.add(t);
}
}
- /**
- * This method returns, given a retry-count, the next delay time to use.
- *
- * @param retry_count the current retry_count.
- * @return the next delay time to use, given the retry count
- */
- private long getNextDelay(int retry_count) {
- if (retry_count > configuration.getDelayTimes().size()) {
- return Delay.DEFAULT_DELAY_TIME;
- }
- return configuration.getDelayTimes().get(retry_count - 1);
- }
-
@Override
public String getMailetInfo() {
return "RemoteDelivery Mailet";
@@ -302,9 +266,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
*/
@Override
public synchronized void destroy() {
- // Mark flag so threads from this Mailet stop themselves
- destroyed = true;
-
+ volatileIsDestroyed.markAsDestroyed();
// Wake up all threads from waiting for an accept
for (Thread t : workersThreads) {
t.interrupt();
@@ -312,867 +274,4 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
notifyAll();
}
- /**
- * Handles checking the outgoing spool for new mail and delivering them if
- * there are any
- */
- @Override
- public void run() {
- final Session session = obtainSession(configuration.createFinalJavaxProperties());
- try {
- while (!Thread.interrupted() && !destroyed) {
- try {
- // Get the 'mail' object that is ready for deliverying. If
- // no
- // message is
- // ready, the 'accept' will block until message is ready.
- // The amount
- // of time to block is determined by the 'getWaitTime'
- // method of the
- // MultipleDelayFilter.
- MailQueueItem queueItem = queue.deQueue();
- Mail mail = queueItem.getMail();
-
- String key = mail.getName();
-
- try {
- if (configuration.isDebug()) {
- String message = Thread.currentThread().getName() + " will process mail " + key;
- log(message);
- }
-
- // Deliver message
- if (deliver(mail, session)) {
- // Message was successfully delivered/fully
- // failed...
- // delete it
- LifecycleUtil.dispose(mail);
- // workRepository.remove(key);
- } else {
- // Something happened that will delay delivery.
- // Store it back in the retry repository.
- // workRepository.store(mail);
- int retries = 0;
- try {
- retries = Integer.parseInt(mail.getErrorMessage());
- } catch (NumberFormatException e) {
- // Something strange was happen with the
- // errorMessage..
- }
-
- long delay = getNextDelay(retries);
-
- if (configuration.isUsePriority()) {
- // Use lowest priority for retries. See JAMES-1311
- mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY);
- }
- queue.enQueue(mail, delay, TimeUnit.MILLISECONDS);
- LifecycleUtil.dispose(mail);
-
- // This is an update, so we have to unlock and
- // notify or this mail is kept locked by this
- // thread.
- // workRepository.unlock(key);
-
- // Note: We do not notify because we updated an
- // already existing mail and we are now free to
- // handle
- // more mails.
- // Furthermore this mail should not be processed now
- // because we have a retry time scheduling.
- }
-
- // Clear the object handle to make sure it recycles
- // this object.
- mail = null;
- queueItem.done(true);
- } catch (Exception e) {
- // Prevent unexpected exceptions from causing looping by
- // removing message from outgoing.
- // DO NOT CHANGE THIS to catch Error! For example, if
- // there were an OutOfMemory condition caused because
- // something else in the server was abusing memory, we
- // would
- // not want to start purging the retrying spool!
- log("Exception caught in RemoteDelivery.run()", e);
- LifecycleUtil.dispose(mail);
- // workRepository.remove(key);
- queueItem.done(false);
- throw new MailQueueException("Unable to perform dequeue", e);
- }
-
- } catch (Throwable e) {
- if (!destroyed) {
- log("Exception caught in RemoteDelivery.run()", e);
- }
- }
- }
- } finally {
- // Restore the thread state to non-interrupted.
- Thread.interrupted();
- }
- }
-
- /**
- * We can assume that the recipients of this message are all going to the
- * same mail server. We will now rely on the DNS server to do DNS MX record
- * lookup and try to deliver to the multiple mail servers. If it fails, it
- * should throw an exception.
- *
- * @param mail org.apache.james.core.MailImpl
- * @param session javax.mail.Session
- * @return boolean Whether the delivery was successful and the message can
- * be deleted
- */
- private boolean deliver(Mail mail, Session session) {
- try {
- if (configuration.isDebug()) {
- log("Attempting to deliver " + mail.getName());
- }
- MimeMessage message = mail.getMessage();
-
- // Create an array of the recipients as InternetAddress objects
- Collection<MailAddress> recipients = mail.getRecipients();
- InternetAddress addr[] = new InternetAddress[recipients.size()];
- int j = 0;
- for (Iterator<MailAddress> i = recipients.iterator(); i.hasNext(); j++) {
- MailAddress rcpt = i.next();
- addr[j] = rcpt.toInternetAddress();
- }
-
- if (addr.length <= 0) {
- log("No recipients specified... not sure how this could have happened.");
- return true;
- }
-
- // Figure out which servers to try to send to. This collection
- // will hold all the possible target servers
- Iterator<HostAddress> targetServers;
- if (configuration.getGatewayServer() == null) {
- MailAddress rcpt = recipients.iterator().next();
- String host = rcpt.getDomain();
-
- // Lookup the possible targets
- try {
- targetServers = new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logger);
- } catch (TemporaryResolutionException e) {
- log("Temporary problem looking up mail server for host: " + host);
- String exceptionBuffer = "Temporary problem looking up mail server for host: " + host + ". I cannot determine where to send this message.";
-
- // temporary problems
- return failMessage(mail, new MessagingException(exceptionBuffer), false);
- }
- if (!targetServers.hasNext()) {
- log("No mail server found for: " + host);
- String exceptionBuffer = "There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.";
-
- int retry = 0;
- try {
- retry = Integer.parseInt(mail.getErrorMessage());
- } catch (NumberFormatException e) {
- // Unable to parse retryCount
- }
- if (retry == 0 || retry > configuration.getDnsProblemRetry()) {
- // The domain has no dns entry.. Return a permanent
- // error
- return failMessage(mail, new MessagingException(exceptionBuffer), true);
- } else {
- return failMessage(mail, new MessagingException(exceptionBuffer), false);
- }
- }
- } else {
- targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer());
- }
-
- MessagingException lastError = null;
-
- while (targetServers.hasNext()) {
- try {
-
- Properties props = session.getProperties();
- if (mail.getSender() == null) {
- props.put("mail.smtp.from", "<>");
- } else {
- String sender = mail.getSender().toString();
- props.put("mail.smtp.from", sender);
- }
-
- HostAddress outgoingMailServer = targetServers.next();
- StringBuilder logMessageBuffer = new StringBuilder(256).append("Attempting delivery of ").append(mail.getName()).append(" to host ").append(outgoingMailServer.getHostName()).append(" at ").append(outgoingMailServer.getHost()).append(" from ").append(props.get("mail.smtp.from"))
- .append(" for addresses ").append(Arrays.asList(addr));
- log(logMessageBuffer.toString());
-
- // Many of these properties are only in later JavaMail
- // versions
- // "mail.smtp.ehlo" //default true
- // "mail.smtp.auth" //default false
- // "mail.smtp.dsn.ret" //default to nothing... appended as
- // RET= after MAIL FROM line.
- // "mail.smtp.dsn.notify" //default to nothing...appended as
- // NOTIFY= after RCPT TO line.
-
- SMTPTransport transport = null;
- try {
- transport = (SMTPTransport) session.getTransport(outgoingMailServer);
- transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
- try {
- if (configuration.getAuthUser() != null) {
- transport.connect(outgoingMailServer.getHostName(), configuration.getAuthUser(), configuration.getAuthPass());
- } else {
- transport.connect();
- }
- } catch (MessagingException me) {
- // Any error on connect should cause the mailet to
- // attempt
- // to connect to the next SMTP server associated
- // with this
- // MX record. Just log the exception. We'll worry
- // about
- // failing the message at the end of the loop.
-
- // Also include the stacktrace if debug is enabled. See JAMES-1257
- if (configuration.isDebug()) {
- log(me.getMessage(), me.getCause());
- } else {
- log(me.getMessage());
- }
- continue;
- }
- // if the transport is a SMTPTransport (from sun) some
- // performance enhancement can be done.
- if (transport.getClass().getName().endsWith(".SMTPTransport")) {
- boolean supports8bitmime = false;
- try {
- Method supportsExtension = transport.getClass().getMethod("supportsExtension", new Class[]{String.class});
- supports8bitmime = (Boolean) supportsExtension.invoke(transport, "8BITMIME");
- } catch (NoSuchMethodException nsme) {
- // An SMTPAddressFailedException with no
- // getAddress method.
- } catch (IllegalAccessException iae) {
- } catch (IllegalArgumentException iae) {
- } catch (InvocationTargetException ite) {
- // Other issues with getAddress invokation.
- }
-
- // if the message is alredy 8bit or binary and the
- // server doesn't support the 8bit extension it has
- // to be converted to 7bit. Javamail api doesn't
- // perform
- // that conversion, but it is required to be a
- // rfc-compliant smtp server.
-
- // Temporarily disabled. See JAMES-638
- if (!supports8bitmime) {
- try {
- convertTo7Bit(message);
- } catch (IOException e) {
- // An error has occured during the 7bit
- // conversion.
- // The error is logged and the message is
- // sent anyway.
-
- log("Error during the conversion to 7 bit.", e);
- }
- }
- } else {
- // If the transport is not the one
- // developed by Sun we are not sure of how it
- // handles the 8 bit mime stuff,
- // so I convert the message to 7bit.
- try {
- convertTo7Bit(message);
- } catch (IOException e) {
- log("Error during the conversion to 7 bit.", e);
- }
- }
- transport.sendMessage(message, addr);
- } finally {
- if (transport != null) {
- try {
- // James-899: transport.close() sends QUIT to
- // the server; if that fails
- // (e.g. because the server has already closed
- // the connection) the message
- // should be considered to be delivered because
- // the error happened outside
- // of the mail transaction (MAIL, RCPT, DATA).
- transport.close();
- } catch (MessagingException e) {
- log("Warning: could not close the SMTP transport after sending mail (" + mail.getName() + ") to " + outgoingMailServer.getHostName() + " at " + outgoingMailServer.getHost() + " for " + mail.getRecipients() + "; probably the server has already closed the "
- + "connection. Message is considered to be delivered. Exception: " + e.getMessage());
- }
- transport = null;
- }
- }
- logMessageBuffer = new StringBuilder(256).append("Mail (").append(mail.getName()).append(") sent successfully to ").append(outgoingMailServer.getHostName()).append(" at ").append(outgoingMailServer.getHost()).append(" from ").append(props.get("mail.smtp.from")).append(" for ")
- .append(mail.getRecipients());
- log(logMessageBuffer.toString());
- outgoingMailsMetric.increment();
- return true;
- } catch (SendFailedException sfe) {
- logSendFailedException(sfe);
-
- if (sfe.getValidSentAddresses() != null) {
- Address[] validSent = sfe.getValidSentAddresses();
- if (validSent.length > 0) {
- String logMessageBuffer = "Mail (" + mail.getName() + ") sent successfully for " + Arrays.asList(validSent);
- log(logMessageBuffer);
- }
- }
-
- /*
- * SMTPSendFailedException introduced in JavaMail 1.3.2, and
- * provides detailed protocol reply code for the operation
- */
- if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
- try {
- int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
- // if 5xx, terminate this delivery attempt by
- // re-throwing the exception.
- if (returnCode >= 500 && returnCode <= 599)
- throw sfe;
- } catch (ClassCastException cce) {
- } catch (IllegalArgumentException iae) {
- }
- }
-
- if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) {
- if (configuration.isDebug())
- log("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers");
- lastError = sfe;
- } else {
- // There are no valid addresses left to send, so rethrow
- throw sfe;
- }
- } catch (MessagingException me) {
- // MessagingException are horribly difficult to figure out
- // what actually happened.
- String exceptionBuffer = "Exception delivering message (" + mail.getName() + ") - " + me.getMessage();
- log(exceptionBuffer);
- if ((me.getNextException() != null) && (me.getNextException() instanceof java.io.IOException)) {
- // This is more than likely a temporary failure
-
- // If it's an IO exception with no nested exception,
- // it's probably
- // some socket or weird I/O related problem.
- lastError = me;
- continue;
- }
- // This was not a connection or I/O error particular to one
- // SMTP server of an MX set. Instead, it is almost certainly
- // a protocol level error. In this case we assume that this
- // is an error we'd encounter with any of the SMTP servers
- // associated with this MX record, and we pass the exception
- // to the code in the outer block that determines its
- // severity.
- throw me;
- }
- } // end while
- // If we encountered an exception while looping through,
- // throw the last MessagingException we caught. We only
- // do this if we were unable to send the message to any
- // server. If sending eventually succeeded, we exit
- // deliver() though the return at the end of the try
- // block.
- if (lastError != null) {
- throw lastError;
- }
- } catch (SendFailedException sfe) {
- logSendFailedException(sfe);
-
- // Copy the recipients as direct modification may not be possible
- Collection<MailAddress> recipients = new ArrayList<MailAddress>(mail.getRecipients());
-
- boolean deleteMessage = false;
-
- /*
- * If you send a message that has multiple invalid addresses, you'll
- * get a top-level SendFailedException that that has the valid,
- * valid-unsent, and invalid address lists, with all of the server
- * response messages will be contained within the nested exceptions.
- * [Note: the content of the nested exceptions is implementation
- * dependent.]
- *
- * sfe.getInvalidAddresses() should be considered permanent.
- * sfe.getValidUnsentAddresses() should be considered temporary.
- *
- * JavaMail v1.3 properly populates those collections based upon the
- * 4xx and 5xx response codes to RCPT TO. Some servers, such as
- * Yahoo! don't respond to the RCPT TO, and provide a 5xx reply
- * after DATA. In that case, we will pick up the failure from
- * SMTPSendFailedException.
- */
-
- /*
- * SMTPSendFailedException introduced in JavaMail 1.3.2, and
- * provides detailed protocol reply code for the operation
- */
- try {
- if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
- int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
- // If we got an SMTPSendFailedException, use its RetCode to
- // determine default permanent/temporary failure
- deleteMessage = (returnCode >= 500 && returnCode <= 599);
- } else {
- // Sometimes we'll get a normal SendFailedException with
- // nested SMTPAddressFailedException, so use the latter
- // RetCode
- MessagingException me = sfe;
- Exception ne;
- while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
- me = (MessagingException) ne;
- if (me.getClass().getName().endsWith(".SMTPAddressFailedException")) {
- int returnCode = (Integer) invokeGetter(me, "getReturnCode");
- deleteMessage = (returnCode >= 500 && returnCode <= 599);
- }
- }
- }
- } catch (IllegalStateException ise) {
- // unexpected exception (not a compatible javamail
- // implementation)
- } catch (ClassCastException cce) {
- // unexpected exception (not a compatible javamail
- // implementation)
- }
-
- // log the original set of intended recipients
- if (configuration.isDebug())
- log("Recipients: " + recipients);
-
- if (sfe.getInvalidAddresses() != null) {
- Address[] address = sfe.getInvalidAddresses();
- if (address.length > 0) {
- recipients.clear();
- for (Address addres : address) {
- try {
- recipients.add(new MailAddress(addres.toString()));
- } catch (ParseException pe) {
- // this should never happen ... we should have
- // caught malformed addresses long before we
- // got to this code.
- log("Can't parse invalid address: " + pe.getMessage());
- }
- }
- // Set the recipients for the mail
- mail.setRecipients(recipients);
-
- if (configuration.isDebug())
- log("Invalid recipients: " + recipients);
- deleteMessage = failMessage(mail, sfe, true);
- }
- }
-
- if (sfe.getValidUnsentAddresses() != null) {
- Address[] address = sfe.getValidUnsentAddresses();
- if (address.length > 0) {
- recipients.clear();
- for (Address addres : address) {
- try {
- recipients.add(new MailAddress(addres.toString()));
- } catch (ParseException pe) {
- // this should never happen ... we should have
- // caught malformed addresses long before we
- // got to this code.
- log("Can't parse unsent address: " + pe.getMessage());
- }
- }
- // Set the recipients for the mail
- mail.setRecipients(recipients);
- if (configuration.isDebug())
- log("Unsent recipients: " + recipients);
- if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
- int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
- deleteMessage = failMessage(mail, sfe, returnCode >= 500 && returnCode <= 599);
- } else {
- deleteMessage = failMessage(mail, sfe, false);
- }
- }
- }
-
-
- return deleteMessage;
- } catch (MessagingException ex) {
- // We should do a better job checking this... if the failure is a
- // general
- // connect exception, this is less descriptive than more specific
- // SMTP command
- // failure... have to lookup and see what are the various Exception
- // possibilities
-
- // Unable to deliver message after numerous tries... fail
- // accordingly
-
- // We check whether this is a 5xx error message, which
- // indicates a permanent failure (like account doesn't exist
- // or mailbox is full or domain is setup wrong).
- // We fail permanently if this was a 5xx error
- return failMessage(mail, ex, ('5' == ex.getMessage().charAt(0)));
- } catch (Exception ex) {
- log("Generic exception = permanent failure: "+ex.getMessage(), ex);
- // Generic exception = permanent failure
- return failMessage(mail, ex, true);
- }
-
- /*
- * If we get here, we've exhausted the loop of servers without sending
- * the message or throwing an exception. One case where this might
- * happen is if we get a MessagingException on each transport.connect(),
- * e.g., if there is only one server and we get a connect exception.
- */
- return failMessage(mail, new MessagingException("No mail server(s) available at this time."), false);
- }
-
- /**
- * Try to return a usefull logString created of the Exception which was
- * given. Return null if nothing usefull could be done
- *
- * @param e The MessagingException to use
- * @return logString
- */
- private String exceptionToLogString(Exception e) {
- if (e.getClass().getName().endsWith(".SMTPSendFailedException")) {
- return "RemoteHost said: " + e.getMessage();
- } else if (e instanceof SendFailedException) {
- SendFailedException exception = (SendFailedException) e;
-
- // No error
- if (exception.getInvalidAddresses().length == 0 && exception.getValidUnsentAddresses().length == 0)
- return null;
-
- Exception ex;
- StringBuilder sb = new StringBuilder();
- boolean smtpExFound = false;
- sb.append("RemoteHost said:");
-
- if (e instanceof MessagingException)
- while ((ex = ((MessagingException) e).getNextException()) != null && ex instanceof MessagingException) {
- e = ex;
- if (ex.getClass().getName().endsWith(".SMTPAddressFailedException")) {
- try {
- InternetAddress ia = (InternetAddress) invokeGetter(ex, "getAddress");
- sb.append(" ( ").append(ia).append(" - [").append(ex.getMessage().replaceAll("\\n", "")).append("] )");
- smtpExFound = true;
- } catch (IllegalStateException ise) {
- // Error invoking the getAddress method
- } catch (ClassCastException cce) {
- // The getAddress method returned something
- // different than InternetAddress
- }
- }
- }
- if (!smtpExFound) {
- boolean invalidAddr = false;
- sb.append(" ( ");
-
- if (exception.getInvalidAddresses().length > 0) {
- sb.append(Arrays.toString(exception.getInvalidAddresses()));
- invalidAddr = true;
- }
- if (exception.getValidUnsentAddresses().length > 0) {
- if (invalidAddr)
- sb.append(" ");
- sb.append(Arrays.toString(exception.getValidUnsentAddresses()));
- }
- sb.append(" - [");
- sb.append(exception.getMessage().replaceAll("\\n", ""));
- sb.append("] )");
- }
- return sb.toString();
- }
- return null;
- }
-
- /**
- * Utility method used to invoke getters for javamail implementation
- * specific classes.
- *
- * @param target the object whom method will be invoked
- * @param getter the no argument method name
- * @return the result object
- * @throws IllegalStateException on invocation error
- */
- private Object invokeGetter(Object target, String getter) {
- try {
- Method getAddress = target.getClass().getMethod(getter);
- return getAddress.invoke(target);
- } catch (NoSuchMethodException nsme) {
- // An SMTPAddressFailedException with no getAddress method.
- } catch (IllegalAccessException iae) {
- } catch (IllegalArgumentException iae) {
- } catch (InvocationTargetException ite) {
- // Other issues with getAddress invokation.
- }
- return new IllegalStateException("Exception invoking " + getter + " on a " + target.getClass() + " object");
- }
-
- /*
- * private method to log the extended SendFailedException introduced in
- * JavaMail 1.3.2.
- */
- private void logSendFailedException(SendFailedException sfe) {
- if (configuration.isDebug()) {
- MessagingException me = sfe;
- if (me.getClass().getName().endsWith(".SMTPSendFailedException")) {
- try {
- String command = (String) invokeGetter(sfe, "getCommand");
- Integer returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
- log("SMTP SEND FAILED:");
- log(sfe.toString());
- log(" Command: " + command);
- log(" RetCode: " + returnCode);
- log(" Response: " + sfe.getMessage());
- } catch (IllegalStateException ise) {
- // Error invoking the getAddress method
- log("Send failed: " + me.toString());
- } catch (ClassCastException cce) {
- // The getAddress method returned something different than
- // InternetAddress
- log("Send failed: " + me.toString());
- }
- } else {
- log("Send failed: " + me.toString());
- }
- Exception ne;
- while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
- me = (MessagingException) ne;
- if (me.getClass().getName().endsWith(".SMTPAddressFailedException") || me.getClass().getName().endsWith(".SMTPAddressSucceededException")) {
- try {
- String action = me.getClass().getName().endsWith(".SMTPAddressFailedException") ? "FAILED" : "SUCCEEDED";
- InternetAddress address = (InternetAddress) invokeGetter(me, "getAddress");
- String command = (String) invokeGetter(me, "getCommand");
- Integer returnCode = (Integer) invokeGetter(me, "getReturnCode");
- log("ADDRESS " + action + ":");
- log(me.toString());
- log(" Address: " + address);
- log(" Command: " + command);
- log(" RetCode: " + returnCode);
- log(" Response: " + me.getMessage());
- } catch (IllegalStateException ise) {
- // Error invoking the getAddress method
- } catch (ClassCastException cce) {
- // A method returned something different than expected
- }
- }
- }
- }
- }
-
- /**
- * Converts a message to 7 bit.
- *
- * @param part
- */
- private void convertTo7Bit(MimePart part) throws MessagingException, IOException {
- if (part.isMimeType("multipart/*")) {
- MimeMultipart parts = (MimeMultipart) part.getContent();
- int count = parts.getCount();
- for (int i = 0; i < count; i++) {
- convertTo7Bit((MimePart) parts.getBodyPart(i));
- }
- } else if ("8bit".equals(part.getEncoding())) {
- // The content may already be in encoded the form (likely with mail
- // created from a
- // stream). In that case, just changing the encoding to
- // quoted-printable will mangle
- // the result when this is transmitted. We must first convert the
- // content into its
- // native format, set it back, and only THEN set the transfer
- // encoding to force the
- // content to be encoded appropriately.
-
- // if the part doesn't contain text it will be base64 encoded.
- String contentTransferEncoding = part.isMimeType("text/*") ? "quoted-printable" : "base64";
- part.setContent(part.getContent(), part.getContentType());
- part.setHeader("Content-Transfer-Encoding", contentTransferEncoding);
- part.addHeader("X-MIME-Autoconverted", "from 8bit to " + contentTransferEncoding + " by " + getMailetContext().getServerInfo());
- }
- }
-
- /**
- * Insert the method's description here.
- *
- * @param mail org.apache.james.core.MailImpl
- * @param ex javax.mail.MessagingException
- * @param permanent
- * @return boolean Whether the message failed fully and can be deleted
- */
- private boolean failMessage(Mail mail, Exception ex, boolean permanent) {
- StringWriter sout = new StringWriter();
- PrintWriter out = new PrintWriter(sout, true);
- if (permanent) {
- out.print("Permanent");
- } else {
- out.print("Temporary");
- }
-
- String exceptionLog = exceptionToLogString(ex);
-
- StringBuilder logBuffer = new StringBuilder(64).append(" exception delivering mail (").append(mail.getName());
-
- if (exceptionLog != null) {
- logBuffer.append(". ");
- logBuffer.append(exceptionLog);
- }
-
- logBuffer.append(": ");
- out.print(logBuffer.toString());
- if (configuration.isDebug())
- ex.printStackTrace(out);
- log(sout.toString());
- if (!permanent) {
- if (!mail.getState().equals(Mail.ERROR)) {
- mail.setState(Mail.ERROR);
- mail.setErrorMessage("0");
- mail.setLastUpdated(new Date());
- }
-
- int retries = 0;
- try {
- retries = Integer.parseInt(mail.getErrorMessage());
- } catch (NumberFormatException e) {
- // Something strange was happen with the errorMessage..
- }
-
- if (retries < configuration.getMaxRetries()) {
- logBuffer = new StringBuilder(128).append("Storing message ").append(mail.getName()).append(" into outgoing after ").append(retries).append(" retries");
- log(logBuffer.toString());
- ++retries;
- mail.setErrorMessage(retries + "");
- mail.setLastUpdated(new Date());
- return false;
- } else {
- logBuffer = new StringBuilder(128).append("Bouncing message ").append(mail.getName()).append(" after ").append(retries).append(" retries");
- log(logBuffer.toString());
- }
- }
-
- if (mail.getSender() == null) {
- log("Null Sender: no bounce will be generated for " + mail.getName());
- return true;
- }
-
- if (configuration.getBounceProcessor() != null) {
- // do the new DSN bounce
- // setting attributes for DSN mailet
- String cause;
- if (ex instanceof MessagingException) {
- cause = getErrorMsg((MessagingException) ex);
- } else {
- cause = ex.getMessage();
- }
- mail.setAttribute("delivery-error", cause);
- mail.setState(configuration.getBounceProcessor());
- // re-insert the mail into the spool for getting it passed to the
- // dsn-processor
- MailetContext mc = getMailetContext();
- try {
- mc.sendMail(mail);
- } catch (MessagingException e) {
- // we shouldn't get an exception, because the mail was already
- // processed
- log("Exception re-inserting failed mail: ", e);
- }
- } else {
- // do an old style bounce
- bounce(mail, ex);
- }
- return true;
- }
-
- /**
- * Utility method for getting the error message from the (nested) exception.
- *
- * @param me MessagingException
- * @return error message
- */
- protected String getErrorMsg(MessagingException me) {
- if (me.getNextException() == null) {
- return me.getMessage().trim();
- } else {
- Exception ex1 = me.getNextException();
- return ex1.getMessage().trim();
- }
- }
-
- private void bounce(Mail mail, Exception ex) {
- StringWriter sout = new StringWriter();
- PrintWriter out = new PrintWriter(sout, true);
- String machine;
- try {
- machine = configuration.getHeloNameProvider().getHeloName();
-
- } catch (Exception e) {
- machine = "[address unknown]";
- }
- String bounceBuffer = "Hi. This is the James mail server at " + machine + ".";
- out.println(bounceBuffer);
- out.println("I'm afraid I wasn't able to deliver your message to the following addresses.");
- out.println("This is a permanent error; I've given up. Sorry it didn't work out. Below");
- out.println("I include the list of recipients and the reason why I was unable to deliver");
- out.println("your message.");
- out.println();
- for (MailAddress mailAddress : mail.getRecipients()) {
- out.println(mailAddress);
- }
- if (ex instanceof MessagingException) {
- if (((MessagingException) ex).getNextException() == null) {
- out.println(ex.getMessage().trim());
- } else {
- Exception ex1 = ((MessagingException) ex).getNextException();
- if (ex1 instanceof SendFailedException) {
- out.println("Remote mail server told me: " + ex1.getMessage().trim());
- } else if (ex1 instanceof UnknownHostException) {
- out.println("Unknown host: " + ex1.getMessage().trim());
- out.println("This could be a DNS server error, a typo, or a problem with the recipient's mail server.");
- } else if (ex1 instanceof ConnectException) {
- // Already formatted as "Connection timed out: connect"
- out.println(ex1.getMessage().trim());
- } else if (ex1 instanceof SocketException) {
- out.println("Socket exception: " + ex1.getMessage().trim());
- } else {
- out.println(ex1.getMessage().trim());
- }
- }
- }
- out.println();
-
- log("Sending failure message " + mail.getName());
- try {
- getMailetContext().bounce(mail, sout.toString());
- } catch (MessagingException me) {
- log("Encountered unexpected messaging exception while bouncing message: " + me.getMessage());
- } catch (Exception e) {
- log("Encountered unexpected exception while bouncing message: " + e.getMessage());
- }
- }
-
- /**
- * Returns the javamail Session object.
- *
- * @param props
- * @return the java mail session
- */
- protected Session obtainSession(Properties props) {
- return Session.getInstance(props);
- }
-
- /**
- * Returns an Iterator over org.apache.mailet.HostAddress, a specialized
- * subclass of javax.mail.URLName, which provides location information for
- * servers that are specified as mail handlers for the given hostname. If no
- * host is found, the Iterator returned will be empty and the first call to
- * hasNext() will return false. The Iterator is a nested iterator: the outer
- * iteration is over each gateway, and the inner iteration is over
- * potentially multiple A records for each gateway.
- *
- * @param gatewayServers - Collection of host[:port] Strings
- * @return an Iterator over HostAddress instances, sorted by priority
- * @since v2.2.0a16-unstable
- */
- private Iterator<HostAddress> getGatewaySMTPHostAddresses(Collection<String> gatewayServers) {
- Iterator<String> gateways = gatewayServers.iterator();
-
- return new MXHostAddressIterator(gateways, dnsServer, false, logger);
- }
-
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[07/50] [abbrv] james-project git commit: JAMES-1877 Extract
RemoteDelivery configuration to an other class
Posted by ro...@apache.org.
JAMES-1877 Extract RemoteDelivery configuration to an other class
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/6fa52984
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/6fa52984
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/6fa52984
Branch: refs/heads/master
Commit: 6fa52984020803b4d4c7de43d42e6dad3bfad6a6
Parents: 61c6309
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Nov 30 11:09:09 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:04:27 2017 +0700
----------------------------------------------------------------------
mailet/base/pom.xml | 5 +
.../org/apache/mailet/base/GenericMailet.java | 2 +-
.../java/org/apache/mailet/base/MailetUtil.java | 12 +-
.../org/apache/mailet/base/MailetUtilTest.java | 9 +-
.../james/transport/mailets/RemoteDelivery.java | 281 +-----
.../RemoteDeliveryConfiguration.java | 288 ++++++
.../mailets/remoteDelivery/Repeat.java | 2 +-
.../RemoteDeliveryConfigurationTest.java | 911 +++++++++++++++++++
.../mailets/remoteDelivery/RepeatTest.java | 6 +-
9 files changed, 1267 insertions(+), 249 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/6fa52984/mailet/base/pom.xml
----------------------------------------------------------------------
diff --git a/mailet/base/pom.xml b/mailet/base/pom.xml
index d40cc5d..0c47808 100644
--- a/mailet/base/pom.xml
+++ b/mailet/base/pom.xml
@@ -76,6 +76,11 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-guava</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
http://git-wip-us.apache.org/repos/asf/james-project/blob/6fa52984/mailet/base/src/main/java/org/apache/mailet/base/GenericMailet.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/main/java/org/apache/mailet/base/GenericMailet.java b/mailet/base/src/main/java/org/apache/mailet/base/GenericMailet.java
index c56a226..741f3f7 100644
--- a/mailet/base/src/main/java/org/apache/mailet/base/GenericMailet.java
+++ b/mailet/base/src/main/java/org/apache/mailet/base/GenericMailet.java
@@ -79,7 +79,7 @@ public abstract class GenericMailet implements Mailet, MailetConfig {
if (config == null) {
throw new NullPointerException("Mailet configuration must be set before getInitParameter is called.");
}
- return MailetUtil.getInitParameter(config, name, defaultValue);
+ return MailetUtil.getInitParameter(config, name).or(defaultValue);
}
/**
http://git-wip-us.apache.org/repos/asf/james-project/blob/6fa52984/mailet/base/src/main/java/org/apache/mailet/base/MailetUtil.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/main/java/org/apache/mailet/base/MailetUtil.java b/mailet/base/src/main/java/org/apache/mailet/base/MailetUtil.java
index 0155d5c..642f760 100644
--- a/mailet/base/src/main/java/org/apache/mailet/base/MailetUtil.java
+++ b/mailet/base/src/main/java/org/apache/mailet/base/MailetUtil.java
@@ -23,6 +23,8 @@ package org.apache.mailet.base;
import org.apache.mailet.MailetConfig;
+import com.google.common.base.Optional;
+
/**
* Collects utility methods.
@@ -91,20 +93,18 @@ public class MailetUtil {
* <p>Gets a boolean valued init parameter.</p>
* @param config not null
* @param name name of the init parameter to be queried
- * @param defaultValue this value will be substituted when the named value
- * cannot be parse or when the init parameter is absent
* @return true when the init parameter is <code>true</code> (ignoring case);
* false when the init parameter is <code>false</code> (ignoring case);
* otherwise the default value
*/
- public static boolean getInitParameter(MailetConfig config, String name, boolean defaultValue) {
+ public static Optional<Boolean> getInitParameter(MailetConfig config, String name) {
String value = config.getInitParameter(name);
if ("true".equalsIgnoreCase(value)) {
- return true;
+ return Optional.of(true);
}
if ("false".equalsIgnoreCase(value)){
- return false;
+ return Optional.of(false);
}
- return defaultValue;
+ return Optional.absent();
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/6fa52984/mailet/base/src/test/java/org/apache/mailet/base/MailetUtilTest.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/MailetUtilTest.java b/mailet/base/src/test/java/org/apache/mailet/base/MailetUtilTest.java
index db1f131..cb56b99 100644
--- a/mailet/base/src/test/java/org/apache/mailet/base/MailetUtilTest.java
+++ b/mailet/base/src/test/java/org/apache/mailet/base/MailetUtilTest.java
@@ -20,6 +20,7 @@
package org.apache.mailet.base;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.guava.api.Assertions.assertThat;
import org.apache.mailet.base.test.FakeMailetConfig;
import org.junit.Test;
@@ -27,6 +28,7 @@ import org.junit.Test;
public class MailetUtilTest {
private static final String A_PARAMETER = "aParameter";
+ public static final String DEFAULT_VALUE = "default";
@Test
public void getInitParameterShouldReturnTrueWhenIsValueTrueLowerCase() {
@@ -77,17 +79,16 @@ public class MailetUtilTest {
}
@Test
- public void getInitParameterShouldReturnDefaultValueWhenNull() {
+ public void getInitParameterShouldReturnAbsentWhenNull() {
FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
.build();
- assertThat(MailetUtil.getInitParameter(mailetConfig, A_PARAMETER, false)).isFalse();
- assertThat(MailetUtil.getInitParameter(mailetConfig, A_PARAMETER, true)).isTrue();
+ assertThat(MailetUtil.getInitParameter(mailetConfig, A_PARAMETER)).isAbsent();
}
private boolean getParameterValued(String value, boolean defaultValue) {
FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
.setProperty(A_PARAMETER, value)
.build();
- return MailetUtil.getInitParameter(mailetConfig, A_PARAMETER, defaultValue);
+ return MailetUtil.getInitParameter(mailetConfig, A_PARAMETER).or(defaultValue);
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/6fa52984/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index 88f8ea7..0067607 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -33,11 +33,9 @@ import java.util.Collection;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
-import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
-import java.util.StringTokenizer;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
@@ -65,8 +63,7 @@ import org.apache.james.queue.api.MailQueue.MailQueueException;
import org.apache.james.queue.api.MailQueue.MailQueueItem;
import org.apache.james.queue.api.MailQueueFactory;
import org.apache.james.transport.mailets.remoteDelivery.Delay;
-import org.apache.james.transport.mailets.remoteDelivery.DelaysAndMaxRetry;
-import org.apache.james.transport.mailets.remoteDelivery.HeloNameProvider;
+import org.apache.james.transport.mailets.remoteDelivery.RemoteDeliveryConfiguration;
import org.apache.james.transport.mailets.remoteDelivery.RemoteDeliverySocketFactory;
import org.apache.mailet.HostAddress;
import org.apache.mailet.Mail;
@@ -156,101 +153,23 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
private final DomainList domainList;
private final MailQueueFactory queueFactory;
private final Metric outgoingMailsMetric;
- private final Properties defprops; // Default properties for the JavaMail Session
private final Collection<Thread> workersThreads;
- /**
- * Flag to define verbose logging messages.
- */
- private boolean isDebug = false;
-
- /**
- * List of Delay Times. Controls frequency of retry attempts.
- */
- private List<Long> delayTimes;
-
- /**
- * Maximum no. of retries (Defaults to 5).
- */
- private int maxRetries;
-
- /**
- * Default number of ms to timeout on smtp delivery
- */
- private long smtpTimeout = 180000;
-
- /**
- * If false then ANY address errors will cause the transmission to fail
- */
- private boolean sendPartial = false;
-
- /**
- * The amount of time JavaMail will wait before giving up on a socket
- * connect()
- */
- private int connectionTimeout = 60000;
-
- /**
- * No. of threads used to process messages that should be retried.
- */
- private int workersThreadCount = 1;
-
- /**
- * The server(s) to send all email to
- */
- private Collection<String> gatewayServer = null;
-
- /**
- * Auth for gateway server
- */
- private String authUser = null;
-
- /**
- * Password for gateway server
- */
- private String authPass = null;
-
- /**
- * True, if the bind configuration parameter is supplied,
- * RemoteDeliverySocketFactory will be used in this case.
- */
- private boolean isBindUsed = false;
+ private MailQueue queue;
+ private Logger logger;
+ private RemoteDeliveryConfiguration configuration;
/**
* Flag used by 'run' method to end itself.
*/
private volatile boolean destroyed = false;
- /**
- * the processor for creating Bounces
- */
- private String bounceProcessor = null;
-
-
- /**
- * The retry count dnsProblemErrors
- */
- private int dnsProblemRetry = 0;
-
- private MailQueue queue;
-
- private Logger logger;
-
- private boolean usePriority;
-
- private boolean startTLS = false;
-
- private boolean isSSLEnable = false;
-
- private HeloNameProvider heloNameProvider;
-
@Inject
public RemoteDelivery(DNSService dnsServer, DomainList domainList, MailQueueFactory queueFactory, MetricFactory metricFactory) {
this.dnsServer = dnsServer;
this.domainList = domainList;
this.queueFactory = queueFactory;
this.outgoingMailsMetric = metricFactory.generate(OUTGOING_MAILS);
- this.defprops = new Properties();
this.workersThreads = new Vector<Thread>();
}
@@ -261,124 +180,20 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
* @throws MessagingException on failure to initialize attributes.
*/
public void init() throws MessagingException {
- // Set isDebug flag.
- isDebug = (getInitParameter("debug") == null) ? false : Boolean.valueOf(getInitParameter("debug"));
-
logger = getMailetContext().getLogger();
-
- try {
- int intendedMaxRetries = Integer.parseInt(getInitParameter("maxRetries", "5"));
- DelaysAndMaxRetry delaysAndMaxRetry = DelaysAndMaxRetry.from(intendedMaxRetries, getInitParameter("delayTime"));
- maxRetries = delaysAndMaxRetry.getMaxRetries();
- delayTimes = delaysAndMaxRetry.getExpendedDelays();
- } catch (Exception e) {
- log("Invalid maxRetries setting: " + getInitParameter("maxRetries"));
- }
- // Get the path for the 'Outgoing' repository. This is the place on the
- // file system where Mail objects will be saved during the 'delivery'
- // processing. This can be changed to a repository on a database (e.g.
- // db://maildb/spool/retry).
- String outgoing = getInitParameter("outgoing");
- if (outgoing == null) {
- outgoing = "outgoing";
- }
- queue = queueFactory.getQueue(outgoing);
-
- try {
- if (getInitParameter("timeout") != null) {
- smtpTimeout = Integer.parseInt(getInitParameter("timeout"));
- }
- } catch (Exception e) {
- log("Invalid timeout setting: " + getInitParameter("timeout"));
- }
-
- try {
- if (getInitParameter("connectiontimeout") != null) {
- connectionTimeout = Integer.parseInt(getInitParameter("connectiontimeout"));
- }
- } catch (Exception e) {
- log("Invalid timeout setting: " + getInitParameter("timeout"));
- }
-
- sendPartial = (getInitParameter("sendpartial") == null) ? false : Boolean.valueOf(getInitParameter("sendpartial"));
-
- bounceProcessor = getInitParameter("bounceProcessor");
-
- String sTLS = getInitParameter("startTLS");
- if (sTLS != null) {
- startTLS = Boolean.valueOf(sTLS);
- }
-
- isSSLEnable = (getInitParameter("sslEnable") == null) ? false : Boolean.valueOf(getInitParameter("sslEnable"));
-
- String gateway = getInitParameter("gateway");
- String gatewayPort = getInitParameter("gatewayPort");
-
- if (gateway != null) {
- gatewayServer = new ArrayList<String>();
- StringTokenizer st = new StringTokenizer(gateway, ",");
- while (st.hasMoreTokens()) {
- String server = st.nextToken().trim();
- if (server.indexOf(':') < 0 && gatewayPort != null) {
- server += ":";
- server += gatewayPort;
- }
-
- if (isDebug)
- log("Adding SMTP gateway: " + server);
- gatewayServer.add(server);
- }
- authUser = getInitParameter("gatewayUsername");
- // backward compatibility with 2.3.x
- if (authUser == null) {
- authUser = getInitParameter("gatewayusername");
- }
- authPass = getInitParameter("gatewayPassword");
- }
-
- /*
- JavaMail delivery socket binds to this local address. If null the
- JavaMail default will be used.
- */
- String bindAddress = getInitParameter("bind");
- isBindUsed = bindAddress != null;
+ configuration = new RemoteDeliveryConfiguration(getMailetConfig(), domainList);
+ queue = queueFactory.getQueue(configuration.getOutGoingQueueName());
+ initDeliveryThreads();
try {
- if (isBindUsed)
- RemoteDeliverySocketFactory.setBindAdress(bindAddress);
+ if (configuration.isBindUsed())
+ RemoteDeliverySocketFactory.setBindAdress(configuration.getBindAddress());
} catch (UnknownHostException e) {
- log("Invalid bind setting (" + bindAddress + "): " + e.toString());
+ log("Invalid bind setting (" + configuration.getBindAddress() + "): " + e.toString());
}
-
-
- // deal with <mail.*> attributes, passing them to javamail
- Iterator<String> i = getInitParameterNames();
- while (i.hasNext()) {
- String name = i.next();
- if (name.startsWith("mail.")) {
- defprops.put(name, getInitParameter(name));
- }
-
- }
-
- String dnsRetry = getInitParameter("maxDnsProblemRetries");
- if (dnsRetry != null && !dnsRetry.equals("")) {
- dnsProblemRetry = Integer.parseInt(dnsRetry);
- }
-
- heloNameProvider = new HeloNameProvider(getInitParameter("heloName"), domainList);
-
- String prio = getInitParameter("usePriority");
- if (prio != null) {
- usePriority = Boolean.valueOf(prio);
- }
-
- // Start Workers Threads.
- workersThreadCount = Integer.parseInt(getInitParameter("deliveryThreads"));
- initDeliveryThreads();
}
private void initDeliveryThreads() {
- for (int a = 0; a < workersThreadCount; a++) {
+ for (int a = 0; a < configuration.getWorkersThreadCount(); a++) {
String threadName = "Remote delivery thread (" + a + ")";
Thread t = new Thread(this, threadName);
t.start();
@@ -393,10 +208,10 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
* @return the next delay time to use, given the retry count
*/
private long getNextDelay(int retry_count) {
- if (retry_count > delayTimes.size()) {
+ if (retry_count > configuration.getDelayTimes().size()) {
return Delay.DEFAULT_DELAY_TIME;
}
- return delayTimes.get(retry_count - 1);
+ return configuration.getDelayTimes().get(retry_count - 1);
}
@Override
@@ -416,17 +231,17 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
@Override
public void service(Mail mail) throws MessagingException {
// Do I want to give the internal key, or the message's Message ID
- if (isDebug) {
+ if (configuration.isDebug()) {
log("Remotely delivering mail " + mail.getName());
}
Collection<MailAddress> recipients = mail.getRecipients();
- if (usePriority) {
+ if (configuration.isUsePriority()) {
// Use highest prio for new emails. See JAMES-1311
mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.HIGH_PRIORITY);
}
- if (gatewayServer == null) {
+ if (configuration.getGatewayServer() == null) {
// Must first organize the recipients into distinct servers (name
// made case insensitive)
Hashtable<String, Collection<MailAddress>> targets = new Hashtable<String, Collection<MailAddress>>();
@@ -449,7 +264,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
// outgoing mail repository
String name = mail.getName();
for (Map.Entry<String, Collection<MailAddress>> entry : targets.entrySet()) {
- if (isDebug) {
+ if (configuration.isDebug()) {
String logMessageBuffer = "Sending mail to " + entry.getValue() + " on host " + entry.getKey();
log(logMessageBuffer);
}
@@ -464,8 +279,8 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
}
} else {
// Store the mail unaltered for processing by the gateway server(s)
- if (isDebug) {
- String logMessageBuffer = "Sending mail to " + mail.getRecipients() + " via " + gatewayServer;
+ if (configuration.isDebug()) {
+ String logMessageBuffer = "Sending mail to " + mail.getRecipients() + " via " + configuration.getGatewayServer();
log(logMessageBuffer);
}
@@ -521,20 +336,20 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
// messages created by an inputstream.
props.setProperty("mail.smtp.allow8bitmime", "true");
// Sets timeout on going connections
- props.put("mail.smtp.timeout", smtpTimeout + "");
+ props.put("mail.smtp.timeout", configuration.getSmtpTimeout() + "");
- props.put("mail.smtp.connectiontimeout", connectionTimeout + "");
- props.put("mail.smtp.sendpartial", String.valueOf(sendPartial));
+ props.put("mail.smtp.connectiontimeout", configuration.getConnectionTimeout() + "");
+ props.put("mail.smtp.sendpartial", String.valueOf(configuration.isSendPartial()));
- props.put("mail.smtp.localhost", heloNameProvider.getHeloName());
+ props.put("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName());
// handle starttls
- props.put("mail.smtp.starttls.enable", String.valueOf(startTLS));
+ props.put("mail.smtp.starttls.enable", String.valueOf(configuration.isStartTLS()));
// handle SSLEnable
- props.put("mail.smtp.ssl.enable", String.valueOf(isSSLEnable));
+ props.put("mail.smtp.ssl.enable", String.valueOf(configuration.isSSLEnable()));
- if (isBindUsed) {
+ if (configuration.isBindUsed()) {
// undocumented JavaMail 1.2 feature, smtp transport will use
// our socket factory, which will also set the local address
props.put("mail.smtp.socketFactory.class", RemoteDeliverySocketFactory.class.getClass());
@@ -543,11 +358,11 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
props.put("mail.smtp.socketFactory.fallback", "false");
}
- if (authUser != null) {
+ if (configuration.getAuthUser() != null) {
props.put("mail.smtp.auth", "true");
}
- props.putAll(defprops);
+ props.putAll(configuration.getJavaxAdditionalProperties());
final Session session = obtainSession(props);
try {
@@ -567,7 +382,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
String key = mail.getName();
try {
- if (isDebug) {
+ if (configuration.isDebug()) {
String message = Thread.currentThread().getName() + " will process mail " + key;
log(message);
}
@@ -593,7 +408,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
long delay = getNextDelay(retries);
- if (usePriority) {
+ if (configuration.isUsePriority()) {
// Use lowest priority for retries. See JAMES-1311
mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY);
}
@@ -657,7 +472,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
*/
private boolean deliver(Mail mail, Session session) {
try {
- if (isDebug) {
+ if (configuration.isDebug()) {
log("Attempting to deliver " + mail.getName());
}
MimeMessage message = mail.getMessage();
@@ -679,7 +494,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
// Figure out which servers to try to send to. This collection
// will hold all the possible target servers
Iterator<HostAddress> targetServers;
- if (gatewayServer == null) {
+ if (configuration.getGatewayServer() == null) {
MailAddress rcpt = recipients.iterator().next();
String host = rcpt.getDomain();
@@ -703,7 +518,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
} catch (NumberFormatException e) {
// Unable to parse retryCount
}
- if (retry == 0 || retry > dnsProblemRetry) {
+ if (retry == 0 || retry > configuration.getDnsProblemRetry()) {
// The domain has no dns entry.. Return a permanent
// error
return failMessage(mail, new MessagingException(exceptionBuffer), true);
@@ -712,7 +527,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
}
}
} else {
- targetServers = getGatewaySMTPHostAddresses(gatewayServer);
+ targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer());
}
MessagingException lastError = null;
@@ -745,10 +560,10 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
SMTPTransport transport = null;
try {
transport = (SMTPTransport) session.getTransport(outgoingMailServer);
- transport.setLocalHost( props.getProperty("mail.smtp.localhost", heloNameProvider.getHeloName()) );
+ transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
try {
- if (authUser != null) {
- transport.connect(outgoingMailServer.getHostName(), authUser, authPass);
+ if (configuration.getAuthUser() != null) {
+ transport.connect(outgoingMailServer.getHostName(), configuration.getAuthUser(), configuration.getAuthPass());
} else {
transport.connect();
}
@@ -762,7 +577,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
// failing the message at the end of the loop.
// Also include the stacktrace if debug is enabled. See JAMES-1257
- if (isDebug) {
+ if (configuration.isDebug()) {
log(me.getMessage(), me.getCause());
} else {
log(me.getMessage());
@@ -868,7 +683,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
}
if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) {
- if (isDebug)
+ if (configuration.isDebug())
log("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers");
lastError = sfe;
} else {
@@ -967,7 +782,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
}
// log the original set of intended recipients
- if (isDebug)
+ if (configuration.isDebug())
log("Recipients: " + recipients);
if (sfe.getInvalidAddresses() != null) {
@@ -987,7 +802,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
// Set the recipients for the mail
mail.setRecipients(recipients);
- if (isDebug)
+ if (configuration.isDebug())
log("Invalid recipients: " + recipients);
deleteMessage = failMessage(mail, sfe, true);
}
@@ -1009,7 +824,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
}
// Set the recipients for the mail
mail.setRecipients(recipients);
- if (isDebug)
+ if (configuration.isDebug())
log("Unsent recipients: " + recipients);
if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
@@ -1141,7 +956,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
* JavaMail 1.3.2.
*/
private void logSendFailedException(SendFailedException sfe) {
- if (isDebug) {
+ if (configuration.isDebug()) {
MessagingException me = sfe;
if (me.getClass().getName().endsWith(".SMTPSendFailedException")) {
try {
@@ -1247,7 +1062,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
logBuffer.append(": ");
out.print(logBuffer.toString());
- if (isDebug)
+ if (configuration.isDebug())
ex.printStackTrace(out);
log(sout.toString());
if (!permanent) {
@@ -1264,7 +1079,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
// Something strange was happen with the errorMessage..
}
- if (retries < maxRetries) {
+ if (retries < configuration.getMaxRetries()) {
logBuffer = new StringBuilder(128).append("Storing message ").append(mail.getName()).append(" into outgoing after ").append(retries).append(" retries");
log(logBuffer.toString());
++retries;
@@ -1282,7 +1097,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
return true;
}
- if (bounceProcessor != null) {
+ if (configuration.getBounceProcessor() != null) {
// do the new DSN bounce
// setting attributes for DSN mailet
String cause;
@@ -1292,7 +1107,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
cause = ex.getMessage();
}
mail.setAttribute("delivery-error", cause);
- mail.setState(bounceProcessor);
+ mail.setState(configuration.getBounceProcessor());
// re-insert the mail into the spool for getting it passed to the
// dsn-processor
MailetContext mc = getMailetContext();
@@ -1330,7 +1145,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
PrintWriter out = new PrintWriter(sout, true);
String machine;
try {
- machine = heloNameProvider.getHeloName();
+ machine = configuration.getHeloNameProvider().getHeloName();
} catch (Exception e) {
machine = "[address unknown]";
http://git-wip-us.apache.org/repos/asf/james-project/blob/6fa52984/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java
new file mode 100644
index 0000000..621f3fe
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java
@@ -0,0 +1,288 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.mailet.MailetConfig;
+import org.apache.mailet.base.MailetUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+
+public class RemoteDeliveryConfiguration {
+
+ private final static Logger LOGGER = LoggerFactory.getLogger(RemoteDeliveryConfiguration.class);
+
+ public static final String DELIVERY_THREADS = "deliveryThreads";
+ public static final String USE_PRIORITY = "usePriority";
+ public static final String MAX_DNS_PROBLEM_RETRIES = "maxDnsProblemRetries";
+ public static final String HELO_NAME = "heloName";
+ public static final String JAVAX_PREFIX = "mail.";
+ public static final String BIND = "bind";
+ public static final String GATEWAY_PASSWORD = "gatewayPassword";
+ public static final String GATEWAY_USERNAME_COMPATIBILITY = "gatewayusername";
+ public static final String GATEWAY_USERNAME = "gatewayUsername";
+ public static final String GATEWAY_PORT = "gatewayPort";
+ public static final String GATEWAY = "gateway";
+ public static final String SSL_ENABLE = "sslEnable";
+ public static final String START_TLS = "startTLS";
+ public static final String BOUNCE_PROCESSOR = "bounceProcessor";
+ public static final String SENDPARTIAL = "sendpartial";
+ public static final String TIMEOUT = "timeout";
+ public static final String CONNECTIONTIMEOUT = "connectiontimeout";
+ public static final String OUTGOING = "outgoing";
+ public static final String MAX_RETRIES = "maxRetries";
+ public static final String DELAY_TIME = "delayTime";
+ public static final String DEBUG = "debug";
+ public static final int DEFAULT_SMTP_TIMEOUT = 180000;
+ public static final String DEFAULT_OUTGOING_QUEUE_NAME = "outgoing";
+ public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
+ public static final int DEFAULT_DNS_RETRY_PROBLEM = 0;
+ public static final int DEFAULT_MAX_RETRY = 5;
+ public static final String ADDRESS_PORT_SEPARATOR = ":";
+
+ private final boolean isDebug;
+ private final boolean usePriority;
+ private final boolean startTLS;
+ private final boolean isSSLEnable;
+ private final boolean isBindUsed;
+ private final boolean sendPartial;
+ private final int maxRetries;
+ private final long smtpTimeout;
+ private final int dnsProblemRetry;
+ private final int connectionTimeout;
+ private final int workersThreadCount;
+ private final List<Long> delayTimes;
+ private final HeloNameProvider heloNameProvider;
+ private final String outGoingQueueName;
+ private final String bindAddress;
+ private final String bounceProcessor;
+ private final Collection<String> gatewayServer;
+ private final String authUser;
+ private final String authPass;
+ private final Properties javaxAdditionalProperties;
+
+ public RemoteDeliveryConfiguration(MailetConfig mailetConfig, DomainList domainList) {
+ isDebug = MailetUtil.getInitParameter(mailetConfig, DEBUG).or(false);
+ startTLS = MailetUtil.getInitParameter(mailetConfig, START_TLS).or(false);
+ isSSLEnable = MailetUtil.getInitParameter(mailetConfig, SSL_ENABLE).or(false);
+ usePriority = MailetUtil.getInitParameter(mailetConfig, USE_PRIORITY).or(false);
+ sendPartial = MailetUtil.getInitParameter(mailetConfig, SENDPARTIAL).or(false);
+ outGoingQueueName = Optional.fromNullable(mailetConfig.getInitParameter(OUTGOING)).or(DEFAULT_OUTGOING_QUEUE_NAME);
+ bounceProcessor = mailetConfig.getInitParameter(BOUNCE_PROCESSOR);
+ bindAddress = mailetConfig.getInitParameter(BIND);
+
+ DelaysAndMaxRetry delaysAndMaxRetry = computeDelaysAndMaxRetry(mailetConfig);
+ maxRetries = delaysAndMaxRetry.getMaxRetries();
+ delayTimes = delaysAndMaxRetry.getExpendedDelays();
+ smtpTimeout = computeSmtpTimeout(mailetConfig);
+ connectionTimeout = computeConnectionTimeout(mailetConfig);
+ dnsProblemRetry = computeDnsProblemRetry(mailetConfig);
+ heloNameProvider = new HeloNameProvider(mailetConfig.getInitParameter(HELO_NAME), domainList);
+ workersThreadCount = Integer.valueOf(mailetConfig.getInitParameter(DELIVERY_THREADS));
+
+ String gatewayPort = mailetConfig.getInitParameter(GATEWAY_PORT);
+ String gateway = mailetConfig.getInitParameter(GATEWAY);
+ gatewayServer = computeGatewayServers(gatewayPort, gateway);
+ if (gateway != null) {
+ authUser = computeGatewayUser(mailetConfig);
+ authPass = mailetConfig.getInitParameter(GATEWAY_PASSWORD);
+ } else {
+ authUser = null;
+ authPass = null;
+ }
+ isBindUsed = bindAddress != null;
+ javaxAdditionalProperties = computeJavaxProperties(mailetConfig);
+ }
+
+ private Properties computeJavaxProperties(MailetConfig mailetConfig) {
+ Properties result = new Properties();
+ // deal with <mail.*> attributes, passing them to javamail
+ for (String propertyName : ImmutableList.copyOf(mailetConfig.getInitParameterNames())) {
+ if (propertyName.startsWith(JAVAX_PREFIX)) {
+ result.put(propertyName, mailetConfig.getInitParameter(propertyName));
+ }
+ }
+ return result;
+ }
+
+ private int computeDnsProblemRetry(MailetConfig mailetConfig) {
+ String dnsRetry = mailetConfig.getInitParameter(MAX_DNS_PROBLEM_RETRIES);
+ if (!Strings.isNullOrEmpty(dnsRetry)) {
+ return Integer.valueOf(dnsRetry);
+ } else {
+ return DEFAULT_DNS_RETRY_PROBLEM;
+ }
+ }
+
+ private int computeConnectionTimeout(MailetConfig mailetConfig) {
+ try {
+ return Integer.valueOf(
+ Optional.fromNullable(mailetConfig.getInitParameter(CONNECTIONTIMEOUT))
+ .or(String.valueOf(DEFAULT_CONNECTION_TIMEOUT)));
+ } catch (Exception e) {
+ LOGGER.warn("Invalid timeout setting: " + mailetConfig.getInitParameter(TIMEOUT));
+ return DEFAULT_CONNECTION_TIMEOUT;
+ }
+ }
+
+ private long computeSmtpTimeout(MailetConfig mailetConfig) {
+ try {
+ if (mailetConfig.getInitParameter(TIMEOUT) != null) {
+ return Integer.valueOf(mailetConfig.getInitParameter(TIMEOUT));
+ } else {
+ return DEFAULT_SMTP_TIMEOUT;
+ }
+ } catch (Exception e) {
+ LOGGER.warn("Invalid timeout setting: " + mailetConfig.getInitParameter(TIMEOUT));
+ return DEFAULT_SMTP_TIMEOUT;
+ }
+ }
+
+ private DelaysAndMaxRetry computeDelaysAndMaxRetry(MailetConfig mailetConfig) {
+ try {
+ int intendedMaxRetries = Integer.valueOf(
+ Optional.fromNullable(mailetConfig.getInitParameter(MAX_RETRIES))
+ .or(String.valueOf(DEFAULT_MAX_RETRY)));
+ return DelaysAndMaxRetry.from(intendedMaxRetries, mailetConfig.getInitParameter(DELAY_TIME));
+ } catch (Exception e) {
+ LOGGER.warn("Invalid maxRetries setting: " + mailetConfig.getInitParameter(MAX_RETRIES));
+ return DelaysAndMaxRetry.defaults();
+ }
+ }
+
+ private String computeGatewayUser(MailetConfig mailetConfig) {
+ // backward compatibility with 2.3.x
+ String user = mailetConfig.getInitParameter(GATEWAY_USERNAME);
+ if (user == null) {
+ return mailetConfig.getInitParameter(GATEWAY_USERNAME_COMPATIBILITY);
+ }
+ return user;
+ }
+
+ private List<String> computeGatewayServers(String gatewayPort, String gateway) {
+ if (gateway != null) {
+ ImmutableList.Builder<String> builder = ImmutableList.builder();
+ Iterable<String> gatewayParts = Splitter.on(',').split(gateway);
+ for(String gatewayPart : gatewayParts) {
+ builder.add(parsePart(gatewayPort, gatewayPart));
+ }
+ return builder.build();
+ } else {
+ return ImmutableList.of();
+ }
+ }
+
+ private String parsePart(String gatewayPort, String gatewayPart) {
+ String address = gatewayPart.trim();
+ if (address.contains(ADDRESS_PORT_SEPARATOR) && gatewayPort != null) {
+ return address + ADDRESS_PORT_SEPARATOR + gatewayPort;
+ }
+ return address;
+ }
+
+ public boolean isDebug() {
+ return isDebug;
+ }
+
+ public List<Long> getDelayTimes() {
+ return delayTimes;
+ }
+
+ public int getMaxRetries() {
+ return maxRetries;
+ }
+
+ public long getSmtpTimeout() {
+ return smtpTimeout;
+ }
+
+ public boolean isSendPartial() {
+ return sendPartial;
+ }
+
+ public int getConnectionTimeout() {
+ return connectionTimeout;
+ }
+
+ public int getWorkersThreadCount() {
+ return workersThreadCount;
+ }
+
+ public Collection<String> getGatewayServer() {
+ return gatewayServer;
+ }
+
+ public String getAuthUser() {
+ return authUser;
+ }
+
+ public String getAuthPass() {
+ return authPass;
+ }
+
+ public boolean isBindUsed() {
+ return isBindUsed;
+ }
+
+ public String getBounceProcessor() {
+ return bounceProcessor;
+ }
+
+ public boolean isUsePriority() {
+ return usePriority;
+ }
+
+ public boolean isStartTLS() {
+ return startTLS;
+ }
+
+ public boolean isSSLEnable() {
+ return isSSLEnable;
+ }
+
+ public HeloNameProvider getHeloNameProvider() {
+ return heloNameProvider;
+ }
+
+ public String getOutGoingQueueName() {
+ return outGoingQueueName;
+ }
+
+ public Properties getJavaxAdditionalProperties() {
+ return javaxAdditionalProperties;
+ }
+
+ public int getDnsProblemRetry() {
+ return dnsProblemRetry;
+ }
+
+ public String getBindAddress() {
+ return bindAddress;
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/6fa52984/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Repeat.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Repeat.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Repeat.java
index 0252214..19682b1 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Repeat.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Repeat.java
@@ -28,7 +28,7 @@ import com.google.common.collect.Iterables;
public class Repeat {
public static <T> List<T> repeat(T element, int times) {
- Preconditions.checkArgument(times > 0, "Times argument should be strictly positive");
+ Preconditions.checkArgument(times >= 0, "Times argument should be strictly positive");
return ImmutableList.copyOf(
Iterables.limit(
Iterables.cycle(element), times));
http://git-wip-us.apache.org/repos/asf/james-project/blob/6fa52984/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfigurationTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfigurationTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfigurationTest.java
new file mode 100644
index 0000000..ec4e23f
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfigurationTest.java
@@ -0,0 +1,911 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Properties;
+
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.mailet.base.test.FakeMailetConfig;
+import org.assertj.core.data.MapEntry;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class RemoteDeliveryConfigurationTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void isDebugShouldBeFalseByDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isDebug()).isFalse();
+ }
+
+ @Test
+ public void isDebugShouldBeTrueIfSpecified() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.DEBUG, "true")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isDebug()).isTrue();
+ }
+
+ @Test
+ public void isDebugShouldBeFalseIfSpecified() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.DEBUG, "false")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isDebug()).isFalse();
+ }
+
+ @Test
+ public void isDebugShouldBeFalseIfParsingException() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.DEBUG, "invalid")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isDebug()).isFalse();
+ }
+
+ @Test
+ public void getSmtpTimeoutShouldReturnDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getSmtpTimeout())
+ .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_SMTP_TIMEOUT);
+ }
+
+ @Test
+ public void getSmtpTimeoutShouldReturnProvidedValue() {
+ int value = 150000;
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.TIMEOUT, String.valueOf(value))
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getSmtpTimeout())
+ .isEqualTo(value);
+ }
+
+ @Test
+ public void getSmtpTimeoutShouldReturnDefaultIfParsingException() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.TIMEOUT, "invalid")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getSmtpTimeout())
+ .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_SMTP_TIMEOUT);
+ }
+
+ @Test
+ public void getSmtpTimeoutShouldReturnProvidedValueWhenZero() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.TIMEOUT, "0")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getSmtpTimeout())
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void getSmtpTimeoutShouldReturnProvidedValueWhenNegativeNumber() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.TIMEOUT, "-1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getSmtpTimeout())
+ .isEqualTo(-1);
+ }
+
+ @Test
+ public void getOutGoingQueueNameShouldReturnDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getOutGoingQueueName())
+ .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_OUTGOING_QUEUE_NAME);
+ }
+
+ @Test
+ public void getOutGoingQueueNameShouldReturnProvidedValue() {
+ String value = "value";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.OUTGOING, value)
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getOutGoingQueueName())
+ .isEqualTo(value);
+ }
+
+ @Test
+ public void getConnectionTimeoutShouldReturnDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getConnectionTimeout())
+ .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_CONNECTION_TIMEOUT);
+ }
+
+ @Test
+ public void getConnectionTimeoutShouldReturnProvidedValue() {
+ int value = 150000;
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.CONNECTIONTIMEOUT, String.valueOf(value))
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getConnectionTimeout())
+ .isEqualTo(value);
+ }
+
+ @Test
+ public void getConnectionTimeoutShouldReturnDefaultIfParsingException() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.CONNECTIONTIMEOUT, "invalid")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getConnectionTimeout())
+ .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_CONNECTION_TIMEOUT);
+ }
+
+ @Test
+ public void getConnectionTimeoutShouldReturnProvidedValueWhenZero() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.CONNECTIONTIMEOUT, "0")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getConnectionTimeout())
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void getConnectionTimeoutShouldReturnProvidedValueWhenNegativeNumber() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.CONNECTIONTIMEOUT, "-1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getConnectionTimeout())
+ .isEqualTo(-1);
+ }
+
+ @Test
+ public void isSendPartialShouldBeFalseByDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSendPartial()).isFalse();
+ }
+
+ @Test
+ public void isSendPartialShouldBeTrueIfSpecified() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.SENDPARTIAL, "true")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSendPartial()).isTrue();
+ }
+
+ @Test
+ public void isSendPartialShouldBeFalseIfSpecified() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.SENDPARTIAL, "false")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSendPartial()).isFalse();
+ }
+
+ @Test
+ public void isSendPartialShouldBeFalseIfParsingException() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.SENDPARTIAL, "invalid")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSendPartial()).isFalse();
+ }
+
+ @Test
+ public void getBounceProcessorShouldReturnNullByDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getBounceProcessor())
+ .isNull();
+ }
+
+ @Test
+ public void getBounceProcessorShouldReturnProvidedValue() {
+ String value = "value";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, value)
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getBounceProcessor())
+ .isEqualTo(value);
+ }
+
+ @Test
+ public void isStartTLSShouldBeFalseByDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isStartTLS()).isFalse();
+ }
+
+ @Test
+ public void isStartTLSShouldBeTrueIfSpecified() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.START_TLS, "true")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isStartTLS()).isTrue();
+ }
+
+ @Test
+ public void isStartTLSShouldBeFalseIfSpecified() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.START_TLS, "false")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isStartTLS()).isFalse();
+ }
+
+ @Test
+ public void isStartTLSShouldBeFalseIfParsingException() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.START_TLS, "invalid")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isStartTLS()).isFalse();
+ }
+
+ @Test
+ public void isSSLEnableShouldBeFalseByDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSSLEnable()).isFalse();
+ }
+
+ @Test
+ public void isSSLEnableShouldBeTrueIfSpecified() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.SSL_ENABLE, "true")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSSLEnable()).isTrue();
+ }
+
+ @Test
+ public void isSSLEnableShouldBeFalseIfSpecified() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.SSL_ENABLE, "false")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSSLEnable()).isFalse();
+ }
+
+ @Test
+ public void isSSLEnableShouldBeFalseIfParsingException() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.SSL_ENABLE, "invalid")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isSSLEnable()).isFalse();
+ }
+
+ @Test
+ public void isBindUsedShouldBeFalseByDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.BIND, "127.0.0.1:25")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isBindUsed()).isTrue();
+ }
+
+ @Test
+ public void getBindAddressShouldBeNullByDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getBindAddress()).isNull();
+ }
+
+ @Test
+ public void getBindAddressShouldReturnProvidedValue() {
+ String value = "127.0.0.1:25";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.BIND, value)
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getBindAddress()).isEqualTo(value);
+ }
+
+ @Test
+ public void getDnsProblemRetryShouldReturnDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDnsProblemRetry())
+ .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_DNS_RETRY_PROBLEM);
+ }
+
+ @Test
+ public void getDnsProblemRetryShouldReturnProvidedValue() {
+ int value = 4;
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, String.valueOf(value))
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDnsProblemRetry())
+ .isEqualTo(value);
+ }
+
+ @Test
+ public void constructorShouldThrowOnInvalidDnsRetries() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "invalid")
+ .build();
+
+ expectedException.expect(NumberFormatException.class);
+
+ new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class));
+ }
+
+ @Test
+ public void getDnsProblemRetryShouldReturnProvidedValueWhenZero() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "0")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDnsProblemRetry())
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void getDnsProblemRetryShouldReturnProvidedValueWhenEmpty() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDnsProblemRetry())
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void getDnsProblemRetryShouldReturnProvidedValueWhenNegativeNumber() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "-1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDnsProblemRetry())
+ .isEqualTo(-1);
+ }
+
+ @Test
+ public void constructorShouldThrowOnNonSpecifiedThreadCount() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .build();
+
+ expectedException.expect(NumberFormatException.class);
+
+ new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getWorkersThreadCount();
+ }
+
+ @Test
+ public void getWorkersThreadCountShouldReturnProvidedValue() {
+ int value = 36;
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, String.valueOf(value))
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getWorkersThreadCount())
+ .isEqualTo(value);
+ }
+
+ @Test
+ public void constructorShouldThrowOnInvalidThreadCount() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "invalid")
+ .build();
+
+ expectedException.expect(NumberFormatException.class);
+
+ new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getWorkersThreadCount();
+ }
+
+ @Test
+ public void isUsePriorityShouldBeFalseByDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isUsePriority()).isFalse();
+ }
+
+ @Test
+ public void isUsePriorityShouldBeTrueIfSpecified() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.USE_PRIORITY, "true")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isUsePriority()).isTrue();
+ }
+
+ @Test
+ public void isUsePriorityShouldBeFalseIfSpecified() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.USE_PRIORITY, "false")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isUsePriority()).isFalse();
+ }
+
+ @Test
+ public void isUsePriorityShouldBeFalseIfParsingException() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.USE_PRIORITY, "invalid")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).isUsePriority()).isFalse();
+ }
+
+ @Test
+ public void getHeloNameProviderShouldCallDomainListByDefault() throws Exception {
+ DomainList domainList = mock(DomainList.class);
+ String value = "value";
+ when(domainList.getDefaultDomain()).thenReturn(value);
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, domainList).getHeloNameProvider().getHeloName())
+ .isEqualTo(value);
+ }
+
+ @Test
+ public void getHeloNameProviderShouldTakeCareOfProvidedValue() {
+ String value = "value";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, value)
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getHeloNameProvider().getHeloName())
+ .isEqualTo(value);
+ }
+
+ @Test
+ public void getJavaxAdditionalPropertiesShouldBeEmptyByDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getJavaxAdditionalProperties())
+ .isEmpty();
+ }
+
+ @Test
+ public void getJavaxAdditionalPropertiesShouldTakeOneEntryIntoAccount() {
+ String key1 = RemoteDeliveryConfiguration.JAVAX_PREFIX + "property1";
+ String value1 = "value1";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(key1, value1)
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getJavaxAdditionalProperties())
+ .containsOnly(MapEntry.entry(key1, value1));
+ }
+
+ @Test
+ public void getJavaxAdditionalPropertiesShouldTakeTwoEntriesIntoAccount() {
+ String key1 = RemoteDeliveryConfiguration.JAVAX_PREFIX + "property1";
+ String value1 = "value1";
+ String key2 = RemoteDeliveryConfiguration.JAVAX_PREFIX + "property2";
+ String value2 = "value2";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(key1, value1)
+ .setProperty(key2, value2)
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getJavaxAdditionalProperties())
+ .containsOnly(MapEntry.entry(key1, value1), MapEntry.entry(key2, value2));
+ }
+
+ @Test
+ public void constructorShouldThrowOnNullValueJavaxProperty() {
+ expectedException.expect(NullPointerException.class);
+
+ String key1 = RemoteDeliveryConfiguration.JAVAX_PREFIX + "property1";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(key1, null)
+ .build();
+
+ new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class));
+ }
+
+ @Test
+ public void getJavaxAdditionalPropertiesShouldTakeOneEmptyEntryIntoAccount() {
+ String key1 = RemoteDeliveryConfiguration.JAVAX_PREFIX + "property1";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(key1, "")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getJavaxAdditionalProperties())
+ .containsOnly(MapEntry.entry(key1, ""));
+ }
+
+ @Test
+ public void getGatewayServerShouldBeNullByDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getGatewayServer()).isEmpty();
+ }
+
+ @Test
+ public void getGatewayServerShouldReturnProvidedValue() {
+ String value = "127.0.0.1";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY, value)
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getGatewayServer())
+ .containsOnly(value);
+ }
+
+ @Test
+ public void getGatewayServerShouldReturnProvidedValues() {
+ String value1 = "127.0.0.1";
+ String value2 = "domain";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY, value1 + ',' + value2)
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getGatewayServer())
+ .containsOnly(value1, value2);
+ }
+
+ @Test
+ public void getAuthUserShouldBeNullByDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isNull();
+ }
+
+ @Test
+ public void getAuthUserShouldBeNullWhenGatewayIsNotSpecified() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME, "name")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isNull();
+ }
+
+ @Test
+ public void getAuthUserShouldReturnSpecifiedValueWhenGatewaySpecified() {
+ String value = "name";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME, value)
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isEqualTo(value);
+ }
+
+ @Test
+ public void getAuthUserShouldReturnSpecifiedEmptyValueWhenGatewaySpecified() {
+ String value = "";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME, value)
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isEqualTo(value);
+ }
+
+ @Test
+ public void getAuthUserShouldReturnSpecifiedCompatibilityValueWhenGatewaySpecified() {
+ String value = "name";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME_COMPATIBILITY, value)
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isEqualTo(value);
+ }
+
+ @Test
+ public void getAuthUserShouldReturnSpecifiedEmptyCompatibilityValueWhenGatewaySpecified() {
+ String value = "";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME_COMPATIBILITY, value)
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isEqualTo(value);
+ }
+
+ @Test
+ public void getAuthUserShouldReturnSpecifiedValueWhenValueAndCompatibilitySpecified() {
+ String value = "name";
+ String compatibilityValue = "compatibilityValue";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME, value)
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME_COMPATIBILITY, compatibilityValue)
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthUser()).isEqualTo(value);
+ }
+
+ @Test
+ public void getAuthPassShouldBeNullByDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthPass()).isNull();
+ }
+
+ @Test
+ public void getAuthPassShouldBeNullWhenGatewayIsNotSpecified() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY_PASSWORD, "name")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthPass()).isNull();
+ }
+
+ @Test
+ public void getAuthPassShouldReturnSpecifiedValueWhenGatewaySpecified() {
+ String value = "name";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY_PASSWORD, value)
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthPass()).isEqualTo(value);
+ }
+
+ @Test
+ public void getAuthPassShouldReturnSpecifiedEmptyValueWhenGatewaySpecified() {
+ String value = "";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY_PASSWORD, value)
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY, "127.0.0.1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getAuthPass()).isEqualTo(value);
+ }
+
+ @Test
+ public void getMaxRetriesShouldReturnProvidedValue() {
+ int value = 36;
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.MAX_RETRIES, String.valueOf(value))
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getMaxRetries()).isEqualTo(value);
+ }
+
+ @Test
+ public void getMaxRetriesShouldReturnOneWhenZero() {
+ int value = 0;
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.MAX_RETRIES, String.valueOf(value))
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getMaxRetries()).isEqualTo(1);
+ }
+
+ @Test
+ public void getMaxRetriesShouldReturnOneWhenNegativeNumber() {
+ int value = -1;
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.MAX_RETRIES, String.valueOf(value))
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getMaxRetries()).isEqualTo(1);
+ }
+
+ @Test
+ public void getMaxRetriesShouldReturnDefaultWhenNoySpecified() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getMaxRetries())
+ .isEqualTo(RemoteDeliveryConfiguration.DEFAULT_MAX_RETRY);
+ }
+
+ @Test
+ public void getDelayTimesShouldReturnDefault() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDelayTimes())
+ .containsOnly(Delay.DEFAULT_DELAY_TIME, Delay.DEFAULT_DELAY_TIME, Delay.DEFAULT_DELAY_TIME, Delay.DEFAULT_DELAY_TIME, Delay.DEFAULT_DELAY_TIME);
+ }
+
+ @Test
+ public void getDelayTimesShouldWorkWithDefaultConfiguration() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.DELAY_TIME, "5000, 100000, 500000")
+ .build();
+
+ assertThat(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).getDelayTimes())
+ .containsOnly(5000L, 100000L, 500000L);
+ }
+
+ @Test
+ public void createFinalJavaxPropertiesShouldProvidePropertiesWithMinimalConfiguration() {
+ String helo = "domain.com";
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, helo)
+ .build();
+
+ Properties properties = new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).createFinalJavaxProperties();
+
+
+ assertThat(properties)
+ .containsOnly(MapEntry.entry("mail.smtp.ssl.enable", "false"),
+ MapEntry.entry("mail.smtp.sendpartial", "false"),
+ MapEntry.entry("mail.smtp.allow8bitmime", "true"),
+ MapEntry.entry("mail.smtp.ehlo", "true"),
+ MapEntry.entry("mail.smtp.connectiontimeout", "60000"),
+ MapEntry.entry("mail.smtp.localhost", helo),
+ MapEntry.entry("mail.smtp.timeout", "180000"),
+ MapEntry.entry("mail.debug", "false"),
+ MapEntry.entry("mail.smtp.starttls.enable", "false"));
+ }
+
+ @Test
+ public void createFinalJavaxPropertiesShouldProvidePropertiesWithFullConfigurationWithoutGateway() {
+ String helo = "domain.com";
+ int connectionTimeout = 1856;
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.SSL_ENABLE, "true")
+ .setProperty(RemoteDeliveryConfiguration.SENDPARTIAL, "true")
+ .setProperty(RemoteDeliveryConfiguration.CONNECTIONTIMEOUT, String.valueOf(connectionTimeout))
+ .setProperty(RemoteDeliveryConfiguration.START_TLS, "true")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, helo)
+ .build();
+
+ Properties properties = new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).createFinalJavaxProperties();
+
+
+ assertThat(properties)
+ .containsOnly(MapEntry.entry("mail.smtp.ssl.enable", "true"),
+ MapEntry.entry("mail.smtp.sendpartial", "true"),
+ MapEntry.entry("mail.smtp.allow8bitmime", "true"),
+ MapEntry.entry("mail.smtp.ehlo", "true"),
+ MapEntry.entry("mail.smtp.connectiontimeout", String.valueOf(connectionTimeout)),
+ MapEntry.entry("mail.smtp.localhost", helo),
+ MapEntry.entry("mail.smtp.timeout", "180000"),
+ MapEntry.entry("mail.debug", "false"),
+ MapEntry.entry("mail.smtp.starttls.enable", "true"));
+ }
+
+ @Test
+ public void createFinalJavaxPropertiesShouldProvidePropertiesWithFullConfigurationWithGateway() {
+ String helo = "domain.com";
+ int connectionTimeout = 1856;
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.SSL_ENABLE, "true")
+ .setProperty(RemoteDeliveryConfiguration.SENDPARTIAL, "true")
+ .setProperty(RemoteDeliveryConfiguration.CONNECTIONTIMEOUT, String.valueOf(connectionTimeout))
+ .setProperty(RemoteDeliveryConfiguration.START_TLS, "true")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, helo)
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY, "gateway.domain.com")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY_USERNAME, "user")
+ .setProperty(RemoteDeliveryConfiguration.GATEWAY_PASSWORD, "password")
+ .build();
+
+ Properties properties = new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)).createFinalJavaxProperties();
+
+
+ assertThat(properties)
+ .containsOnly(MapEntry.entry("mail.smtp.ssl.enable", "true"),
+ MapEntry.entry("mail.smtp.sendpartial", "true"),
+ MapEntry.entry("mail.smtp.allow8bitmime", "true"),
+ MapEntry.entry("mail.smtp.ehlo", "true"),
+ MapEntry.entry("mail.smtp.connectiontimeout", String.valueOf(connectionTimeout)),
+ MapEntry.entry("mail.smtp.localhost", helo),
+ MapEntry.entry("mail.smtp.timeout", "180000"),
+ MapEntry.entry("mail.debug", "false"),
+ MapEntry.entry("mail.smtp.starttls.enable", "true"),
+ MapEntry.entry("mail.smtp.auth", "true"));
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/6fa52984/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RepeatTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RepeatTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RepeatTest.java
index 13b9968..4ea1640 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RepeatTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RepeatTest.java
@@ -39,10 +39,8 @@ public class RepeatTest {
}
@Test
- public void repeatShouldThrowOnZeroTimes() {
- expectedException.expect(IllegalArgumentException.class);
-
- Repeat.repeat(new Object(), 0);
+ public void repeatShouldReturnEmptyListOnZeroTimes() {
+ assertThat(Repeat.repeat(new Object(), 0)).isEmpty();
}
@Test
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[35/50] [abbrv] james-project git commit: JAMES-1877 Extract
mailAddress conversion
Posted by ro...@apache.org.
JAMES-1877 Extract mailAddress conversion
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/7f8cf9e9
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/7f8cf9e9
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/7f8cf9e9
Branch: refs/heads/master
Commit: 7f8cf9e9f5c4f227759da77b82520df3e510fb9f
Parents: fc1b1d3
Author: Benoit Tellier <bt...@linagora.com>
Authored: Fri Dec 2 10:47:24 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:52 2017 +0700
----------------------------------------------------------------------
.../InternetAddressConverter.java | 44 ++++++++++++++
.../mailets/remoteDelivery/MailDelivrer.java | 12 +---
.../InternetAddressConverterTest.java | 62 ++++++++++++++++++++
3 files changed, 107 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/7f8cf9e9/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/InternetAddressConverter.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/InternetAddressConverter.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/InternetAddressConverter.java
new file mode 100644
index 0000000..52bd2a6
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/InternetAddressConverter.java
@@ -0,0 +1,44 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.util.Collection;
+
+import javax.mail.internet.InternetAddress;
+
+import org.apache.mailet.MailAddress;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.FluentIterable;
+
+public class InternetAddressConverter {
+
+ public static InternetAddress[] convert(Collection<MailAddress> recipients) {
+ Preconditions.checkNotNull(recipients);
+ return FluentIterable.from(recipients).transform(new Function<MailAddress, InternetAddress>() {
+ @Override
+ public InternetAddress apply(MailAddress input) {
+ return input.toInternetAddress();
+ }
+ }).toArray(InternetAddress.class);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/7f8cf9e9/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
index bcfe330..941ef21 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
@@ -127,7 +127,7 @@ public class MailDelivrer {
targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer());
}
- return doDeliver(mail, mail.getMessage(), convertToInetAddr(mail.getRecipients()), targetServers);
+ return doDeliver(mail, mail.getMessage(), InternetAddressConverter.convert(mail.getRecipients()), targetServers);
}
@SuppressWarnings("deprecation")
@@ -312,16 +312,6 @@ public class MailDelivrer {
}
}
- private InternetAddress[] convertToInetAddr(Collection<MailAddress> recipients) {
- InternetAddress addr[] = new InternetAddress[recipients.size()];
- int j = 0;
- for (Iterator<MailAddress> i = recipients.iterator(); i.hasNext(); j++) {
- MailAddress rcpt = i.next();
- addr[j] = rcpt.toInternetAddress();
- }
- return addr;
- }
-
private ExecutionResult handleTemporaryResolutionException(Mail mail, String host) {
ExecutionResult executionResult = ExecutionResult.temporaryFailure(new MessagingException("Temporary problem looking " +
"up mail server for host: " + host + ". I cannot determine where to send this message."));
http://git-wip-us.apache.org/repos/asf/james-project/blob/7f8cf9e9/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/InternetAddressConverterTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/InternetAddressConverterTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/InternetAddressConverterTest.java
new file mode 100644
index 0000000..9020533
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/InternetAddressConverterTest.java
@@ -0,0 +1,62 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import javax.mail.internet.InternetAddress;
+
+import org.apache.mailet.MailAddress;
+import org.apache.mailet.base.MailAddressFixture;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import com.google.common.collect.ImmutableList;
+
+public class InternetAddressConverterTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void convertShouldWorkWithEmptyAddressList() {
+ assertThat(InternetAddressConverter.convert(ImmutableList.<MailAddress>of())).isEmpty();
+ }
+
+ @Test
+ public void convertShouldThrowOnNullAddress() {
+ expectedException.expect(NullPointerException.class);
+
+ InternetAddressConverter.convert(null);
+ }
+
+ @Test
+ public void convertShouldWorkWithOneAddress() throws Exception {
+ assertThat(InternetAddressConverter.convert(ImmutableList.of(MailAddressFixture.ANY_AT_JAMES)))
+ .containsOnly(new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString()));
+ }
+
+ @Test
+ public void convertShouldWorkWithTwoAddress() throws Exception {
+ assertThat(InternetAddressConverter.convert(ImmutableList.of(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES)))
+ .containsOnly(new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString()), new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString()));
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[10/50] [abbrv] james-project git commit: JAMES-1877 Creating javax
properties is a responsibility of RemoteDeliveryConfiguration
Posted by ro...@apache.org.
JAMES-1877 Creating javax properties is a responsibility of RemoteDeliveryConfiguration
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/69f66c7a
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/69f66c7a
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/69f66c7a
Branch: refs/heads/master
Commit: 69f66c7a6282c9b904ac5c1a0dc120b4e73a04f4
Parents: 6fa5298
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Nov 30 17:28:42 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:04:32 2017 +0700
----------------------------------------------------------------------
.../james/transport/mailets/RemoteDelivery.java | 48 +-------------------
.../RemoteDeliveryConfiguration.java | 29 ++++++++++++
2 files changed, 30 insertions(+), 47 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/69f66c7a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index 0067607..c4c18d2 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -318,53 +318,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
*/
@Override
public void run() {
-
- // Checks the pool and delivers a mail message
- Properties props = new Properties();
- // Not needed for production environment
- props.put("mail.debug", "false");
- // Reactivated: javamail 1.3.2 should no more have problems with
- // "250 OK"
- // messages (WAS "false": Prevents problems encountered with 250 OK
- // Messages)
- props.put("mail.smtp.ehlo", "true");
- // By setting this property to true the transport is allowed to
- // send 8 bit data to the server (if it supports the 8bitmime
- // extension).
- // 2006/03/01 reverted to false because of a javamail bug converting to
- // 8bit
- // messages created by an inputstream.
- props.setProperty("mail.smtp.allow8bitmime", "true");
- // Sets timeout on going connections
- props.put("mail.smtp.timeout", configuration.getSmtpTimeout() + "");
-
- props.put("mail.smtp.connectiontimeout", configuration.getConnectionTimeout() + "");
- props.put("mail.smtp.sendpartial", String.valueOf(configuration.isSendPartial()));
-
- props.put("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName());
-
- // handle starttls
- props.put("mail.smtp.starttls.enable", String.valueOf(configuration.isStartTLS()));
-
- // handle SSLEnable
- props.put("mail.smtp.ssl.enable", String.valueOf(configuration.isSSLEnable()));
-
- if (configuration.isBindUsed()) {
- // undocumented JavaMail 1.2 feature, smtp transport will use
- // our socket factory, which will also set the local address
- props.put("mail.smtp.socketFactory.class", RemoteDeliverySocketFactory.class.getClass());
- // Don't fallback to the standard socket factory on error, do throw
- // an exception
- props.put("mail.smtp.socketFactory.fallback", "false");
- }
-
- if (configuration.getAuthUser() != null) {
- props.put("mail.smtp.auth", "true");
- }
-
- props.putAll(configuration.getJavaxAdditionalProperties());
-
- final Session session = obtainSession(props);
+ final Session session = obtainSession(configuration.createFinalJavaxProperties());
try {
while (!Thread.interrupted() && !destroyed) {
try {
http://git-wip-us.apache.org/repos/asf/james-project/blob/69f66c7a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java
index 621f3fe..3bfde9e 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java
@@ -206,6 +206,35 @@ public class RemoteDeliveryConfiguration {
return address;
}
+ public Properties createFinalJavaxProperties() {
+ Properties props = new Properties();
+ props.put("mail.debug", "false");
+ // Reactivated: javamail 1.3.2 should no more have problems with "250 OK" messages
+ // (WAS "false": Prevents problems encountered with 250 OK Messages)
+ props.put("mail.smtp.ehlo", "true");
+ // By setting this property to true the transport is allowed to send 8 bit data to the server (if it supports
+ // the 8bitmime extension).
+ props.setProperty("mail.smtp.allow8bitmime", "true");
+ props.put("mail.smtp.timeout", String.valueOf(smtpTimeout));
+ props.put("mail.smtp.connectiontimeout", String.valueOf(connectionTimeout));
+ props.put("mail.smtp.sendpartial", String.valueOf(sendPartial));
+ props.put("mail.smtp.localhost", heloNameProvider.getHeloName());
+ props.put("mail.smtp.starttls.enable", String.valueOf(startTLS));
+ props.put("mail.smtp.ssl.enable", String.valueOf(isSSLEnable));
+ if (isBindUsed()) {
+ // undocumented JavaMail 1.2 feature, smtp transport will use
+ // our socket factory, which will also set the local address
+ props.put("mail.smtp.socketFactory.class", RemoteDeliverySocketFactory.class.getClass());
+ // Don't fallback to the standard socket factory on error, do throw an exception
+ props.put("mail.smtp.socketFactory.fallback", "false");
+ }
+ if (authUser != null) {
+ props.put("mail.smtp.auth", "true");
+ }
+ props.putAll(javaxAdditionalProperties);
+ return props;
+ }
+
public boolean isDebug() {
return isDebug;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[45/50] [abbrv] james-project git commit: JAMES-1877 Tests MX
iteration behavior upon deliver
Posted by ro...@apache.org.
JAMES-1877 Tests MX iteration behavior upon deliver
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/c06d312a
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/c06d312a
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/c06d312a
Branch: refs/heads/master
Commit: c06d312a4facc24e281934706f7439ae20ef29aa
Parents: 97e23ae
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Dec 7 11:43:35 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 18:14:27 2017 +0700
----------------------------------------------------------------------
.../mailets/remoteDelivery/MailDelivrer.java | 91 +++------
.../remoteDelivery/MailDelivrerToHost.java | 74 ++++---
.../remoteDelivery/MailDelivrerTest.java | 201 +++++++++++++++++--
3 files changed, 245 insertions(+), 121 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/c06d312a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
index f42a0fc..1036734 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
@@ -37,6 +37,8 @@ import org.apache.mailet.MailAddress;
import org.slf4j.Logger;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
public class MailDelivrer {
@@ -62,15 +64,13 @@ public class MailDelivrer {
}
/**
- * We can assume that the recipients of this message are all going to the
- * same mail server. We will now rely on the DNS server to do DNS MX record
- * lookup and try to deliver to the multiple mail servers. If it fails, it
- * should throw an exception.
+ * We can assume that the recipients of this message are all going to the same mail server. We will now rely on the
+ * DNS server to do DNS MX record lookup and try to deliver to the multiple mail servers. If it fails, it should
+ * throw an exception.
*
* @param mail org.apache.james.core.MailImpl
* @param session javax.mail.Session
- * @return boolean Whether the delivery was successful and the message can
- * be deleted
+ * @return boolean Whether the delivery was successful and the message can be deleted
*/
public ExecutionResult deliver(Mail mail) {
try {
@@ -78,25 +78,13 @@ public class MailDelivrer {
} catch (SendFailedException sfe) {
return handleSenderFailedException(mail, sfe);
} catch (MessagingException ex) {
- // We should do a better job checking this... if the failure is a general
- // connect exception, this is less descriptive than more specific SMTP command
- // failure... have to lookup and see what are the various Exception possibilities
-
- // Unable to deliver message after numerous tries... fail accordingly
-
// We check whether this is a 5xx error message, which indicates a permanent failure (like account doesn't exist
// or mailbox is full or domain is setup wrong). We fail permanently if this was a 5xx error
-
- boolean isPermanent = '5' == ex.getMessage().charAt(0);
- ExecutionResult executionResult = ExecutionResult.onFailure(isPermanent, ex);
- logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
- return executionResult;
+ boolean isPermanent = new EnhancedMessagingException(ex).isServerError();
+ return logAndReturn(mail, ExecutionResult.onFailure(isPermanent, ex));
} catch (Exception ex) {
- logger.error("Generic exception = permanent failure: " + ex.getMessage(), ex);
- // Generic exception = permanent failure
- ExecutionResult executionResult = ExecutionResult.permanentFailure(ex);
- logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
- return executionResult;
+ logger.error("Generic exception = permanent failure: {}", ex.getMessage(), ex);
+ return logAndReturn(mail, ExecutionResult.permanentFailure(ex));
}
}
@@ -107,7 +95,7 @@ public class MailDelivrer {
return ExecutionResult.permanentFailure(new Exception("No recipients specified for " + mail.getName() + " sent by " + mail.getSender()));
}
if (configuration.isDebug()) {
- logger.debug("Attempting to deliver " + mail.getName());
+ logger.debug("Attempting to deliver {}", mail.getName());
}
String host = retrieveTargetHostname(mail);
@@ -126,7 +114,8 @@ public class MailDelivrer {
}
private String retrieveTargetHostname(Mail mail) {
- MailAddress rcpt = mail.getRecipients().iterator().next();
+ Preconditions.checkArgument(!mail.getRecipients().isEmpty(), "Mail should have recipients to attempt delivery");
+ MailAddress rcpt = Iterables.getFirst(mail.getRecipients(), null);
return rcpt.getDomain();
}
@@ -136,9 +125,7 @@ public class MailDelivrer {
while (targetServers.hasNext()) {
try {
- if (mailDelivrerToHost.tryDeliveryToHost(mail, addr, targetServers.next())) {
- return ExecutionResult.success();
- }
+ return mailDelivrerToHost.tryDeliveryToHost(mail, addr, targetServers.next());
} catch (SendFailedException sfe) {
lastError = handleSendFailExceptionOnMxIteration(mail, sfe);
} catch (MessagingException me) {
@@ -163,21 +150,16 @@ public class MailDelivrer {
}
private MessagingException handleMessagingException(Mail mail, MessagingException me) throws MessagingException {
- logger.debug("Exception delivering message (" + mail.getName() + ") - " + me.getMessage());
+ logger.debug("Exception delivering message ({}) - {}", mail.getName(), me.getMessage());
if ((me.getNextException() != null) && (me.getNextException() instanceof IOException)) {
- // This is more than likely a temporary failure
-
// If it's an IO exception with no nested exception, it's probably
// some socket or weird I/O related problem.
return me;
} else {
- // This was not a connection or I/O error particular to one
- // SMTP server of an MX set. Instead, it is almost certainly
- // a protocol level error. In this case we assume that this
- // is an error we'd encounter with any of the SMTP servers
- // associated with this MX record, and we pass the exception
- // to the code in the outer block that determines its
- // severity.
+ // This was not a connection or I/O error particular to one SMTP server of an MX set. Instead, it is almost
+ // certainly a protocol level error. In this case we assume that this is an error we'd encounter with any of
+ // the SMTP servers associated with this MX record, and we pass the exception to the code in the outer block
+ // that determines its severity.
throw me;
}
}
@@ -189,12 +171,12 @@ public class MailDelivrer {
List<MailAddress> invalidAddresses = SFEHelper.getAddressesAsMailAddress(sfe.getInvalidAddresses(), logger);
List<MailAddress> validUnsentAddresses = SFEHelper.getAddressesAsMailAddress(sfe.getValidUnsentAddresses(), logger);
if (configuration.isDebug()) {
- logger.debug("Mail " + mail.getName() + " has initially recipients: " + mail.getRecipients());
+ logger.debug("Mail {} has initially recipients: {}", mail.getName(), mail.getRecipients());
if (!invalidAddresses.isEmpty()) {
- logger.debug("Invalid recipients: " + invalidAddresses);
+ logger.debug("Invalid recipients: {}", invalidAddresses);
}
if (!validUnsentAddresses.isEmpty()) {
- logger.debug("Unsent recipients: " + validUnsentAddresses);
+ logger.debug("Unsent recipients: {}", validUnsentAddresses);
}
}
if (!validUnsentAddresses.isEmpty()) {
@@ -234,14 +216,10 @@ public class MailDelivrer {
if (sfe.getValidSentAddresses() != null) {
Address[] validSent = sfe.getValidSentAddresses();
if (validSent.length > 0) {
- logger.debug( "Mail (" + mail.getName() + ") sent successfully for " + Arrays.asList(validSent));
+ logger.debug( "Mail ({}) sent successfully for {}", mail.getName(), Arrays.asList(validSent));
}
}
- /*
- * SMTPSendFailedException introduced in JavaMail 1.3.2, and
- * provides detailed protocol reply code for the operation
- */
EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
if (enhancedMessagingException.isServerError()) {
throw sfe;
@@ -249,7 +227,7 @@ public class MailDelivrer {
if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) {
if (configuration.isDebug())
- logger.debug("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers");
+ logger.debug("Send failed, {} valid addresses remain, continuing with any other servers", sfe.getValidUnsentAddresses().length);
return sfe;
} else {
// There are no valid addresses left to send, so rethrow
@@ -258,10 +236,9 @@ public class MailDelivrer {
}
private ExecutionResult handleNoTargetServer(Mail mail, String host) {
- logger.info("No mail server found for: " + host);
+ logger.info("No mail server found for: {}", host);
MessagingException messagingException = new MessagingException("There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.");
int retry = DeliveryRetriesHelper.retrieveRetries(mail);
- System.out.println("retyry " + retry);
if (retry >= configuration.getDnsProblemRetry()) {
return logAndReturn(mail, ExecutionResult.permanentFailure(messagingException));
} else {
@@ -273,13 +250,10 @@ public class MailDelivrer {
if (configuration.isDebug()) {
EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
if (enhancedMessagingException.hasReturnCode()) {
- logger.debug("SMTP SEND FAILED:");
- logger.debug(sfe.toString());
- logger.debug(" Command: " + enhancedMessagingException.computeCommand());
- logger.debug(" RetCode: " + enhancedMessagingException.getReturnCode());
- logger.debug(" Response: " + sfe.getMessage());
+ logger.debug("SMTP SEND FAILED: Command [{}] RetCode: [{}] Response[{}]", enhancedMessagingException.computeCommand(),
+ enhancedMessagingException.getReturnCode(), sfe.getMessage());
} else {
- logger.debug("Send failed: " + sfe.toString());
+ logger.debug("Send failed: {}", sfe.toString());
}
logLevels(sfe);
}
@@ -291,12 +265,9 @@ public class MailDelivrer {
me = (MessagingException) ne;
EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(me);
if (me.getClass().getName().endsWith(".SMTPAddressFailedException") || me.getClass().getName().endsWith(".SMTPAddressSucceededException")) {
- logger.debug("ADDRESS " + enhancedMessagingException.computeAction() + ":");
- logger.debug(me.toString());
- logger.debug(" Address: " + enhancedMessagingException.computeAddress());
- logger.debug(" Command: " + enhancedMessagingException.computeCommand());
- logger.debug(" RetCode: " + enhancedMessagingException.getReturnCode());
- logger.debug(" Response: " + me.getMessage());
+ logger.debug("ADDRESS :[{}] Address:[{}] Command : [{}] RetCode[{}] Response [{}]",
+ enhancedMessagingException.computeAction(), me.toString(), enhancedMessagingException.computeAddress(),
+ enhancedMessagingException.computeCommand(), enhancedMessagingException.getReturnCode());
}
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/c06d312a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java
index a9f5758..a6ffbad 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java
@@ -50,24 +50,16 @@ public class MailDelivrerToHost {
this.logger = logger;
}
- public boolean tryDeliveryToHost(Mail mail, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException {
- Properties props = session.getProperties();
- if (mail.getSender() == null) {
- props.put("mail.smtp.from", "<>");
- } else {
- String sender = mail.getSender().toString();
- props.put("mail.smtp.from", sender);
- }
- logger.debug("Attempting delivery of " + mail.getName() + " to host " + outgoingMailServer.getHostName()
- + " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from"));
+ public ExecutionResult tryDeliveryToHost(Mail mail, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException {
+ Properties props = getPropertiesForMail(mail);
+ logger.debug("Attempting delivery of {} to host {} at {} from {}",
+ mail.getName(), outgoingMailServer.getHostName(), outgoingMailServer.getHost(), props.get("mail.smtp.from"));
// Many of these properties are only in later JavaMail versions
// "mail.smtp.ehlo" //default true
// "mail.smtp.auth" //default false
- // "mail.smtp.dsn.ret" //default to nothing... appended as
- // RET= after MAIL FROM line.
- // "mail.smtp.dsn.notify" //default to nothing...appended as
- // NOTIFY= after RCPT TO line.
+ // "mail.smtp.dsn.ret" //default to nothing... appended as RET= after MAIL FROM line.
+ // "mail.smtp.dsn.notify" //default to nothing... appended as NOTIFY= after RCPT TO line.
SMTPTransport transport = null;
try {
@@ -75,12 +67,23 @@ public class MailDelivrerToHost {
transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
connect(outgoingMailServer, transport);
transport.sendMessage(adaptToTransport(mail.getMessage(), transport), addr);
- logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() +
- " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients());
- return true;
+ logger.debug("Mail ({}) sent successfully to {} at {} from {} for {}", mail.getName(), outgoingMailServer.getHostName(),
+ outgoingMailServer.getHost(), props.get("mail.smtp.from"), mail.getRecipients());
} finally {
closeTransport(mail, outgoingMailServer, transport);
}
+ return ExecutionResult.success();
+ }
+
+ private Properties getPropertiesForMail(Mail mail) {
+ Properties props = session.getProperties();
+ if (mail.getSender() == null) {
+ props.put("mail.smtp.from", "<>");
+ } else {
+ String sender = mail.getSender().toString();
+ props.put("mail.smtp.from", sender);
+ }
+ return props;
}
private void connect(HostAddress outgoingMailServer, SMTPTransport transport) throws MessagingException {
@@ -92,27 +95,7 @@ public class MailDelivrerToHost {
}
private MimeMessage adaptToTransport(MimeMessage message, SMTPTransport transport) throws MessagingException {
- // if the transport is a SMTPTransport (from sun) some
- // performance enhancement can be done.
- if (transport.getClass().getName().endsWith(".SMTPTransport")) {
- // if the message is alredy 8bit or binary and the server doesn't support the 8bit extension it has
- // to be converted to 7bit. Javamail api doesn't perform
- // that conversion, but it is required to be a rfc-compliant smtp server.
-
- // Temporarily disabled. See JAMES-638
- if (!transport.supportsExtension(BIT_MIME_8)) {
- try {
- converter7Bit.convertTo7Bit(message);
- } catch (IOException e) {
- // An error has occured during the 7bit conversion.
- // The error is logged and the message is sent anyway.
-
- logger.error("Error during the conversion to 7 bit.", e);
- }
- }
- } else {
- // If the transport is not the one developed by Sun we are not sure of how it
- // handles the 8 bit mime stuff, so I convert the message to 7bit.
+ if (shouldAdapt(transport)) {
try {
converter7Bit.convertTo7Bit(message);
} catch (IOException e) {
@@ -122,6 +105,16 @@ public class MailDelivrerToHost {
return message;
}
+ private boolean shouldAdapt(SMTPTransport transport) {
+ // If the transport is a SMTPTransport (from sun) some performance enhancement can be done.
+ // If the transport is not the one developed by Sun we are not sure of how it handles the 8 bit mime stuff, so I
+ // convert the message to 7bit.
+ return !transport.getClass().getName().endsWith(".SMTPTransport")
+ || !transport.supportsExtension(BIT_MIME_8);
+ // if the message is already 8bit or binary and the server doesn't support the 8bit extension it has to be converted
+ // to 7bit. Javamail api doesn't perform that conversion, but it is required to be a rfc-compliant smtp server.
+ }
+
private void closeTransport(Mail mail, HostAddress outgoingMailServer, SMTPTransport transport) {
if (transport != null) {
try {
@@ -131,8 +124,9 @@ public class MailDelivrerToHost {
// of the mail transaction (MAIL, RCPT, DATA).
transport.close();
} catch (MessagingException e) {
- logger.error("Warning: could not close the SMTP transport after sending mail (" + mail.getName() + ") to " + outgoingMailServer.getHostName() + " at " + outgoingMailServer.getHost() + " for " + mail.getRecipients() + "; probably the server has already closed the "
- + "connection. Message is considered to be delivered. Exception: " + e.getMessage());
+ logger.error("Warning: could not close the SMTP transport after sending mail ({}) to {} at {} for {}; " +
+ "probably the server has already closed the connection. Message is considered to be delivered. Exception: {}",
+ mail.getName(), outgoingMailServer.getHostName(), outgoingMailServer.getHost(), mail.getRecipients(), e.getMessage());
}
transport = null;
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/c06d312a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
index 3f7b726..b77fcb4 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
@@ -20,12 +20,18 @@
package org.apache.james.transport.mailets.remoteDelivery;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import java.io.IOException;
+
import javax.mail.Address;
+import javax.mail.MessagingException;
import javax.mail.SendFailedException;
import javax.mail.internet.InternetAddress;
@@ -47,16 +53,32 @@ import com.sun.mail.smtp.SMTPSenderFailedException;
public class MailDelivrerTest {
private static final Logger LOGGER = LoggerFactory.getLogger(MailDelivrerTest.class);
+ public static final String MX1_HOSTNAME = "mx1." + MailAddressFixture.JAMES2_APACHE_ORG;
+ public static final String MX2_HOSTNAME = "mx2." + MailAddressFixture.JAMES2_APACHE_ORG;
+ public static final String SMTP_URI2 = "protocol://userid:password@host:119/file1";
+ public static final String SMTP_URI1 = "protocol://userid:password@host:119/file2";
+ @SuppressWarnings("deprecation")
+ public static final HostAddress HOST_ADDRESS_1 = new HostAddress(MX1_HOSTNAME, SMTP_URI1);
+ @SuppressWarnings("deprecation")
+ public static final HostAddress HOST_ADDRESS_2 = new HostAddress(MX2_HOSTNAME, SMTP_URI2);
private MailDelivrer testee;
private Bouncer bouncer;
private DnsHelper dnsHelper;
+ private MailDelivrerToHost mailDelivrerToHost;
@Before
public void setUp() {
bouncer = mock(Bouncer.class);
dnsHelper = mock(DnsHelper.class);
- testee = new MailDelivrer(mock(RemoteDeliveryConfiguration.class), mock(MailDelivrerToHost.class), dnsHelper, bouncer, LOGGER);
+ mailDelivrerToHost = mock(MailDelivrerToHost.class);
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "3")
+ .setProperty(RemoteDeliveryConfiguration.DEBUG, "true")
+ .build(),
+ mock(DomainList.class));
+ testee = new MailDelivrer(configuration, mailDelivrerToHost, dnsHelper, bouncer, LOGGER);
}
@Test
@@ -224,11 +246,6 @@ public class MailDelivrerTest {
@Test
public void deliverShouldReturnTemporaryErrorWhenFirstDNSProblem() throws Exception {
Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
- FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
- .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
- .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "3")
- .build();
- testee = new MailDelivrer(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)), mock(MailDelivrerToHost.class), dnsHelper, bouncer, LOGGER);
UnmodifiableIterator<HostAddress> empty = ImmutableList.<HostAddress>of().iterator();
when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(empty);
@@ -242,12 +259,7 @@ public class MailDelivrerTest {
@Test
public void deliverShouldReturnTemporaryErrorWhenToleratedDNSProblem() throws Exception {
Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
- FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
- .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
- .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "3")
- .build();
DeliveryRetriesHelper.incrementRetries(mail);
- testee = new MailDelivrer(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)), mock(MailDelivrerToHost.class), dnsHelper, bouncer, LOGGER);
UnmodifiableIterator<HostAddress> empty = ImmutableList.<HostAddress>of().iterator();
when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(empty);
@@ -261,14 +273,9 @@ public class MailDelivrerTest {
@Test
public void deliverShouldReturnPermanentErrorWhenLimitDNSProblemReached() throws Exception {
Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
- FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
- .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
- .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "3")
- .build();
DeliveryRetriesHelper.incrementRetries(mail);
DeliveryRetriesHelper.incrementRetries(mail);
DeliveryRetriesHelper.incrementRetries(mail);
- testee = new MailDelivrer(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)), mock(MailDelivrerToHost.class), dnsHelper, bouncer, LOGGER);
UnmodifiableIterator<HostAddress> empty = ImmutableList.<HostAddress>of().iterator();
when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(empty);
@@ -282,15 +289,11 @@ public class MailDelivrerTest {
@Test
public void deliverShouldReturnPermanentErrorWhenLimitDNSProblemExceeded() throws Exception {
Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
- FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
- .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
- .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "3")
- .build();
+
DeliveryRetriesHelper.incrementRetries(mail);
DeliveryRetriesHelper.incrementRetries(mail);
DeliveryRetriesHelper.incrementRetries(mail);
DeliveryRetriesHelper.incrementRetries(mail);
- testee = new MailDelivrer(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)), mock(MailDelivrerToHost.class), dnsHelper, bouncer, LOGGER);
UnmodifiableIterator<HostAddress> empty = ImmutableList.<HostAddress>of().iterator();
when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(empty);
@@ -300,4 +303,160 @@ public class MailDelivrerTest {
assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.PERMANENT_FAILURE);
}
+ @SuppressWarnings("deprecation")
+ @Test
+ public void deliverShouldWork() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+ HOST_ADDRESS_1,
+ HOST_ADDRESS_2).iterator();
+ when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+ when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class)))
+ .thenReturn(ExecutionResult.success());
+ ExecutionResult executionResult = testee.deliver(mail);
+
+ verify(mailDelivrerToHost, times(1)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+ assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.SUCCESS);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void deliverShouldAbortWhenServerError() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+ HOST_ADDRESS_1,
+ HOST_ADDRESS_2).iterator();
+ when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+ when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class)))
+ .thenThrow(new MessagingException("500 : Horrible way to manage Server Return code"));
+ ExecutionResult executionResult = testee.deliver(mail);
+
+ verify(mailDelivrerToHost, times(1)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+ assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.PERMANENT_FAILURE);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void deliverShouldAbortWithTemporaryWhenMessagingExceptionCauseUnknown() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+ HOST_ADDRESS_1,
+ HOST_ADDRESS_2).iterator();
+ when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+ when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class)))
+ .thenThrow(new MessagingException("400 : Horrible way to manage Server Return code"));
+ ExecutionResult executionResult = testee.deliver(mail);
+
+ verify(mailDelivrerToHost, times(1)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+ assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.TEMPORARY_FAILURE);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void deliverShouldTryTwiceOnIOException() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+ HOST_ADDRESS_1,
+ HOST_ADDRESS_2).iterator();
+ when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+ when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), eq(HOST_ADDRESS_1)))
+ .thenThrow(new MessagingException("400 : Horrible way to manage Server Return code", new IOException()));
+ when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), eq(HOST_ADDRESS_2)))
+ .thenReturn(ExecutionResult.success());
+ ExecutionResult executionResult = testee.deliver(mail);
+
+ verify(mailDelivrerToHost, times(2)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+ assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.SUCCESS);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void deliverShouldAbortWhenServerErrorSFE() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+ HOST_ADDRESS_1,
+ HOST_ADDRESS_2).iterator();
+ when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+ when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class)))
+ .thenThrow(new SMTPSenderFailedException(new InternetAddress(MailAddressFixture.ANY_AT_JAMES.toString()), "command", 505, "Big failure"));
+ ExecutionResult executionResult = testee.deliver(mail);
+
+ verify(mailDelivrerToHost, times(1)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+ assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.PERMANENT_FAILURE);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void deliverShouldAttemptDeliveryOnlyOnceIfNoMoreValidUnsent() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+ HOST_ADDRESS_1,
+ HOST_ADDRESS_2).iterator();
+ when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+ when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class)))
+ .thenThrow(new SendFailedException());
+ ExecutionResult executionResult = testee.deliver(mail);
+
+ verify(mailDelivrerToHost, times(1)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+ assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.TEMPORARY_FAILURE);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void deliverShouldAttemptDeliveryOnBothMXIfStillRecipients() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+ Address[] validSent = {};
+ Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+ Address[] invalid = {};
+ SendFailedException sfe = new SendFailedException("Message",
+ new Exception(),
+ validSent,
+ validUnsent,
+ invalid);
+
+ UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+ HOST_ADDRESS_1,
+ HOST_ADDRESS_2).iterator();
+ when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+ when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class)))
+ .thenThrow(sfe);
+ ExecutionResult executionResult = testee.deliver(mail);
+
+ verify(mailDelivrerToHost, times(2)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+ assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.TEMPORARY_FAILURE);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void deliverShouldWorkIfOnlyMX2Valid() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+ Address[] validSent = {};
+ Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+ Address[] invalid = {};
+ SendFailedException sfe = new SendFailedException("Message",
+ new Exception(),
+ validSent,
+ validUnsent,
+ invalid);
+
+ UnmodifiableIterator<HostAddress> dnsEntries = ImmutableList.of(
+ HOST_ADDRESS_1,
+ HOST_ADDRESS_2).iterator();
+ when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(dnsEntries);
+ when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), eq(HOST_ADDRESS_1)))
+ .thenThrow(sfe);
+ when(mailDelivrerToHost.tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), eq(HOST_ADDRESS_2)))
+ .thenReturn(ExecutionResult.success());
+ ExecutionResult executionResult = testee.deliver(mail);
+
+ verify(mailDelivrerToHost, times(2)).tryDeliveryToHost(any(Mail.class), any(InternetAddress[].class), any(HostAddress.class));
+ assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.SUCCESS);
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[15/50] [abbrv] james-project git commit: JAMES-1877 Make mail
lifeCycle readable in DeliveryRunnable
Posted by ro...@apache.org.
JAMES-1877 Make mail lifeCycle readable in DeliveryRunnable
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/cb0cb77c
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/cb0cb77c
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/cb0cb77c
Branch: refs/heads/master
Commit: cb0cb77cdcbd605b8e09d289a2b78f7eff1fcb28
Parents: 2e60b2d
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 16:12:39 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:49 2017 +0700
----------------------------------------------------------------------
.../mailets/remoteDelivery/DeliveryRunnable.java | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/cb0cb77c/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index 75fb3e2..b8be45d 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -101,10 +101,8 @@ public class DeliveryRunnable implements Runnable {
if (configuration.isDebug()) {
logger.debug(Thread.currentThread().getName() + " will process mail " + mail.getName());
}
-
attemptDelivery(session, mail);
-
- // Clear the object handle to make sure it recycles this object.
+ LifecycleUtil.dispose(mail);
mail = null;
queueItem.done(true);
} catch (Exception e) {
@@ -131,10 +129,7 @@ public class DeliveryRunnable implements Runnable {
}
private void attemptDelivery(Session session, Mail mail) throws MailQueue.MailQueueException {
- if (deliver(mail, session)) {
- // Message was successfully delivered/fully failed... delete it
- LifecycleUtil.dispose(mail);
- } else {
+ if (!deliver(mail, session)) {
// Something happened that will delay delivery. Store it back in the retry repository.
long delay = getNextDelay(DeliveryRetriesHelper.retrieveRetries(mail));
@@ -143,7 +138,6 @@ public class DeliveryRunnable implements Runnable {
mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY);
}
queue.enQueue(mail, delay, TimeUnit.MILLISECONDS);
- LifecycleUtil.dispose(mail);
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[12/50] [abbrv] james-project git commit: JAMES-1877 Extract a
message composer
Posted by ro...@apache.org.
JAMES-1877 Extract a message composer
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/80039f14
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/80039f14
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/80039f14
Branch: refs/heads/master
Commit: 80039f140dff5e26ae4bfc605faf27a6702433cd
Parents: 63bb307
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 14:11:45 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:48 2017 +0700
----------------------------------------------------------------------
.../mailets/remoteDelivery/MessageComposer.java | 212 +++++++++++++++++++
1 file changed, 212 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/80039f14/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
new file mode 100644
index 0000000..a57b496
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
@@ -0,0 +1,212 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.ConnectException;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
+import javax.mail.MessagingException;
+import javax.mail.SendFailedException;
+import javax.mail.internet.InternetAddress;
+
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+
+public class MessageComposer {
+
+ private final RemoteDeliveryConfiguration configuration;
+
+ public MessageComposer(RemoteDeliveryConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ public String composeForBounce(Mail mail, Exception ex) {
+ StringWriter sout = new StringWriter();
+ PrintWriter out = new PrintWriter(sout, true);
+ String machine;
+ try {
+ machine = configuration.getHeloNameProvider().getHeloName();
+
+ } catch (Exception e) {
+ machine = "[address unknown]";
+ }
+ String bounceBuffer = "Hi. This is the James mail server at " + machine + ".";
+ out.println(bounceBuffer);
+ out.println("I'm afraid I wasn't able to deliver your message to the following addresses.");
+ out.println("This is a permanent error; I've given up. Sorry it didn't work out. Below");
+ out.println("I include the list of recipients and the reason why I was unable to deliver");
+ out.println("your message.");
+ out.println();
+ for (MailAddress mailAddress : mail.getRecipients()) {
+ out.println(mailAddress);
+ }
+ if (ex instanceof MessagingException) {
+ if (((MessagingException) ex).getNextException() == null) {
+ out.println(ex.getMessage().trim());
+ } else {
+ Exception ex1 = ((MessagingException) ex).getNextException();
+ if (ex1 instanceof SendFailedException) {
+ out.println("Remote mail server told me: " + ex1.getMessage().trim());
+ } else if (ex1 instanceof UnknownHostException) {
+ out.println("Unknown host: " + ex1.getMessage().trim());
+ out.println("This could be a DNS server error, a typo, or a problem with the recipient's mail server.");
+ } else if (ex1 instanceof ConnectException) {
+ // Already formatted as "Connection timed out: connect"
+ out.println(ex1.getMessage().trim());
+ } else if (ex1 instanceof SocketException) {
+ out.println("Socket exception: " + ex1.getMessage().trim());
+ } else {
+ out.println(ex1.getMessage().trim());
+ }
+ }
+ }
+ out.println();
+ return sout.toString();
+ }
+
+ /**
+ * Try to return a usefull logString created of the Exception which was
+ * given. Return null if nothing usefull could be done
+ *
+ * @param e The MessagingException to use
+ * @return logString
+ */
+ public String fromException(Exception e) {
+ if (e.getClass().getName().endsWith(".SMTPSendFailedException")) {
+ return "RemoteHost said: " + e.getMessage();
+ } else if (e instanceof SendFailedException) {
+ SendFailedException exception = (SendFailedException) e;
+
+ // No error
+ if (exception.getInvalidAddresses().length == 0 && exception.getValidUnsentAddresses().length == 0)
+ return null;
+
+ Exception ex;
+ StringBuilder sb = new StringBuilder();
+ boolean smtpExFound = false;
+ sb.append("RemoteHost said:");
+
+ if (e instanceof MessagingException)
+ while ((ex = ((MessagingException) e).getNextException()) != null && ex instanceof MessagingException) {
+ e = ex;
+ if (ex.getClass().getName().endsWith(".SMTPAddressFailedException")) {
+ try {
+ InternetAddress ia = (InternetAddress) invokeGetter(ex, "getAddress");
+ sb.append(" ( ").append(ia).append(" - [").append(ex.getMessage().replaceAll("\\n", "")).append("] )");
+ smtpExFound = true;
+ } catch (IllegalStateException ise) {
+ // Error invoking the getAddress method
+ } catch (ClassCastException cce) {
+ // The getAddress method returned something
+ // different than InternetAddress
+ }
+ }
+ }
+ if (!smtpExFound) {
+ boolean invalidAddr = false;
+ sb.append(" ( ");
+
+ if (exception.getInvalidAddresses().length > 0) {
+ sb.append(Arrays.toString(exception.getInvalidAddresses()));
+ invalidAddr = true;
+ }
+ if (exception.getValidUnsentAddresses().length > 0) {
+ if (invalidAddr)
+ sb.append(" ");
+ sb.append(Arrays.toString(exception.getValidUnsentAddresses()));
+ }
+ sb.append(" - [");
+ sb.append(exception.getMessage().replaceAll("\\n", ""));
+ sb.append("] )");
+ }
+ return sb.toString();
+ }
+ return null;
+ }
+
+ /**
+ * Utility method for getting the error message from the (nested) exception.
+ *
+ * @param me MessagingException
+ * @return error message
+ */
+ public String getErrorMsg(Exception ex) {
+ if (ex instanceof MessagingException) {
+ return getNestedExceptionMessage((MessagingException) ex);
+ } else {
+ return ex.getMessage();
+ }
+ }
+
+ public String getNestedExceptionMessage(MessagingException me) {
+ if (me.getNextException() == null) {
+ return me.getMessage().trim();
+ } else {
+ Exception ex1 = me.getNextException();
+ return ex1.getMessage().trim();
+ }
+ }
+
+ public String composeFailLogMessage(Mail mail, Exception ex, boolean permanent) {
+ StringWriter sout = new StringWriter();
+ PrintWriter out = new PrintWriter(sout, true);
+ out.print(permanentAsString(permanent) + " exception delivering mail (" + mail.getName() + ")" + retrieveExceptionLog(ex) + ": " );
+ if (configuration.isDebug()) {
+ ex.printStackTrace(out);
+ }
+ return sout.toString();
+ }
+
+ private String permanentAsString(boolean permanent) {
+ if (permanent) {
+ return "Permanent";
+ }
+ return "Temporary";
+ }
+
+ private String retrieveExceptionLog(Exception ex) {
+ String exceptionLog = fromException(ex);
+ if (exceptionLog != null) {
+ return ". " + exceptionLog;
+ }
+ return "";
+ }
+
+ private Object invokeGetter(Object target, String getter) {
+ try {
+ Method getAddress = target.getClass().getMethod(getter);
+ return getAddress.invoke(target);
+ } catch (NoSuchMethodException nsme) {
+ // An SMTPAddressFailedException with no getAddress method.
+ } catch (IllegalAccessException iae) {
+ } catch (IllegalArgumentException iae) {
+ } catch (InvocationTargetException ite) {
+ // Other issues with getAddress invokation.
+ }
+ return new IllegalStateException("Exception invoking " + getter + " on a " + target.getClass() + " object");
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[26/50] [abbrv] james-project git commit: JAMES-1877 Introduce a
helper for working with MessagingException
Posted by ro...@apache.org.
JAMES-1877 Introduce a helper for working with MessagingException
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/a0ca1bfa
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/a0ca1bfa
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/a0ca1bfa
Branch: refs/heads/master
Commit: a0ca1bfa700afb4e5e14aedb2fcca29c146d0489
Parents: 2a4936d
Author: Benoit Tellier <bt...@linagora.com>
Authored: Fri Dec 2 10:06:14 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:51 2017 +0700
----------------------------------------------------------------------
.../remoteDelivery/DeliveryRunnable.java | 135 +++++-----------
.../EnhancedMessagingException.java | 161 +++++++++++++++++++
2 files changed, 200 insertions(+), 96 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/a0ca1bfa/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index c45e736..d62f6f6 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -51,6 +51,7 @@ import org.apache.mailet.MailAddress;
import org.apache.mailet.MailetContext;
import org.slf4j.Logger;
+import com.google.common.base.Optional;
import com.sun.mail.smtp.SMTPTransport;
@SuppressWarnings("deprecation")
@@ -334,6 +335,7 @@ public class DeliveryRunnable implements Runnable {
Collection<MailAddress> recipients = new ArrayList<MailAddress>(mail.getRecipients());
ExecutionResult deleteMessage = ExecutionResult.temporaryFailure();
+ EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
/*
* If you send a message that has multiple invalid addresses, you'll
@@ -357,32 +359,12 @@ public class DeliveryRunnable implements Runnable {
* SMTPSendFailedException introduced in JavaMail 1.3.2, and
* provides detailed protocol reply code for the operation
*/
- try {
- if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
- int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
- // If we got an SMTPSendFailedException, use its RetCode to
- // determine default permanent/temporary failure
- deleteMessage = ExecutionResult.onFailure(returnCode >= 500 && returnCode <= 599, sfe);
+ if (enhancedMessagingException.hasReturnCode()) {
+ if (enhancedMessagingException.isServerError()) {
+ deleteMessage = ExecutionResult.permanentFailure(sfe);
} else {
- // Sometimes we'll get a normal SendFailedException with
- // nested SMTPAddressFailedException, so use the latter
- // RetCode
- MessagingException me = sfe;
- Exception ne;
- while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
- me = (MessagingException) ne;
- if (me.getClass().getName().endsWith(".SMTPAddressFailedException")) {
- int returnCode = (Integer) invokeGetter(me, "getReturnCode");
- deleteMessage = ExecutionResult.onFailure(returnCode >= 500 && returnCode <= 599, sfe);
- }
- }
+ deleteMessage = ExecutionResult.temporaryFailure(sfe);
}
- } catch (IllegalStateException ise) {
- // unexpected exception (not a compatible javamail
- // implementation)
- } catch (ClassCastException cce) {
- // unexpected exception (not a compatible javamail
- // implementation)
}
// log the original set of intended recipients
@@ -432,9 +414,8 @@ public class DeliveryRunnable implements Runnable {
if (configuration.isDebug())
logger.debug("Unsent recipients: " + recipients);
- if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
- int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
- boolean isPermanent = returnCode >= 500 && returnCode <= 599;
+ if (enhancedMessagingException.hasReturnCode()) {
+ boolean isPermanent = enhancedMessagingException.isServerError();
deleteMessage = ExecutionResult.onFailure(isPermanent, sfe);
logger.debug(messageComposer.composeFailLogMessage(mail, deleteMessage));
} else {
@@ -458,20 +439,13 @@ public class DeliveryRunnable implements Runnable {
}
}
- /*
- * SMTPSendFailedException introduced in JavaMail 1.3.2, and
- * provides detailed protocol reply code for the operation
- */
- if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
- try {
- int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
- // if 5xx, terminate this delivery attempt by
- // re-throwing the exception.
- if (returnCode >= 500 && returnCode <= 599)
- throw sfe;
- } catch (ClassCastException cce) {
- } catch (IllegalArgumentException iae) {
- }
+ /*
+ * SMTPSendFailedException introduced in JavaMail 1.3.2, and
+ * provides detailed protocol reply code for the operation
+ */
+ EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
+ if (enhancedMessagingException.isServerError()) {
+ throw sfe;
}
if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) {
@@ -585,65 +559,34 @@ public class DeliveryRunnable implements Runnable {
return configuration.getDelayTimes().get(retry_count - 1);
}
-
- private Object invokeGetter(Object target, String getter) {
- try {
- Method getAddress = target.getClass().getMethod(getter);
- return getAddress.invoke(target);
- } catch (NoSuchMethodException nsme) {
- // An SMTPAddressFailedException with no getAddress method.
- } catch (IllegalAccessException iae) {
- } catch (IllegalArgumentException iae) {
- } catch (InvocationTargetException ite) {
- // Other issues with getAddress invokation.
- }
- return new IllegalStateException("Exception invoking " + getter + " on a " + target.getClass() + " object");
- }
-
private void logSendFailedException(SendFailedException sfe) {
if (configuration.isDebug()) {
- MessagingException me = sfe;
- if (me.getClass().getName().endsWith(".SMTPSendFailedException")) {
- try {
- String command = (String) invokeGetter(sfe, "getCommand");
- Integer returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
- logger.debug("SMTP SEND FAILED:");
- logger.debug(sfe.toString());
- logger.debug(" Command: " + command);
- logger.debug(" RetCode: " + returnCode);
- logger.debug(" Response: " + sfe.getMessage());
- } catch (IllegalStateException ise) {
- // Error invoking the getAddress method
- logger.debug("Send failed: " + me.toString());
- } catch (ClassCastException cce) {
- // The getAddress method returned something different than
- // InternetAddress
- logger.debug("Send failed: " + me.toString());
- }
+ EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
+ if (enhancedMessagingException.hasReturnCode()) {
+ logger.debug("SMTP SEND FAILED:");
+ logger.debug(sfe.toString());
+ logger.debug(" Command: " + enhancedMessagingException.computeCommand());
+ logger.debug(" RetCode: " + enhancedMessagingException.getReturnCode());
+ logger.debug(" Response: " + sfe.getMessage());
} else {
- logger.debug("Send failed: " + me.toString());
+ logger.debug("Send failed: " + sfe.toString());
}
- Exception ne;
- while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
- me = (MessagingException) ne;
- if (me.getClass().getName().endsWith(".SMTPAddressFailedException") || me.getClass().getName().endsWith(".SMTPAddressSucceededException")) {
- try {
- String action = me.getClass().getName().endsWith(".SMTPAddressFailedException") ? "FAILED" : "SUCCEEDED";
- InternetAddress address = (InternetAddress) invokeGetter(me, "getAddress");
- String command = (String) invokeGetter(me, "getCommand");
- Integer returnCode = (Integer) invokeGetter(me, "getReturnCode");
- logger.debug("ADDRESS " + action + ":");
- logger.debug(me.toString());
- logger.debug(" Address: " + address);
- logger.debug(" Command: " + command);
- logger.debug(" RetCode: " + returnCode);
- logger.debug(" Response: " + me.getMessage());
- } catch (IllegalStateException ise) {
- // Error invoking the getAddress method
- } catch (ClassCastException cce) {
- // A method returned something different than expected
- }
- }
+ logLevels(sfe);
+ }
+ }
+
+ private void logLevels(MessagingException me) {
+ Exception ne;
+ while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
+ me = (MessagingException) ne;
+ EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(me);
+ if (me.getClass().getName().endsWith(".SMTPAddressFailedException") || me.getClass().getName().endsWith(".SMTPAddressSucceededException")) {
+ logger.debug("ADDRESS " + enhancedMessagingException.computeAction() + ":");
+ logger.debug(me.toString());
+ logger.debug(" Address: " + enhancedMessagingException.computeAddress());
+ logger.debug(" Command: " + enhancedMessagingException.computeCommand());
+ logger.debug(" RetCode: " + enhancedMessagingException.getReturnCode());
+ logger.debug(" Response: " + me.getMessage());
}
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/a0ca1bfa/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/EnhancedMessagingException.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/EnhancedMessagingException.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/EnhancedMessagingException.java
new file mode 100644
index 0000000..44b40bd
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/EnhancedMessagingException.java
@@ -0,0 +1,161 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.InternetAddress;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+public class EnhancedMessagingException {
+
+ private final MessagingException messagingException;
+ private final Optional<Integer> returnCode;
+ private final Optional<Integer> nestedReturnCode;
+
+ public EnhancedMessagingException(MessagingException messagingException) {
+ this.messagingException = messagingException;
+ this.returnCode = computeReturnCode();
+ this.nestedReturnCode = computeNestedReturnCode();
+ }
+
+ public boolean hasReturnCode() {
+ return returnCode.isPresent();
+ }
+
+ public boolean hasNestedReturnCode() {
+ return nestedReturnCode.isPresent();
+ }
+
+ public boolean isServerError() {
+ return isServerError(returnCode) || isServerError(nestedReturnCode);
+ }
+
+ private boolean isServerError(Optional<Integer> returnCode) {
+ return (returnCode.isPresent()
+ && returnCode.get() >= 500
+ && returnCode.get() <= 599)
+ || messageIndicatesServerException();
+ }
+
+ private boolean messageIndicatesServerException() {
+ return Optional.fromNullable(messagingException.getMessage())
+ .transform(startWith5())
+ .or(false);
+ }
+
+ private Function<String, Boolean> startWith5() {
+ return new Function<String, Boolean>() {
+ @Override
+ public Boolean apply(String input) {
+ return input.startsWith("5");
+ }
+ };
+ }
+
+ private Optional<Integer> computeReturnCode() {
+ if (messagingException.getClass().getName().endsWith(".SMTPSendFailedException")
+ || messagingException.getClass().getName().endsWith(".SMTPAddressSucceededException")) {
+ try {
+ return Optional.of ((Integer) invokeGetter(messagingException, "getReturnCode"));
+ } catch (ClassCastException cce) {
+ } catch (IllegalArgumentException iae) {
+ } catch (IllegalStateException ise) {
+ }
+ }
+ return Optional.absent();
+ }
+
+ public Optional<String> computeCommand() {
+ if (hasReturnCode()) {
+ try {
+ return Optional.of((String) invokeGetter(messagingException, "getCommand"));
+ } catch (ClassCastException cce) {
+ } catch (IllegalArgumentException iae) {
+ } catch (IllegalStateException ise) {
+ }
+ }
+ return Optional.absent();
+ }
+
+ public Optional<InternetAddress> computeAddress() {
+ if (hasReturnCode()) {
+ try {
+ return Optional.of((InternetAddress) invokeGetter(messagingException, "getAddress"));
+ } catch (ClassCastException cce) {
+ } catch (IllegalArgumentException iae) {
+ } catch (IllegalStateException ise) {
+ }
+ }
+ return Optional.absent();
+ }
+
+ public String computeAction() {
+ return messagingException.getClass().getName().endsWith(".SMTPAddressFailedException") ? "FAILED" : "SUCCEEDED";
+ }
+
+ public Optional<Integer> getReturnCode() {
+ return returnCode;
+ }
+
+ private Optional<Integer> computeNestedReturnCode() {
+ EnhancedMessagingException currentMessagingException = this;
+ while (true) {
+ Optional<Integer> returnCode = currentMessagingException.computeReturnCode();
+ if (returnCode.isPresent()) {
+ return returnCode;
+ }
+ if (currentMessagingException.hasNestedMessagingException()) {
+ currentMessagingException = currentMessagingException.getNestedMessagingException();
+ } else {
+ return Optional.absent();
+ }
+ }
+ }
+
+ private boolean hasNestedMessagingException() {
+ return messagingException.getNextException() != null
+ && messagingException.getNextException() instanceof MessagingException;
+ }
+
+ private EnhancedMessagingException getNestedMessagingException() {
+ Preconditions.checkState(hasNestedMessagingException());
+ return new EnhancedMessagingException((MessagingException) messagingException.getNextException());
+ }
+
+ private Object invokeGetter(Object target, String getter) {
+ try {
+ Method getAddress = target.getClass().getMethod(getter);
+ return getAddress.invoke(target);
+ } catch (NoSuchMethodException nsme) {
+ // An SMTPAddressFailedException with no getAddress method.
+ } catch (IllegalAccessException iae) {
+ } catch (IllegalArgumentException iae) {
+ } catch (InvocationTargetException ite) {
+ // Other issues with getAddress invokation.
+ }
+ return new IllegalStateException("Exception invoking " + getter + " on a " + target.getClass() + " object");
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[48/50] [abbrv] james-project git commit: JAMES-1877 Remove wildcard
and eclipse warnings
Posted by ro...@apache.org.
JAMES-1877 Remove wildcard and eclipse warnings
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/4221b357
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/4221b357
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/4221b357
Branch: refs/heads/master
Commit: 4221b357cfe2a02172a4d4c54b5a20b946efc6ba
Parents: c06d312
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Dec 7 11:50:00 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 18:14:32 2017 +0700
----------------------------------------------------------------------
.../src/test/java/org/apache/james/util/streams/IteratorsTest.java | 2 +-
.../transport/mailets/remoteDelivery/DeliveryRunnableTest.java | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/4221b357/server/container/util-java8/src/test/java/org/apache/james/util/streams/IteratorsTest.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/streams/IteratorsTest.java b/server/container/util-java8/src/test/java/org/apache/james/util/streams/IteratorsTest.java
index cad060d..4c63f1a 100644
--- a/server/container/util-java8/src/test/java/org/apache/james/util/streams/IteratorsTest.java
+++ b/server/container/util-java8/src/test/java/org/apache/james/util/streams/IteratorsTest.java
@@ -22,7 +22,7 @@ package org.apache.james.util.streams;
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
-import java.util.stream.*;
+import java.util.stream.Stream;
import org.junit.Test;
http://git-wip-us.apache.org/repos/asf/james-project/blob/4221b357/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnableTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnableTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnableTest.java
index 1bfec0d..f8dfd40 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnableTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnableTest.java
@@ -19,7 +19,6 @@
package org.apache.james.transport.mailets.remoteDelivery;
-import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[02/50] [abbrv] james-project git commit: JAMES-1877 Extract HeloName
provider and test it
Posted by ro...@apache.org.
JAMES-1877 Extract HeloName provider and test it
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/1cb969bd
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/1cb969bd
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/1cb969bd
Branch: refs/heads/master
Commit: 1cb969bdda7db0ba8f1c8b52adeb27186bb566e7
Parents: e82996e
Author: Benoit Tellier <bt...@linagora.com>
Authored: Tue Nov 29 10:27:13 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 11:37:10 2017 +0700
----------------------------------------------------------------------
.../james/transport/mailets/RemoteDelivery.java | 30 ++------
.../remoteDelivery/HeloNameProvider.java | 53 +++++++++++++
.../remoteDelivery/HeloNameProviderTest.java | 79 ++++++++++++++++++++
3 files changed, 140 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/1cb969bd/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index 0e7e48d..c4113b5 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -53,12 +53,10 @@ import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimePart;
import javax.mail.internet.ParseException;
-import com.sun.mail.smtp.SMTPTransport;
import org.apache.james.dnsservice.api.DNSService;
import org.apache.james.dnsservice.api.TemporaryResolutionException;
import org.apache.james.dnsservice.library.MXHostAddressIterator;
import org.apache.james.domainlist.api.DomainList;
-import org.apache.james.domainlist.api.DomainListException;
import org.apache.james.lifecycle.api.LifecycleUtil;
import org.apache.james.metrics.api.Metric;
import org.apache.james.metrics.api.MetricFactory;
@@ -67,6 +65,7 @@ import org.apache.james.queue.api.MailQueue;
import org.apache.james.queue.api.MailQueue.MailQueueException;
import org.apache.james.queue.api.MailQueue.MailQueueItem;
import org.apache.james.queue.api.MailQueueFactory;
+import org.apache.james.transport.mailets.remoteDelivery.HeloNameProvider;
import org.apache.james.transport.mailets.remoteDelivery.RemoteDeliverySocketFactory;
import org.apache.james.transport.util.Patterns;
import org.apache.james.util.TimeConverter;
@@ -77,6 +76,8 @@ import org.apache.mailet.MailetContext;
import org.apache.mailet.base.GenericMailet;
import org.slf4j.Logger;
+import com.sun.mail.smtp.SMTPTransport;
+
/**
* <p>The RemoteDelivery mailet delivers messages to a remote SMTP server able to deliver or forward messages to their final
* destination.
@@ -252,8 +253,6 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
private MailQueue queue;
- private String heloName;
-
private Logger logger;
private boolean usePriority;
@@ -266,6 +265,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
private MetricFactory metricFactory;
private Metric outgoingMailsMetric;
+ private HeloNameProvider heloNameProvider;
@Inject
public void setDomainList(DomainList domainList) {
@@ -444,7 +444,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
dnsProblemRetry = Integer.parseInt(dnsRetry);
}
- heloName = getInitParameter("heloName");
+ heloNameProvider = new HeloNameProvider(getInitParameter("heloName"), domainList);
String prio = getInitParameter("usePriority");
if (prio != null) {
@@ -751,7 +751,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
props.put("mail.smtp.connectiontimeout", connectionTimeout + "");
props.put("mail.smtp.sendpartial", String.valueOf(sendPartial));
- props.put("mail.smtp.localhost", getHeloName());
+ props.put("mail.smtp.localhost", heloNameProvider.getHeloName());
// handle starttls
props.put("mail.smtp.starttls.enable", String.valueOf(startTLS));
@@ -970,7 +970,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
SMTPTransport transport = null;
try {
transport = (SMTPTransport) session.getTransport(outgoingMailServer);
- transport.setLocalHost( props.getProperty("mail.smtp.localhost", heloName) );
+ transport.setLocalHost( props.getProperty("mail.smtp.localhost", heloNameProvider.getHeloName()) );
try {
if (authUser != null) {
transport.connect(outgoingMailServer.getHostName(), authUser, authPass);
@@ -1555,7 +1555,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
PrintWriter out = new PrintWriter(sout, true);
String machine;
try {
- machine = getHeloName();
+ machine = heloNameProvider.getHeloName();
} catch (Exception e) {
machine = "[address unknown]";
@@ -1631,18 +1631,4 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
return new MXHostAddressIterator(gateways, dnsServer, false, logger);
}
- protected String getHeloName() {
- if (heloName == null) {
- // TODO: Maybe we should better just lookup the hostname via dns
- try {
- return domainList.getDefaultDomain();
- } catch (DomainListException e) {
- log("Unable to access DomainList", e);
- return "localhost";
- }
- } else {
- return heloName;
- }
- }
-
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/1cb969bd/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/HeloNameProvider.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/HeloNameProvider.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/HeloNameProvider.java
new file mode 100644
index 0000000..b91c68e
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/HeloNameProvider.java
@@ -0,0 +1,53 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.domainlist.api.DomainListException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HeloNameProvider {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(HeloNameProvider.class);
+ public static final String LOCALHOST = "localhost";
+
+ private final String heloName;
+ private final DomainList domainList;
+
+ public HeloNameProvider(String heloName, DomainList domainList) {
+ this.heloName = heloName;
+ this.domainList = domainList;
+ }
+
+ public String getHeloName() {
+ if (heloName == null) {
+ // TODO: Maybe we should better just lookup the hostname via dns
+ try {
+ return domainList.getDefaultDomain();
+ } catch (DomainListException e) {
+ LOGGER.warn("Unable to access DomainList", e);
+ return LOCALHOST;
+ }
+ } else {
+ return heloName;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/1cb969bd/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/HeloNameProviderTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/HeloNameProviderTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/HeloNameProviderTest.java
new file mode 100644
index 0000000..987b99b
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/HeloNameProviderTest.java
@@ -0,0 +1,79 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.mockito.Mockito.mock;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.domainlist.api.DomainListException;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class HeloNameProviderTest {
+
+ public static final String DOMAIN = "domain";
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private DomainList domainList;
+
+ @Before
+ public void setUp() {
+ domainList = mock(DomainList.class);
+ }
+
+ @Test
+ public void getHeloNameShouldReturnNonNullProvidedHeloName() {
+ HeloNameProvider heloNameProvider = new HeloNameProvider(DOMAIN, domainList);
+
+ assertThat(heloNameProvider.getHeloName()).isEqualTo(DOMAIN);
+ }
+
+ @Test
+ public void getHeloNameShouldReturnDomainListDefaultDomainOnNullHeloName() throws DomainListException {
+ when(domainList.getDefaultDomain()).thenReturn(DOMAIN);
+ HeloNameProvider heloNameProvider = new HeloNameProvider(null, domainList);
+
+ assertThat(heloNameProvider.getHeloName()).isEqualTo(DOMAIN);
+ }
+
+ @Test
+ public void getHeloNameShouldReturnLocalhostOnDomainListException() throws DomainListException {
+ when(domainList.getDefaultDomain()).thenThrow(new DomainListException("any message"));
+ HeloNameProvider heloNameProvider = new HeloNameProvider(null, domainList);
+
+ assertThat(heloNameProvider.getHeloName()).isEqualTo(HeloNameProvider.LOCALHOST);
+ }
+
+ @Test
+ public void getHeloNameShouldPropagateRuntimeExceptions() throws DomainListException {
+ when(domainList.getDefaultDomain()).thenThrow(new RuntimeException());
+ HeloNameProvider heloNameProvider = new HeloNameProvider(null, domainList);
+
+ expectedException.expect(RuntimeException.class);
+ heloNameProvider.getHeloName();
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[23/50] [abbrv] james-project git commit: JAMES-1877 Remove unrelated
exception
Posted by ro...@apache.org.
JAMES-1877 Remove unrelated exception
No attempts to dequeue the e-mail was done, no need to throw an exception that will be caught 10 lines under
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/f5fc4757
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/f5fc4757
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/f5fc4757
Branch: refs/heads/master
Commit: f5fc4757e0965b3205d4e519378d5d12b8bce2c8
Parents: cb0cb77
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 16:14:10 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:50 2017 +0700
----------------------------------------------------------------------
.../james/transport/mailets/remoteDelivery/DeliveryRunnable.java | 1 -
1 file changed, 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/f5fc4757/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index b8be45d..f6763ef 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -113,7 +113,6 @@ public class DeliveryRunnable implements Runnable {
logger.error("Exception caught in RemoteDelivery.run()", e);
LifecycleUtil.dispose(mail);
queueItem.done(false);
- throw new MailQueue.MailQueueException("Unable to perform dequeue", e);
}
} catch (Throwable e) {
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[44/50] [abbrv] james-project git commit: JAMES-1877
MailDelivrerToHost interface simplification
Posted by ro...@apache.org.
JAMES-1877 MailDelivrerToHost interface simplification
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/97e23aee
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/97e23aee
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/97e23aee
Branch: refs/heads/master
Commit: 97e23aee67370202e5d3406becc377f9148a31a3
Parents: d004e6e
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Dec 7 11:07:46 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 18:14:27 2017 +0700
----------------------------------------------------------------------
.../james/transport/mailets/remoteDelivery/MailDelivrer.java | 7 +++----
.../transport/mailets/remoteDelivery/MailDelivrerToHost.java | 4 ++--
2 files changed, 5 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/97e23aee/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
index 1dfc81b..f42a0fc 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
@@ -28,7 +28,6 @@ import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.SendFailedException;
import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
import org.apache.james.dnsservice.api.DNSService;
import org.apache.james.dnsservice.api.TemporaryResolutionException;
@@ -119,7 +118,7 @@ public class MailDelivrer {
if (!targetServers.hasNext()) {
return handleNoTargetServer(mail, host);
}
- return doDeliver(mail, mail.getMessage(), InternetAddressConverter.convert(mail.getRecipients()), targetServers);
+ return doDeliver(mail, InternetAddressConverter.convert(mail.getRecipients()), targetServers);
} catch (TemporaryResolutionException e) {
return logAndReturn(mail, ExecutionResult.temporaryFailure(new MessagingException("Temporary problem looking " +
"up mail server for host: " + host + ". I cannot determine where to send this message.")));
@@ -132,12 +131,12 @@ public class MailDelivrer {
}
@SuppressWarnings("deprecation")
- private ExecutionResult doDeliver(Mail mail, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException {
+ private ExecutionResult doDeliver(Mail mail, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException {
MessagingException lastError = null;
while (targetServers.hasNext()) {
try {
- if (mailDelivrerToHost.tryDeliveryToHost(mail, message, addr, targetServers.next())) {
+ if (mailDelivrerToHost.tryDeliveryToHost(mail, addr, targetServers.next())) {
return ExecutionResult.success();
}
} catch (SendFailedException sfe) {
http://git-wip-us.apache.org/repos/asf/james-project/blob/97e23aee/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java
index 46bd8f9..a9f5758 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java
@@ -50,7 +50,7 @@ public class MailDelivrerToHost {
this.logger = logger;
}
- public boolean tryDeliveryToHost(Mail mail, MimeMessage message, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException {
+ public boolean tryDeliveryToHost(Mail mail, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException {
Properties props = session.getProperties();
if (mail.getSender() == null) {
props.put("mail.smtp.from", "<>");
@@ -74,7 +74,7 @@ public class MailDelivrerToHost {
transport = (SMTPTransport) session.getTransport(outgoingMailServer);
transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
connect(outgoingMailServer, transport);
- transport.sendMessage(adaptToTransport(message, transport), addr);
+ transport.sendMessage(adaptToTransport(mail.getMessage(), transport), addr);
logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() +
" at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients());
return true;
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[32/50] [abbrv] james-project git commit: JAMES-1877 Improve Bouncer :
Posted by ro...@apache.org.
JAMES-1877 Improve Bouncer :
- Stop failing on empty exception error message
- Remove extra space in message
- Move methods of MessageComposer used only by Bouncer
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/6a2fe8a8
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/6a2fe8a8
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/6a2fe8a8
Branch: refs/heads/master
Commit: 6a2fe8a883e37afaebcd832dcee1082314b65d2d
Parents: 9b59d55
Author: Benoit Tellier <bt...@linagora.com>
Authored: Fri Dec 2 13:57:11 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:52 2017 +0700
----------------------------------------------------------------------
.../mailets/remoteDelivery/Bouncer.java | 69 +++++++++++++-------
.../mailets/remoteDelivery/MessageComposer.java | 23 -------
.../mailets/remoteDelivery/BouncerTest.java | 62 +++++++++++++-----
3 files changed, 93 insertions(+), 61 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/6a2fe8a8/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
index da90b08..fa60c23 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
@@ -37,28 +37,26 @@ public class Bouncer {
public static final String DELIVERY_ERROR = "delivery-error";
private final RemoteDeliveryConfiguration configuration;
- private final MessageComposer messageComposer;
private final MailetContext mailetContext;
private final Logger logger;
public Bouncer(RemoteDeliveryConfiguration configuration, MailetContext mailetContext, Logger logger) {
this.configuration = configuration;
- this.messageComposer = new MessageComposer(configuration);
this.mailetContext = mailetContext;
this.logger = logger;
}
public void bounce(Mail mail, Exception ex) {
if (mail.getSender() == null) {
- logger.debug("Null Sender: no bounce will be generated for " + mail.getName());
+ logger.debug("Null Sender: no bounce will be generated for {}", mail.getName());
} else {
if (configuration.getBounceProcessor() != null) {
- mail.setAttribute(DELIVERY_ERROR, messageComposer.getErrorMsg(ex));
+ mail.setAttribute(DELIVERY_ERROR, getErrorMsg(ex));
mail.setState(configuration.getBounceProcessor());
try {
mailetContext.sendMail(mail);
} catch (MessagingException e) {
- logger.debug("Exception re-inserting failed mail: ", e);
+ logger.warn("Exception re-inserting failed mail: ", e);
}
} else {
bounceWithMailetContext(mail, ex);
@@ -72,26 +70,18 @@ public class Bouncer {
try {
mailetContext.bounce(mail, explanationText(mail, ex));
} catch (MessagingException me) {
- logger.debug("Encountered unexpected messaging exception while bouncing message: " + me.getMessage());
+ logger.warn("Encountered unexpected messaging exception while bouncing message: {}", me.getMessage());
} catch (Exception e) {
- logger.debug("Encountered unexpected exception while bouncing message: " + e.getMessage());
+ logger.warn("Encountered unexpected exception while bouncing message: {}", e.getMessage());
}
}
public String explanationText(Mail mail, Exception ex) {
StringWriter sout = new StringWriter();
PrintWriter out = new PrintWriter(sout, true);
- String machine;
- try {
- machine = configuration.getHeloNameProvider().getHeloName();
-
- } catch (Exception e) {
- machine = "[address unknown]";
- }
- String bounceBuffer = "Hi. This is the James mail server at " + machine + ".";
- out.println(bounceBuffer);
+ out.println("Hi. This is the James mail server at " + resolveMachineName() + ".");
out.println("I'm afraid I wasn't able to deliver your message to the following addresses.");
- out.println("This is a permanent error; I've given up. Sorry it didn't work out. Below");
+ out.println("This is a permanent error; I've given up. Sorry it didn't work out. Below");
out.println("I include the list of recipients and the reason why I was unable to deliver");
out.println("your message.");
out.println();
@@ -100,25 +90,58 @@ public class Bouncer {
}
if (ex instanceof MessagingException) {
if (((MessagingException) ex).getNextException() == null) {
- out.println(ex.getMessage().trim());
+ out.println(sanitizeExceptionMessage(ex));
} else {
Exception ex1 = ((MessagingException) ex).getNextException();
if (ex1 instanceof SendFailedException) {
- out.println("Remote mail server told me: " + ex1.getMessage().trim());
+ out.println("Remote mail server told me: " + sanitizeExceptionMessage(ex1));
} else if (ex1 instanceof UnknownHostException) {
- out.println("Unknown host: " + ex1.getMessage().trim());
+ out.println("Unknown host: " + sanitizeExceptionMessage(ex1));
out.println("This could be a DNS server error, a typo, or a problem with the recipient's mail server.");
} else if (ex1 instanceof ConnectException) {
// Already formatted as "Connection timed out: connect"
- out.println(ex1.getMessage().trim());
+ out.println(sanitizeExceptionMessage(ex1));
} else if (ex1 instanceof SocketException) {
- out.println("Socket exception: " + ex1.getMessage().trim());
+ out.println("Socket exception: " + sanitizeExceptionMessage(ex1));
} else {
- out.println(ex1.getMessage().trim());
+ out.println(sanitizeExceptionMessage(ex1));
}
}
}
out.println();
return sout.toString();
}
+
+ private String sanitizeExceptionMessage(Exception e) {
+ if (e.getMessage() == null) {
+ return "null";
+ } else {
+ return e.getMessage().trim();
+ }
+ }
+
+ private String resolveMachineName() {
+ try {
+ return configuration.getHeloNameProvider().getHeloName();
+ } catch (Exception e) {
+ return "[address unknown]";
+ }
+ }
+
+ public String getErrorMsg(Exception ex) {
+ if (ex instanceof MessagingException) {
+ return getNestedExceptionMessage((MessagingException) ex);
+ } else {
+ return sanitizeExceptionMessage(ex);
+ }
+ }
+
+ public String getNestedExceptionMessage(MessagingException me) {
+ if (me.getNextException() == null) {
+ return sanitizeExceptionMessage(me);
+ } else {
+ Exception ex1 = me.getNextException();
+ return sanitizeExceptionMessage(ex1);
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/6a2fe8a8/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
index 3e6d861..74852e9 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
@@ -99,29 +99,6 @@ public class MessageComposer {
return null;
}
- /**
- * Utility method for getting the error message from the (nested) exception.
- *
- * @param me MessagingException
- * @return error message
- */
- public String getErrorMsg(Exception ex) {
- if (ex instanceof MessagingException) {
- return getNestedExceptionMessage((MessagingException) ex);
- } else {
- return ex.getMessage();
- }
- }
-
- public String getNestedExceptionMessage(MessagingException me) {
- if (me.getNextException() == null) {
- return me.getMessage().trim();
- } else {
- Exception ex1 = me.getNextException();
- return ex1.getMessage().trim();
- }
- }
-
public String composeFailLogMessage(Mail mail, ExecutionResult executionResult) {
StringWriter sout = new StringWriter();
PrintWriter out = new PrintWriter(sout, true);
http://git-wip-us.apache.org/repos/asf/james-project/blob/6a2fe8a8/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/BouncerTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/BouncerTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/BouncerTest.java
index de683c0..cc600ad 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/BouncerTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/BouncerTest.java
@@ -74,7 +74,7 @@ public class BouncerTest {
FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
"Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
"I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
- "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
"I include the list of recipients and the reason why I was unable to deliver\n" +
"your message.\n\n\n",
Optional.<MailAddress>absent());
@@ -101,7 +101,7 @@ public class BouncerTest {
FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
"Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
"I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
- "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
"I include the list of recipients and the reason why I was unable to deliver\n" +
"your message.\n" +
"\n" +
@@ -130,7 +130,7 @@ public class BouncerTest {
FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
"Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
"I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
- "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
"I include the list of recipients and the reason why I was unable to deliver\n" +
"your message.\n" +
"\n" +
@@ -159,7 +159,7 @@ public class BouncerTest {
FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
"Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
"I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
- "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
"I include the list of recipients and the reason why I was unable to deliver\n" +
"your message.\n" +
"\n" +
@@ -189,7 +189,7 @@ public class BouncerTest {
FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
"Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
"I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
- "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
"I include the list of recipients and the reason why I was unable to deliver\n" +
"your message.\n" +
"\n" +
@@ -218,7 +218,7 @@ public class BouncerTest {
FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
"Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
"I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
- "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
"I include the list of recipients and the reason why I was unable to deliver\n" +
"your message.\n" +
"\n" +
@@ -247,7 +247,7 @@ public class BouncerTest {
FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
"Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
"I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
- "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
"I include the list of recipients and the reason why I was unable to deliver\n" +
"your message.\n" +
"\n" +
@@ -277,7 +277,7 @@ public class BouncerTest {
}
@Test
- public void bounceShouldSupportExceptionWithoutMessagesByDefaultByDefault() throws Exception {
+ public void bounceShouldSupportExceptionWithoutMessagesByDefault() throws Exception {
RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
FakeMailetConfig.builder()
.setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
@@ -294,7 +294,7 @@ public class BouncerTest {
FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
"Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
"I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
- "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
"I include the list of recipients and the reason why I was unable to deliver\n" +
"your message.\n\n\n",
Optional.<MailAddress>absent());
@@ -303,7 +303,7 @@ public class BouncerTest {
}
@Test
- public void bounceShouldNotSupportMessagingExceptionWithoutMessagesByDefaultByDefault() throws Exception {
+ public void bounceShouldNotSupportMessagingExceptionWithoutMessagesByDefault() throws Exception {
RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
FakeMailetConfig.builder()
.setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
@@ -317,8 +317,15 @@ public class BouncerTest {
.build();
testee.bounce(mail, new MessagingException());
+ FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
+ "Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
+ "I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "I include the list of recipients and the reason why I was unable to deliver\n" +
+ "your message.\n\nnull\n\n",
+ Optional.<MailAddress>absent());
assertThat(mailetContext.getSentMails()).isEmpty();
- assertThat(mailetContext.getBouncedMails()).isEmpty();
+ assertThat(mailetContext.getBouncedMails()).containsOnly(expected);
}
@Test
@@ -367,7 +374,7 @@ public class BouncerTest {
}
@Test
- public void bounceShouldDisplayAddressByDefaultByDefault() throws Exception {
+ public void bounceShouldDisplayAddressByDefault() throws Exception {
RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
FakeMailetConfig.builder()
.setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
@@ -385,7 +392,7 @@ public class BouncerTest {
FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
"Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
"I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
- "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
"I include the list of recipients and the reason why I was unable to deliver\n" +
"your message.\n\n" +
MailAddressFixture.ANY_AT_JAMES2.asString() + "\n\n",
@@ -395,7 +402,7 @@ public class BouncerTest {
}
@Test
- public void bounceShouldDisplayAddressesByDefaultByDefault() throws Exception {
+ public void bounceShouldDisplayAddressesByDefault() throws Exception {
RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
FakeMailetConfig.builder()
.setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
@@ -413,7 +420,7 @@ public class BouncerTest {
FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail),
"Hi. This is the James mail server at " + HELLO_NAME + ".\n" +
"I'm afraid I wasn't able to deliver your message to the following addresses.\n" +
- "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
+ "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" +
"I include the list of recipients and the reason why I was unable to deliver\n" +
"your message.\n\n" +
MailAddressFixture.ANY_AT_JAMES2.asString() + "\n" +
@@ -422,4 +429,29 @@ public class BouncerTest {
assertThat(mailetContext.getSentMails()).isEmpty();
assertThat(mailetContext.getBouncedMails()).containsOnly(expected);
}
+
+ @Test
+ public void bounceShouldWorkWhenProcessorSpecifiedAndNoExceptionMessage() throws Exception {
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(
+ FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME)
+ .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR)
+ .build(),
+ mock(DomainList.class));
+ Bouncer testee = new Bouncer(configuration, mailetContext, LOGGER);
+
+ Mail mail = FakeMail.builder().state(Mail.DEFAULT)
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .build();
+ testee.bounce(mail, new MessagingException());
+
+ FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder()
+ .sender(MailAddressFixture.ANY_AT_JAMES)
+ .attribute(DELIVERY_ERROR, "null")
+ .state(BOUNCE_PROCESSOR)
+ .build();
+ assertThat(mailetContext.getSentMails()).containsOnly(expected);
+ assertThat(mailetContext.getBouncedMails()).isEmpty();
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[22/50] [abbrv] james-project git commit: JAMES-1877 Centralize
decision making in DeliveryRunnable
Posted by ro...@apache.org.
JAMES-1877 Centralize decision making in DeliveryRunnable
All parts generates ExecutionResults.
All boucing / success / enqueuing decision should be centralized
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/bc52f337
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/bc52f337
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/bc52f337
Branch: refs/heads/master
Commit: bc52f3375231187e3f5093f43ee995c2dce365ce
Parents: c8a3dd9
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 18:14:25 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:50 2017 +0700
----------------------------------------------------------------------
.../remoteDelivery/DeliveryRunnable.java | 130 +++++++++----------
1 file changed, 62 insertions(+), 68 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/bc52f337/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index 45169a1..a3e08ef 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -186,22 +186,44 @@ public class DeliveryRunnable implements Runnable {
outgoingMailsMetric.increment();
break;
case TEMPORARY_FAILURE:
- // TODO move the incrementing of retries here instead of in fail message
- // Something happened that will delay delivery. Store it back in the retry repository.
- long delay = getNextDelay(DeliveryRetriesHelper.retrieveRetries(mail));
-
- if (configuration.isUsePriority()) {
- // Use lowest priority for retries. See JAMES-1311
- mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY);
- }
- queue.enQueue(mail, delay, TimeUnit.MILLISECONDS);
+ handleTemporaryFailure(mail, executionResult);
break;
case PERMANENT_FAILURE:
- // TODO move boucing logic here
+ bounce(mail, executionResult.getException().orNull());
break;
}
}
+ private void handleTemporaryFailure(Mail mail, ExecutionResult executionResult) throws MailQueue.MailQueueException {
+ if (!mail.getState().equals(Mail.ERROR)) {
+ mail.setState(Mail.ERROR);
+ DeliveryRetriesHelper.initRetries(mail);
+ mail.setLastUpdated(new Date());
+ }
+ int retries = DeliveryRetriesHelper.retrieveRetries(mail);
+
+ if (retries < configuration.getMaxRetries()) {
+ reAttemptDelivery(mail, retries);
+ } else {
+ logger.debug("Bouncing message " + mail.getName() + " after " + retries + " retries");
+ bounce(mail, new Exception("Too many retries failure. Bouncing after " + retries + " retries.", executionResult.getException().orNull()));
+ }
+ }
+
+ private void reAttemptDelivery(Mail mail, int retries) throws MailQueue.MailQueueException {
+ logger.debug("Storing message " + mail.getName() + " into outgoing after " + retries + " retries");
+ DeliveryRetriesHelper.incrementRetries(mail);
+ mail.setLastUpdated(new Date());
+ // Something happened that will delay delivery. Store it back in the retry repository.
+ long delay = getNextDelay(DeliveryRetriesHelper.retrieveRetries(mail));
+
+ if (configuration.isUsePriority()) {
+ // Use lowest priority for retries. See JAMES-1311
+ mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY);
+ }
+ queue.enQueue(mail, delay, TimeUnit.MILLISECONDS);
+ }
+
/**
* We can assume that the recipients of this message are all going to the
* same mail server. We will now rely on the DNS server to do DNS MX record
@@ -215,14 +237,7 @@ public class DeliveryRunnable implements Runnable {
*/
private ExecutionResult deliver(Mail mail, Session session) {
try {
- return Optional.fromNullable(tryDeliver(mail, session))
- .or(failMessage(mail, new MessagingException("No mail server(s) available at this time."), false));
- /*
- * If we get here, we've exhausted the loop of servers without sending
- * the message or throwing an exception. One case where this might
- * happen is if we get a MessagingException on each transport.connect(),
- * e.g., if there is only one server and we get a connect exception.
- */
+ return tryDeliver(mail, session);
} catch (SendFailedException sfe) {
return handleSenderFailedException(mail, sfe);
} catch (MessagingException ex) {
@@ -234,11 +249,15 @@ public class DeliveryRunnable implements Runnable {
// We check whether this is a 5xx error message, which indicates a permanent failure (like account doesn't exist
// or mailbox is full or domain is setup wrong). We fail permanently if this was a 5xx error
- return failMessage(mail, ex, ('5' == ex.getMessage().charAt(0)));
+
+ boolean isPermanent = '5' == ex.getMessage().charAt(0);
+ logger.debug(messageComposer.composeFailLogMessage(mail, ex, isPermanent));
+ return onFailure(isPermanent, ex);
} catch (Exception ex) {
logger.error("Generic exception = permanent failure: " + ex.getMessage(), ex);
// Generic exception = permanent failure
- return failMessage(mail, ex, PERMANENT_FAILURE);
+ logger.debug(messageComposer.composeFailLogMessage(mail, ex, PERMANENT_FAILURE));
+ return permanentFailure(ex);
}
}
@@ -301,7 +320,6 @@ public class DeliveryRunnable implements Runnable {
}
private boolean tryDeliveryToHost(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException {
- boolean success = false;
Properties props = session.getProperties();
if (mail.getSender() == null) {
props.put("mail.smtp.from", "<>");
@@ -325,16 +343,15 @@ public class DeliveryRunnable implements Runnable {
transport = (SMTPTransport) session.getTransport(outgoingMailServer);
transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
if (!connect(outgoingMailServer, transport)) {
- success = false;
+ return false;
}
transport.sendMessage(adaptToTransport(message, transport), addr);
- success = true;
logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() +
" at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients());
+ return true;
} finally {
closeTransport(mail, outgoingMailServer, transport);
}
- return success;
}
private MessagingException handleMessagingException(Mail mail, MessagingException me) throws MessagingException {
@@ -440,7 +457,8 @@ public class DeliveryRunnable implements Runnable {
if (configuration.isDebug())
logger.debug("Invalid recipients: " + recipients);
- deleteMessage = failMessage(mail, sfe, true);
+ logger.debug(messageComposer.composeFailLogMessage(mail, sfe, true));
+ deleteMessage = permanentFailure(sfe);
}
}
@@ -462,11 +480,15 @@ public class DeliveryRunnable implements Runnable {
mail.setRecipients(recipients);
if (configuration.isDebug())
logger.debug("Unsent recipients: " + recipients);
+
if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
- deleteMessage = failMessage(mail, sfe, returnCode >= 500 && returnCode <= 599);
+ boolean isPermanent = returnCode >= 500 && returnCode <= 599;
+ logger.debug(messageComposer.composeFailLogMessage(mail, sfe, isPermanent));
+ deleteMessage = onFailure(isPermanent, sfe);
} else {
- deleteMessage = failMessage(mail, sfe, false);
+ logger.debug(messageComposer.composeFailLogMessage(mail, sfe, false));
+ deleteMessage = temporaryFailure(sfe);
}
}
}
@@ -593,11 +615,9 @@ public class DeliveryRunnable implements Runnable {
}
private ExecutionResult handleTemporaryResolutionException(Mail mail, String host) {
- logger.info("Temporary problem looking up mail server for host: " + host);
- // temporary problems
- return failMessage(mail,
- new MessagingException("Temporary problem looking up mail server for host: " + host + ". I cannot determine where to send this message."),
- false);
+ MessagingException messagingException = new MessagingException("Temporary problem looking up mail server for host: " + host + ". I cannot determine where to send this message.");
+ logger.debug(messageComposer.composeFailLogMessage(mail, messagingException, false));
+ return temporaryFailure(messagingException);
}
private ExecutionResult handleNoTargetServer(Mail mail, String host) {
@@ -607,9 +627,13 @@ public class DeliveryRunnable implements Runnable {
int retry = DeliveryRetriesHelper.retrieveRetries(mail);
if (retry == 0 || retry > configuration.getDnsProblemRetry()) {
// The domain has no dns entry.. Return a permanent error
- return failMessage(mail, new MessagingException(exceptionBuffer), true);
+ MessagingException messagingException = new MessagingException(exceptionBuffer);
+ logger.debug(messageComposer.composeFailLogMessage(mail, messagingException, true));
+ return permanentFailure(messagingException);
} else {
- return failMessage(mail, new MessagingException(exceptionBuffer), false);
+ MessagingException messagingException = new MessagingException(exceptionBuffer);
+ logger.debug(messageComposer.composeFailLogMessage(mail, messagingException, false));
+ return temporaryFailure(messagingException);
}
}
@@ -687,41 +711,13 @@ public class DeliveryRunnable implements Runnable {
}
}
- /**
- * @param mail org.apache.james.core.MailImpl
- * @param ex javax.mail.MessagingException
- * @param permanent
- * @return boolean Whether the message failed fully and can be deleted
- */
- private ExecutionResult failMessage(Mail mail, Exception ex, boolean permanent) {
- logger.debug(messageComposer.composeFailLogMessage(mail, ex, permanent));
- if (!permanent) {
- if (!mail.getState().equals(Mail.ERROR)) {
- mail.setState(Mail.ERROR);
- DeliveryRetriesHelper.initRetries(mail);
- mail.setLastUpdated(new Date());
- }
-
- int retries = DeliveryRetriesHelper.retrieveRetries(mail);
-
- if (retries < configuration.getMaxRetries()) {
- logger.debug("Storing message " + mail.getName() + " into outgoing after " + retries + " retries");
- DeliveryRetriesHelper.incrementRetries(mail);
- mail.setLastUpdated(new Date());
- return temporaryFailure();
- } else {
- logger.debug("Bouncing message " + mail.getName() + " after " + retries + " retries");
- }
- }
-
+ private void bounce(Mail mail, Exception ex) {
if (mail.getSender() == null) {
logger.debug("Null Sender: no bounce will be generated for " + mail.getName());
- return permanentFailure(ex);
}
if (configuration.getBounceProcessor() != null) {
- // do the new DSN bounce
- // setting attributes for DSN mailet
+ // do the new DSN bounce setting attributes for DSN mailet
mail.setAttribute("delivery-error", messageComposer.getErrorMsg(ex));
mail.setState(configuration.getBounceProcessor());
// re-insert the mail into the spool for getting it passed to the dsn-processor
@@ -732,14 +728,12 @@ public class DeliveryRunnable implements Runnable {
logger.debug("Exception re-inserting failed mail: ", e);
}
} else {
- // do an old style bounce
- bounce(mail, ex);
+ bounceWithMailetContext(mail, ex);
}
- return permanentFailure(ex);
}
- private void bounce(Mail mail, Exception ex) {
+ private void bounceWithMailetContext(Mail mail, Exception ex) {
logger.debug("Sending failure message " + mail.getName());
try {
mailetContext.bounce(mail, messageComposer.composeForBounce(mail, ex));
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[28/50] [abbrv] james-project git commit: JAMES-1877 Provide tests
for DeliveryRunnable decision making
Posted by ro...@apache.org.
JAMES-1877 Provide tests for DeliveryRunnable decision making
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/fc1b1d3e
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/fc1b1d3e
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/fc1b1d3e
Branch: refs/heads/master
Commit: fc1b1d3e7054bf1c8ede4c3fb5d0727f677cf13f
Parents: 9790170
Author: Benoit Tellier <bt...@linagora.com>
Authored: Fri Dec 2 14:35:46 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:51 2017 +0700
----------------------------------------------------------------------
.../remoteDelivery/DeliveryRunnable.java | 33 ++-
.../remoteDelivery/DeliveryRunnableTest.java | 249 +++++++++++++++++++
2 files changed, 276 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/fc1b1d3e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index d46a9f5..bc01245 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -31,8 +31,19 @@ import org.apache.mailet.Mail;
import org.apache.mailet.MailetContext;
import org.slf4j.Logger;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Supplier;
+
public class DeliveryRunnable implements Runnable {
+ public static final Supplier<Date> CURRENT_DATE_SUPPLIER = new Supplier<Date>() {
+ @Override
+ public Date get() {
+ return new Date();
+ }
+ };
+ public static final AtomicBoolean DEFAULT_NOT_STARTED = new AtomicBoolean(false);
+
private final MailQueue queue;
private final RemoteDeliveryConfiguration configuration;
private final Metric outgoingMailsMetric;
@@ -40,17 +51,26 @@ public class DeliveryRunnable implements Runnable {
private final Bouncer bouncer;
private final MailDelivrer mailDelivrer;
private final VolatileIsDestroyed volatileIsDestroyed;
+ private final Supplier<Date> dateSupplier;
public DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, DNSService dnsServer, Metric outgoingMailsMetric,
Logger logger, MailetContext mailetContext, VolatileIsDestroyed volatileIsDestroyed) {
+ this(queue, configuration, outgoingMailsMetric, logger, new Bouncer(configuration, mailetContext, logger),
+ new MailDelivrer(configuration, new MailDelivrerToHost(configuration, mailetContext, logger), dnsServer, logger),
+ volatileIsDestroyed, CURRENT_DATE_SUPPLIER);
+ }
+
+ @VisibleForTesting
+ DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, Metric outgoingMailsMetric, Logger logger, Bouncer bouncer,
+ MailDelivrer mailDelivrer, VolatileIsDestroyed volatileIsDestroyed, Supplier<Date> dateSupplier) {
this.queue = queue;
this.configuration = configuration;
this.outgoingMailsMetric = outgoingMailsMetric;
this.logger = logger;
+ this.bouncer = bouncer;
+ this.mailDelivrer = mailDelivrer;
this.volatileIsDestroyed = volatileIsDestroyed;
- this.bouncer = new Bouncer(configuration, mailetContext, logger);
- MailDelivrerToHost mailDelivrerToHost = new MailDelivrerToHost(configuration, mailetContext, logger);
- this.mailDelivrer = new MailDelivrer(configuration, mailDelivrerToHost, dnsServer, logger);
+ this.dateSupplier = dateSupplier;
}
@Override
@@ -98,7 +118,8 @@ public class DeliveryRunnable implements Runnable {
}
}
- private void attemptDelivery(Mail mail) throws MailQueue.MailQueueException {
+ @VisibleForTesting
+ void attemptDelivery(Mail mail) throws MailQueue.MailQueueException {
ExecutionResult executionResult = mailDelivrer.deliver(mail);
switch (executionResult.getExecutionState()) {
case SUCCESS:
@@ -117,7 +138,7 @@ public class DeliveryRunnable implements Runnable {
if (!mail.getState().equals(Mail.ERROR)) {
mail.setState(Mail.ERROR);
DeliveryRetriesHelper.initRetries(mail);
- mail.setLastUpdated(new Date());
+ mail.setLastUpdated(dateSupplier.get());
}
int retries = DeliveryRetriesHelper.retrieveRetries(mail);
@@ -132,7 +153,7 @@ public class DeliveryRunnable implements Runnable {
private void reAttemptDelivery(Mail mail, int retries) throws MailQueue.MailQueueException {
logger.debug("Storing message " + mail.getName() + " into outgoing after " + retries + " retries");
DeliveryRetriesHelper.incrementRetries(mail);
- mail.setLastUpdated(new Date());
+ mail.setLastUpdated(dateSupplier.get());
// Something happened that will delay delivery. Store it back in the retry repository.
long delay = getNextDelay(DeliveryRetriesHelper.retrieveRetries(mail));
http://git-wip-us.apache.org/repos/asf/james-project/blob/fc1b1d3e/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnableTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnableTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnableTest.java
new file mode 100644
index 0000000..1bfec0d
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnableTest.java
@@ -0,0 +1,249 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.metrics.api.Metric;
+import org.apache.james.queue.api.MailQueue;
+import org.apache.mailet.Mail;
+import org.apache.mailet.base.test.FakeMail;
+import org.apache.mailet.base.test.FakeMailetConfig;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Supplier;
+
+public class DeliveryRunnableTest {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DeliveryRunnableTest.class);
+ public static final Date FIXED_DATE = new Date(1159599194961L);
+ public static final Supplier<Date> FIXED_DATE_SUPPLIER = new Supplier<Date>() {
+ @Override
+ public Date get() {
+ return FIXED_DATE;
+ }
+ };
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private DeliveryRunnable testee;
+ private Metric outgoingMailsMetric;
+ private Bouncer bouncer;
+ private MailDelivrer mailDelivrer;
+ private MailQueue mailQueue;
+
+ @Before
+ public void setUp() {
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.DEBUG, "true")
+ .setProperty(RemoteDeliveryConfiguration.DELAY_TIME, "1000,2000,3000,4000,5000")
+ .build();
+
+ RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class));
+ outgoingMailsMetric = mock(Metric.class);
+ bouncer = mock(Bouncer.class);
+ mailDelivrer = mock(MailDelivrer.class);
+ mailQueue = mock(MailQueue.class);
+ testee = new DeliveryRunnable(mailQueue, configuration, outgoingMailsMetric, LOGGER, bouncer, mailDelivrer, DeliveryRunnable.DEFAULT_NOT_STARTED, FIXED_DATE_SUPPLIER);
+ }
+
+ @Test
+ public void deliverySuccessShouldIncrementMetric() throws Exception {
+ FakeMail fakeMail = FakeMail.defaultFakeMail();
+ when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.success());
+
+ testee.attemptDelivery(fakeMail);
+
+ verify(outgoingMailsMetric).increment();
+ verifyNoMoreInteractions(outgoingMailsMetric);
+ }
+
+ @Test
+ public void deliveryPermanentFailureShouldBounceTheMail() throws Exception {
+ FakeMail fakeMail = FakeMail.defaultFakeMail();
+ Exception exception = new Exception();
+ when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.permanentFailure(exception));
+
+ testee.attemptDelivery(fakeMail);
+
+ verify(bouncer).bounce(fakeMail, exception);
+ verifyNoMoreInteractions(bouncer);
+ }
+
+ @Test
+ public void deliveryPermanentFailureShouldNotIncrementDeliveryMetric() throws Exception {
+ FakeMail fakeMail = FakeMail.defaultFakeMail();
+ Exception exception = new Exception();
+ when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.permanentFailure(exception));
+
+ testee.attemptDelivery(fakeMail);
+
+ verifyNoMoreInteractions(outgoingMailsMetric);
+ }
+
+ @Test
+ public void deliveryTemporaryFailureShouldNotIncrementDeliveryMetric() throws Exception {
+ FakeMail fakeMail = FakeMail.builder().state(Mail.DEFAULT).build();
+ Exception exception = new Exception();
+ when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception));
+
+ testee.attemptDelivery(fakeMail);
+
+ verifyNoMoreInteractions(outgoingMailsMetric);
+ }
+
+ @Test
+ public void deliveryTemporaryFailureShouldFailOnMailsWithoutState() throws Exception {
+ FakeMail fakeMail = FakeMail.defaultFakeMail();
+ Exception exception = new Exception();
+ when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception));
+
+ expectedException.expect(NullPointerException.class);
+
+ testee.attemptDelivery(fakeMail);
+ }
+
+ @Test
+ public void deliveryTemporaryFailureShouldRetryDelivery() throws Exception {
+ FakeMail fakeMail = FakeMail.builder().state(Mail.DEFAULT).build();
+ Exception exception = new Exception();
+ when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception));
+
+ testee.attemptDelivery(fakeMail);
+
+ verify(mailQueue).enQueue(FakeMail.builder()
+ .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 1)
+ .state(Mail.ERROR)
+ .lastUpdated(FIXED_DATE)
+ .build(),
+ 1000,
+ TimeUnit.MILLISECONDS);
+ verifyNoMoreInteractions(mailQueue);
+ }
+
+ @Test
+ public void deliveryTemporaryFailureShouldRetryDeliveryWithRightDelay() throws Exception {
+ FakeMail fakeMail = FakeMail.builder()
+ .state(Mail.ERROR)
+ .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 2)
+ .build();
+ Exception exception = new Exception();
+ when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception));
+
+ testee.attemptDelivery(fakeMail);
+
+ verify(mailQueue).enQueue(FakeMail.builder()
+ .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 3)
+ .state(Mail.ERROR)
+ .lastUpdated(FIXED_DATE)
+ .build(),
+ 3000,
+ TimeUnit.MILLISECONDS);
+ verifyNoMoreInteractions(mailQueue);
+ }
+
+ @Test
+ public void deliveryTemporaryFailureShouldRetryDeliveryOnMaximumRetryNumber() throws Exception {
+ FakeMail fakeMail = FakeMail.builder()
+ .state(Mail.ERROR)
+ .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 4)
+ .build();
+ Exception exception = new Exception();
+ when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception));
+
+ testee.attemptDelivery(fakeMail);
+
+ verify(mailQueue).enQueue(FakeMail.builder()
+ .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 5)
+ .state(Mail.ERROR)
+ .lastUpdated(FIXED_DATE)
+ .build(),
+ 5000,
+ TimeUnit.MILLISECONDS);
+ verifyNoMoreInteractions(mailQueue);
+ }
+
+ @Test
+ public void deliveryTemporaryFailureShouldNotRetryDeliveryOverMaximumRetryNumber() throws Exception {
+ FakeMail fakeMail = FakeMail.builder()
+ .state(Mail.ERROR)
+ .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 5)
+ .build();
+ Exception exception = new Exception();
+ when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception));
+
+ testee.attemptDelivery(fakeMail);
+
+ verifyNoMoreInteractions(mailQueue);
+ }
+
+ @Test
+ public void deliveryTemporaryFailureShouldBounceWhenRetryExceeded() throws Exception {
+ FakeMail fakeMail = FakeMail.builder()
+ .state(Mail.ERROR)
+ .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 5)
+ .build();
+ Exception exception = new Exception("");
+ when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception));
+
+ testee.attemptDelivery(fakeMail);
+
+ verify(bouncer).bounce(eq(fakeMail), any(Exception.class));
+ verifyNoMoreInteractions(bouncer);
+ }
+
+ @Test
+ public void deliveryTemporaryFailureShouldResetDeliveryCountOnNonErrorState() throws Exception {
+ FakeMail fakeMail = FakeMail.builder()
+ .state(Mail.DEFAULT)
+ .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 5)
+ .build();
+ Exception exception = new Exception();
+ when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception));
+
+ testee.attemptDelivery(fakeMail);
+
+ verify(mailQueue).enQueue(FakeMail.builder()
+ .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 1)
+ .state(Mail.ERROR)
+ .lastUpdated(FIXED_DATE)
+ .build(),
+ 1000,
+ TimeUnit.MILLISECONDS);
+ verifyNoMoreInteractions(mailQueue);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[29/50] [abbrv] james-project git commit: JAMES-1877 Extract delivery
to single server to MailDelivrer
Posted by ro...@apache.org.
JAMES-1877 Extract delivery to single server to MailDelivrer
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/f567a5a5
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/f567a5a5
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/f567a5a5
Branch: refs/heads/master
Commit: f567a5a5606aceb53b4bf02beb9384f0d62b31a7
Parents: a0ca1bf
Author: Benoit Tellier <bt...@linagora.com>
Authored: Fri Dec 2 10:20:51 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:51 2017 +0700
----------------------------------------------------------------------
.../remoteDelivery/DeliveryRunnable.java | 126 ++--------------
.../remoteDelivery/MailDelivrerToHost.java | 142 +++++++++++++++++++
2 files changed, 155 insertions(+), 113 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/f567a5a5/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index d62f6f6..37ae531 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -20,20 +20,16 @@
package org.apache.james.transport.mailets.remoteDelivery;
import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
-import java.util.Properties;
import java.util.concurrent.TimeUnit;
import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.SendFailedException;
-import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.ParseException;
@@ -51,24 +47,21 @@ import org.apache.mailet.MailAddress;
import org.apache.mailet.MailetContext;
import org.slf4j.Logger;
-import com.google.common.base.Optional;
-import com.sun.mail.smtp.SMTPTransport;
-
@SuppressWarnings("deprecation")
public class DeliveryRunnable implements Runnable {
- public static final String BIT_MIME_8 = "8BITMIME";
private final MailQueue queue;
private final RemoteDeliveryConfiguration configuration;
private final DNSService dnsServer;
private final Metric outgoingMailsMetric;
private final Logger logger;
private final Bouncer bouncer;
+ private final MailDelivrerToHost mailDelivrerToHost;
private final VolatileIsDestroyed volatileIsDestroyed;
private final MessageComposer messageComposer;
- private final Converter7Bit converter7Bit;
- public DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, DNSService dnsServer, Metric outgoingMailsMetric, Logger logger, MailetContext mailetContext, VolatileIsDestroyed volatileIsDestroyed) {
+ public DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, DNSService dnsServer, Metric outgoingMailsMetric,
+ Logger logger, MailetContext mailetContext, VolatileIsDestroyed volatileIsDestroyed) {
this.queue = queue;
this.configuration = configuration;
this.dnsServer = dnsServer;
@@ -76,8 +69,8 @@ public class DeliveryRunnable implements Runnable {
this.logger = logger;
this.volatileIsDestroyed = volatileIsDestroyed;
this.messageComposer = new MessageComposer(configuration);
- this.converter7Bit = new Converter7Bit(mailetContext);
this.bouncer = new Bouncer(configuration, messageComposer, mailetContext, logger);
+ this.mailDelivrerToHost = new MailDelivrerToHost(configuration, mailetContext, logger);
}
/**
@@ -86,7 +79,6 @@ public class DeliveryRunnable implements Runnable {
*/
@Override
public void run() {
- final Session session = obtainSession(configuration.createFinalJavaxProperties());
try {
while (!Thread.interrupted() && !volatileIsDestroyed.isDestroyed()) {
try {
@@ -100,7 +92,7 @@ public class DeliveryRunnable implements Runnable {
if (configuration.isDebug()) {
logger.debug(Thread.currentThread().getName() + " will process mail " + mail.getName());
}
- attemptDelivery(session, mail);
+ attemptDelivery(mail);
LifecycleUtil.dispose(mail);
mail = null;
queueItem.done(true);
@@ -126,8 +118,8 @@ public class DeliveryRunnable implements Runnable {
}
}
- private void attemptDelivery(Session session, Mail mail) throws MailQueue.MailQueueException {
- ExecutionResult executionResult = deliver(mail, session);
+ private void attemptDelivery(Mail mail) throws MailQueue.MailQueueException {
+ ExecutionResult executionResult = deliver(mail);
switch (executionResult.getExecutionState()) {
case SUCCESS:
outgoingMailsMetric.increment();
@@ -182,9 +174,9 @@ public class DeliveryRunnable implements Runnable {
* @return boolean Whether the delivery was successful and the message can
* be deleted
*/
- private ExecutionResult deliver(Mail mail, Session session) {
+ private ExecutionResult deliver(Mail mail) {
try {
- return tryDeliver(mail, session);
+ return tryDeliver(mail);
} catch (SendFailedException sfe) {
return handleSenderFailedException(mail, sfe);
} catch (MessagingException ex) {
@@ -210,7 +202,7 @@ public class DeliveryRunnable implements Runnable {
}
}
- private ExecutionResult tryDeliver(Mail mail, Session session) throws MessagingException {
+ private ExecutionResult tryDeliver(Mail mail) throws MessagingException {
if (mail.getRecipients().isEmpty()) {
logger.info("No recipients specified... not sure how this could have happened.");
return ExecutionResult.permanentFailure(new Exception("No recipients specified for " + mail.getName() + " sent by " + mail.getSender()));
@@ -239,15 +231,15 @@ public class DeliveryRunnable implements Runnable {
targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer());
}
- return doDeliver(mail, session, mail.getMessage(), convertToInetAddr(mail.getRecipients()), targetServers);
+ return doDeliver(mail, mail.getMessage(), convertToInetAddr(mail.getRecipients()), targetServers);
}
- private ExecutionResult doDeliver(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException {
+ private ExecutionResult doDeliver(Mail mail, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException {
MessagingException lastError = null;
while (targetServers.hasNext()) {
try {
- if (tryDeliveryToHost(mail, session, message, addr, targetServers.next())) {
+ if (mailDelivrerToHost.tryDeliveryToHost(mail, message, addr, targetServers.next())) {
return ExecutionResult.success();
}
} catch (SendFailedException sfe) {
@@ -273,39 +265,6 @@ public class DeliveryRunnable implements Runnable {
return ExecutionResult.temporaryFailure();
}
- private boolean tryDeliveryToHost(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException {
- Properties props = session.getProperties();
- if (mail.getSender() == null) {
- props.put("mail.smtp.from", "<>");
- } else {
- String sender = mail.getSender().toString();
- props.put("mail.smtp.from", sender);
- }
- logger.debug("Attempting delivery of " + mail.getName() + " to host " + outgoingMailServer.getHostName()
- + " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from"));
-
- // Many of these properties are only in later JavaMail versions
- // "mail.smtp.ehlo" //default true
- // "mail.smtp.auth" //default false
- // "mail.smtp.dsn.ret" //default to nothing... appended as
- // RET= after MAIL FROM line.
- // "mail.smtp.dsn.notify" //default to nothing...appended as
- // NOTIFY= after RCPT TO line.
-
- SMTPTransport transport = null;
- try {
- transport = (SMTPTransport) session.getTransport(outgoingMailServer);
- transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
- connect(outgoingMailServer, transport);
- transport.sendMessage(adaptToTransport(message, transport), addr);
- logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() +
- " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients());
- return true;
- } finally {
- closeTransport(mail, outgoingMailServer, transport);
- }
- }
-
private MessagingException handleMessagingException(Mail mail, MessagingException me) throws MessagingException {
MessagingException lastError;// MessagingException are horribly difficult to figure out what actually happened.
logger.debug("Exception delivering message (" + mail.getName() + ") - " + me.getMessage());
@@ -468,61 +427,6 @@ public class DeliveryRunnable implements Runnable {
return addr;
}
- private MimeMessage adaptToTransport(MimeMessage message, SMTPTransport transport) throws MessagingException {
- // if the transport is a SMTPTransport (from sun) some
- // performance enhancement can be done.
- if (transport.getClass().getName().endsWith(".SMTPTransport")) {
- // if the message is alredy 8bit or binary and the server doesn't support the 8bit extension it has
- // to be converted to 7bit. Javamail api doesn't perform
- // that conversion, but it is required to be a rfc-compliant smtp server.
-
- // Temporarily disabled. See JAMES-638
- if (!transport.supportsExtension(BIT_MIME_8)) {
- try {
- converter7Bit.convertTo7Bit(message);
- } catch (IOException e) {
- // An error has occured during the 7bit conversion.
- // The error is logged and the message is sent anyway.
-
- logger.error("Error during the conversion to 7 bit.", e);
- }
- }
- } else {
- // If the transport is not the one developed by Sun we are not sure of how it
- // handles the 8 bit mime stuff, so I convert the message to 7bit.
- try {
- converter7Bit.convertTo7Bit(message);
- } catch (IOException e) {
- logger.error("Error during the conversion to 7 bit.", e);
- }
- }
- return message;
- }
-
- private void closeTransport(Mail mail, HostAddress outgoingMailServer, SMTPTransport transport) {
- if (transport != null) {
- try {
- // James-899: transport.close() sends QUIT to the server; if that fails
- // (e.g. because the server has already closed the connection) the message
- // should be considered to be delivered because the error happened outside
- // of the mail transaction (MAIL, RCPT, DATA).
- transport.close();
- } catch (MessagingException e) {
- logger.error("Warning: could not close the SMTP transport after sending mail (" + mail.getName() + ") to " + outgoingMailServer.getHostName() + " at " + outgoingMailServer.getHost() + " for " + mail.getRecipients() + "; probably the server has already closed the "
- + "connection. Message is considered to be delivered. Exception: " + e.getMessage());
- }
- transport = null;
- }
- }
-
- private void connect(HostAddress outgoingMailServer, SMTPTransport transport) throws MessagingException {
- if (configuration.getAuthUser() != null) {
- transport.connect(outgoingMailServer.getHostName(), configuration.getAuthUser(), configuration.getAuthPass());
- } else {
- transport.connect();
- }
- }
-
private ExecutionResult handleTemporaryResolutionException(Mail mail, String host) {
ExecutionResult executionResult = ExecutionResult.temporaryFailure(new MessagingException("Temporary problem looking " +
"up mail server for host: " + host + ". I cannot determine where to send this message."));
@@ -548,10 +452,6 @@ public class DeliveryRunnable implements Runnable {
}
}
- protected Session obtainSession(Properties props) {
- return Session.getInstance(props);
- }
-
private long getNextDelay(int retry_count) {
if (retry_count > configuration.getDelayTimes().size()) {
return Delay.DEFAULT_DELAY_TIME;
http://git-wip-us.apache.org/repos/asf/james-project/blob/f567a5a5/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java
new file mode 100644
index 0000000..46bd8f9
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java
@@ -0,0 +1,142 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.io.IOException;
+import java.util.Properties;
+
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.mailet.HostAddress;
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailetContext;
+import org.slf4j.Logger;
+
+import com.sun.mail.smtp.SMTPTransport;
+
+@SuppressWarnings("deprecation")
+public class MailDelivrerToHost {
+ public static final String BIT_MIME_8 = "8BITMIME";
+
+ private final RemoteDeliveryConfiguration configuration;
+ private final Converter7Bit converter7Bit;
+ private final Session session;
+ private final Logger logger;
+
+ public MailDelivrerToHost(RemoteDeliveryConfiguration remoteDeliveryConfiguration, MailetContext mailetContext, Logger logger) {
+ this.configuration = remoteDeliveryConfiguration;
+ this.converter7Bit = new Converter7Bit(mailetContext);
+ this.session = Session.getInstance(configuration.createFinalJavaxProperties());
+ this.logger = logger;
+ }
+
+ public boolean tryDeliveryToHost(Mail mail, MimeMessage message, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException {
+ Properties props = session.getProperties();
+ if (mail.getSender() == null) {
+ props.put("mail.smtp.from", "<>");
+ } else {
+ String sender = mail.getSender().toString();
+ props.put("mail.smtp.from", sender);
+ }
+ logger.debug("Attempting delivery of " + mail.getName() + " to host " + outgoingMailServer.getHostName()
+ + " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from"));
+
+ // Many of these properties are only in later JavaMail versions
+ // "mail.smtp.ehlo" //default true
+ // "mail.smtp.auth" //default false
+ // "mail.smtp.dsn.ret" //default to nothing... appended as
+ // RET= after MAIL FROM line.
+ // "mail.smtp.dsn.notify" //default to nothing...appended as
+ // NOTIFY= after RCPT TO line.
+
+ SMTPTransport transport = null;
+ try {
+ transport = (SMTPTransport) session.getTransport(outgoingMailServer);
+ transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
+ connect(outgoingMailServer, transport);
+ transport.sendMessage(adaptToTransport(message, transport), addr);
+ logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() +
+ " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients());
+ return true;
+ } finally {
+ closeTransport(mail, outgoingMailServer, transport);
+ }
+ }
+
+ private void connect(HostAddress outgoingMailServer, SMTPTransport transport) throws MessagingException {
+ if (configuration.getAuthUser() != null) {
+ transport.connect(outgoingMailServer.getHostName(), configuration.getAuthUser(), configuration.getAuthPass());
+ } else {
+ transport.connect();
+ }
+ }
+
+ private MimeMessage adaptToTransport(MimeMessage message, SMTPTransport transport) throws MessagingException {
+ // if the transport is a SMTPTransport (from sun) some
+ // performance enhancement can be done.
+ if (transport.getClass().getName().endsWith(".SMTPTransport")) {
+ // if the message is alredy 8bit or binary and the server doesn't support the 8bit extension it has
+ // to be converted to 7bit. Javamail api doesn't perform
+ // that conversion, but it is required to be a rfc-compliant smtp server.
+
+ // Temporarily disabled. See JAMES-638
+ if (!transport.supportsExtension(BIT_MIME_8)) {
+ try {
+ converter7Bit.convertTo7Bit(message);
+ } catch (IOException e) {
+ // An error has occured during the 7bit conversion.
+ // The error is logged and the message is sent anyway.
+
+ logger.error("Error during the conversion to 7 bit.", e);
+ }
+ }
+ } else {
+ // If the transport is not the one developed by Sun we are not sure of how it
+ // handles the 8 bit mime stuff, so I convert the message to 7bit.
+ try {
+ converter7Bit.convertTo7Bit(message);
+ } catch (IOException e) {
+ logger.error("Error during the conversion to 7 bit.", e);
+ }
+ }
+ return message;
+ }
+
+ private void closeTransport(Mail mail, HostAddress outgoingMailServer, SMTPTransport transport) {
+ if (transport != null) {
+ try {
+ // James-899: transport.close() sends QUIT to the server; if that fails
+ // (e.g. because the server has already closed the connection) the message
+ // should be considered to be delivered because the error happened outside
+ // of the mail transaction (MAIL, RCPT, DATA).
+ transport.close();
+ } catch (MessagingException e) {
+ logger.error("Warning: could not close the SMTP transport after sending mail (" + mail.getName() + ") to " + outgoingMailServer.getHostName() + " at " + outgoingMailServer.getHost() + " for " + mail.getRecipients() + "; probably the server has already closed the "
+ + "connection. Message is considered to be delivered. Exception: " + e.getMessage());
+ }
+ transport = null;
+ }
+ }
+
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[47/50] [abbrv] james-project git commit: JAMES-1877 Provide tests
for SFEHelperTest
Posted by ro...@apache.org.
JAMES-1877 Provide tests for SFEHelperTest
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/d584c13e
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/d584c13e
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/d584c13e
Branch: refs/heads/master
Commit: d584c13e5fbe8e5f554a352593f85ddba0d2f6ec
Parents: 4221b35
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 8 15:20:17 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 18:14:32 2017 +0700
----------------------------------------------------------------------
...ddressesArrayToMailAddressListConverter.java | 66 ++++++++++++++++++++
.../mailets/remoteDelivery/MailDelivrer.java | 4 +-
.../mailets/remoteDelivery/SFEHelper.java | 66 --------------------
...ssesArrayToMailAddressListConverterTest.java | 59 +++++++++++++++++
4 files changed, 127 insertions(+), 68 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/d584c13e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverter.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverter.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverter.java
new file mode 100644
index 0000000..d468947
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverter.java
@@ -0,0 +1,66 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.mail.Address;
+import javax.mail.internet.AddressException;
+
+import org.apache.mailet.MailAddress;
+import org.slf4j.Logger;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+
+public class AddressesArrayToMailAddressListConverter {
+
+ public static List<MailAddress> getAddressesAsMailAddress(Address[] addresses, final Logger logger) {
+ if (addresses == null) {
+ return ImmutableList.of();
+ }
+ return FluentIterable.from(Arrays.asList(addresses)).transform(new Function<Address, Optional<MailAddress>>() {
+ @Override
+ public Optional<MailAddress> apply(Address input) {
+ try {
+ return Optional.of(new MailAddress(input.toString()));
+ } catch (AddressException e) {
+ logger.debug("Can't parse unsent address: " + e.getMessage());
+ return Optional.absent();
+ }
+ }
+ }).filter(new Predicate<Optional<MailAddress>>() {
+ @Override
+ public boolean apply(Optional<MailAddress> input) {
+ return input.isPresent();
+ }
+ }).transform(new Function<Optional<MailAddress>, MailAddress>() {
+ @Override
+ public MailAddress apply(Optional<MailAddress> input) {
+ return input.get();
+ }
+ }).toList();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/d584c13e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
index 1036734..df38243 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
@@ -168,8 +168,8 @@ public class MailDelivrer {
ExecutionResult handleSenderFailedException(Mail mail, SendFailedException sfe) {
logSendFailedException(sfe);
EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
- List<MailAddress> invalidAddresses = SFEHelper.getAddressesAsMailAddress(sfe.getInvalidAddresses(), logger);
- List<MailAddress> validUnsentAddresses = SFEHelper.getAddressesAsMailAddress(sfe.getValidUnsentAddresses(), logger);
+ List<MailAddress> invalidAddresses = AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(sfe.getInvalidAddresses(), logger);
+ List<MailAddress> validUnsentAddresses = AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(sfe.getValidUnsentAddresses(), logger);
if (configuration.isDebug()) {
logger.debug("Mail {} has initially recipients: {}", mail.getName(), mail.getRecipients());
if (!invalidAddresses.isEmpty()) {
http://git-wip-us.apache.org/repos/asf/james-project/blob/d584c13e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/SFEHelper.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/SFEHelper.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/SFEHelper.java
deleted file mode 100644
index a9650d3..0000000
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/SFEHelper.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you under the Apache License, Version 2.0 (the *
- * "License"); you may not use this file except in compliance *
- * with the License. You may obtain a copy of the License at *
- * *
- * http://www.apache.org/licenses/LICENSE-2.0 *
- * *
- * Unless required by applicable law or agreed to in writing, *
- * software distributed under the License is distributed on an *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
- * KIND, either express or implied. See the License for the *
- * specific language governing permissions and limitations *
- * under the License. *
- ****************************************************************/
-
-package org.apache.james.transport.mailets.remoteDelivery;
-
-import java.util.Arrays;
-import java.util.List;
-
-import javax.mail.Address;
-import javax.mail.internet.AddressException;
-
-import org.apache.mailet.MailAddress;
-import org.slf4j.Logger;
-
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
-
-public class SFEHelper {
-
- public static List<MailAddress> getAddressesAsMailAddress(Address[] addresses, final Logger logger) {
- if (addresses == null) {
- return ImmutableList.of();
- }
- return FluentIterable.from(Arrays.asList(addresses)).transform(new Function<Address, Optional<MailAddress>>() {
- @Override
- public Optional<MailAddress> apply(Address input) {
- try {
- return Optional.of(new MailAddress(input.toString()));
- } catch (AddressException e) {
- logger.debug("Can't parse unsent address: " + e.getMessage());
- return Optional.absent();
- }
- }
- }).filter(new Predicate<Optional<MailAddress>>() {
- @Override
- public boolean apply(Optional<MailAddress> input) {
- return input.isPresent();
- }
- }).transform(new Function<Optional<MailAddress>, MailAddress>() {
- @Override
- public MailAddress apply(Optional<MailAddress> input) {
- return input.get();
- }
- }).toList();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/james-project/blob/d584c13e/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverterTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverterTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverterTest.java
new file mode 100644
index 0000000..dd05c7c
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverterTest.java
@@ -0,0 +1,59 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import javax.mail.Address;
+import javax.mail.internet.InternetAddress;
+
+import org.apache.mailet.base.MailAddressFixture;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AddressesArrayToMailAddressListConverterTest {
+ private static final Logger LOGGER = LoggerFactory.getLogger(AddressesArrayToMailAddressListConverterTest.class);
+
+ @Test
+ public void getAddressesAsMailAddressShouldReturnEmptyOnNull() {
+ assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(null, LOGGER)).isEmpty();
+ }
+
+ @Test
+ public void getAddressesAsMailAddressShouldReturnEmptyOnEmpty() {
+ assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(new Address[]{}, LOGGER)).isEmpty();
+ }
+
+ @Test
+ public void getAddressesAsMailAddressShouldWorkWithSingleValue() throws Exception {
+ assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(new Address[]{
+ new InternetAddress(MailAddressFixture.ANY_AT_JAMES.toString())}, LOGGER))
+ .containsOnly(MailAddressFixture.ANY_AT_JAMES);
+ }
+
+ @Test
+ public void getAddressesAsMailAddressShouldWorkWithTwoValues() throws Exception {
+ assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(new Address[]{
+ new InternetAddress(MailAddressFixture.ANY_AT_JAMES.toString()),
+ new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.toString())}, LOGGER))
+ .containsOnly(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[08/50] [abbrv] james-project git commit: JAMES-1877 Extract
DeliveryRunnable from RemoteDelivery
Posted by ro...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/4a5a4ba6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
new file mode 100644
index 0000000..5a0bdf1
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -0,0 +1,963 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.ConnectException;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import javax.mail.Address;
+import javax.mail.MessagingException;
+import javax.mail.SendFailedException;
+import javax.mail.Session;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+import javax.mail.internet.MimePart;
+import javax.mail.internet.ParseException;
+
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.TemporaryResolutionException;
+import org.apache.james.dnsservice.library.MXHostAddressIterator;
+import org.apache.james.lifecycle.api.LifecycleUtil;
+import org.apache.james.metrics.api.Metric;
+import org.apache.james.queue.api.MailPrioritySupport;
+import org.apache.james.queue.api.MailQueue;
+import org.apache.mailet.HostAddress;
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+import org.apache.mailet.MailetContext;
+import org.slf4j.Logger;
+
+import com.sun.mail.smtp.SMTPTransport;
+
+@SuppressWarnings("deprecation")
+public class DeliveryRunnable implements Runnable {
+
+ private final MailQueue queue;
+ private final RemoteDeliveryConfiguration configuration;
+ private final DNSService dnsServer;
+ private final Metric outgoingMailsMetric;
+ private final Logger logger;
+ private final MailetContext mailetContext;
+ private final VolatileIsDestroyed volatileIsDestroyed;
+
+ public DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, DNSService dnsServer, Metric outgoingMailsMetric, Logger logger, MailetContext mailetContext, VolatileIsDestroyed volatileIsDestroyed) {
+ this.queue = queue;
+ this.configuration = configuration;
+ this.dnsServer = dnsServer;
+ this.outgoingMailsMetric = outgoingMailsMetric;
+ this.logger = logger;
+ this.mailetContext = mailetContext;
+ this.volatileIsDestroyed = volatileIsDestroyed;
+ }
+
+ /**
+ * Handles checking the outgoing spool for new mail and delivering them if
+ * there are any
+ */
+ @Override
+ public void run() {
+ final Session session = obtainSession(configuration.createFinalJavaxProperties());
+ try {
+ while (!Thread.interrupted() && !volatileIsDestroyed.isDestroyed()) {
+ try {
+ // Get the 'mail' object that is ready for deliverying. If
+ // no
+ // message is
+ // ready, the 'accept' will block until message is ready.
+ // The amount
+ // of time to block is determined by the 'getWaitTime'
+ // method of the
+ // MultipleDelayFilter.
+ MailQueue.MailQueueItem queueItem = queue.deQueue();
+ Mail mail = queueItem.getMail();
+
+ String key = mail.getName();
+
+ try {
+ if (configuration.isDebug()) {
+ String message = Thread.currentThread().getName() + " will process mail " + key;
+ logger.debug(message);
+ }
+
+ // Deliver message
+ if (deliver(mail, session)) {
+ // Message was successfully delivered/fully
+ // failed...
+ // delete it
+ LifecycleUtil.dispose(mail);
+ // workRepository.remove(key);
+ } else {
+ // Something happened that will delay delivery.
+ // Store it back in the retry repository.
+ // workRepository.store(mail);
+ int retries = 0;
+ try {
+ retries = Integer.parseInt(mail.getErrorMessage());
+ } catch (NumberFormatException e) {
+ // Something strange was happen with the
+ // errorMessage..
+ }
+
+ long delay = getNextDelay(retries);
+
+ if (configuration.isUsePriority()) {
+ // Use lowest priority for retries. See JAMES-1311
+ mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY);
+ }
+ queue.enQueue(mail, delay, TimeUnit.MILLISECONDS);
+ LifecycleUtil.dispose(mail);
+
+ // This is an update, so we have to unlock and
+ // notify or this mail is kept locked by this
+ // thread.
+ // workRepository.unlock(key);
+
+ // Note: We do not notify because we updated an
+ // already existing mail and we are now free to
+ // handle
+ // more mails.
+ // Furthermore this mail should not be processed now
+ // because we have a retry time scheduling.
+ }
+
+ // Clear the object handle to make sure it recycles
+ // this object.
+ mail = null;
+ queueItem.done(true);
+ } catch (Exception e) {
+ // Prevent unexpected exceptions from causing looping by
+ // removing message from outgoing.
+ // DO NOT CHANGE THIS to catch Error! For example, if
+ // there were an OutOfMemory condition caused because
+ // something else in the server was abusing memory, we
+ // would
+ // not want to start purging the retrying spool!
+ logger.error("Exception caught in RemoteDelivery.run()", e);
+ LifecycleUtil.dispose(mail);
+ // workRepository.remove(key);
+ queueItem.done(false);
+ throw new MailQueue.MailQueueException("Unable to perform dequeue", e);
+ }
+
+ } catch (Throwable e) {
+ if (!volatileIsDestroyed.isDestroyed()) {
+ logger.error("Exception caught in RemoteDelivery.run()", e);
+ }
+ }
+ }
+ } finally {
+ // Restore the thread state to non-interrupted.
+ Thread.interrupted();
+ }
+ }
+
+
+ /**
+ * We can assume that the recipients of this message are all going to the
+ * same mail server. We will now rely on the DNS server to do DNS MX record
+ * lookup and try to deliver to the multiple mail servers. If it fails, it
+ * should throw an exception.
+ *
+ * @param mail org.apache.james.core.MailImpl
+ * @param session javax.mail.Session
+ * @return boolean Whether the delivery was successful and the message can
+ * be deleted
+ */
+ private boolean deliver(Mail mail, Session session) {
+ try {
+ if (configuration.isDebug()) {
+ logger.debug("Attempting to deliver " + mail.getName());
+ }
+ MimeMessage message = mail.getMessage();
+
+ // Create an array of the recipients as InternetAddress objects
+ Collection<MailAddress> recipients = mail.getRecipients();
+ InternetAddress addr[] = new InternetAddress[recipients.size()];
+ int j = 0;
+ for (Iterator<MailAddress> i = recipients.iterator(); i.hasNext(); j++) {
+ MailAddress rcpt = i.next();
+ addr[j] = rcpt.toInternetAddress();
+ }
+
+ if (addr.length <= 0) {
+ logger.info("No recipients specified... not sure how this could have happened.");
+ return true;
+ }
+
+ // Figure out which servers to try to send to. This collection
+ // will hold all the possible target servers
+ Iterator<HostAddress> targetServers;
+ if (configuration.getGatewayServer().isEmpty()) {
+ MailAddress rcpt = recipients.iterator().next();
+ String host = rcpt.getDomain();
+
+ // Lookup the possible targets
+ try {
+ targetServers = new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logger);
+ } catch (TemporaryResolutionException e) {
+ logger.info("Temporary problem looking up mail server for host: " + host);
+ String exceptionBuffer = "Temporary problem looking up mail server for host: " + host + ". I cannot determine where to send this message.";
+
+ // temporary problems
+ return failMessage(mail, new MessagingException(exceptionBuffer), false);
+ }
+ if (!targetServers.hasNext()) {
+ logger.info("No mail server found for: " + host);
+ String exceptionBuffer = "There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.";
+
+ int retry = 0;
+ try {
+ retry = Integer.parseInt(mail.getErrorMessage());
+ } catch (NumberFormatException e) {
+ // Unable to parse retryCount
+ }
+ if (retry == 0 || retry > configuration.getDnsProblemRetry()) {
+ // The domain has no dns entry.. Return a permanent
+ // error
+ return failMessage(mail, new MessagingException(exceptionBuffer), true);
+ } else {
+ return failMessage(mail, new MessagingException(exceptionBuffer), false);
+ }
+ }
+ } else {
+ targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer());
+ }
+
+ MessagingException lastError = null;
+
+ while (targetServers.hasNext()) {
+ try {
+
+ Properties props = session.getProperties();
+ if (mail.getSender() == null) {
+ props.put("mail.smtp.from", "<>");
+ } else {
+ String sender = mail.getSender().toString();
+ props.put("mail.smtp.from", sender);
+ }
+
+ HostAddress outgoingMailServer = targetServers.next();
+ StringBuilder logMessageBuffer = new StringBuilder(256).append("Attempting delivery of ").append(mail.getName()).append(" to host ").append(outgoingMailServer.getHostName()).append(" at ").append(outgoingMailServer.getHost()).append(" from ").append(props.get("mail.smtp.from"))
+ .append(" for addresses ").append(Arrays.asList(addr));
+ logger.debug(logMessageBuffer.toString());
+
+ // Many of these properties are only in later JavaMail
+ // versions
+ // "mail.smtp.ehlo" //default true
+ // "mail.smtp.auth" //default false
+ // "mail.smtp.dsn.ret" //default to nothing... appended as
+ // RET= after MAIL FROM line.
+ // "mail.smtp.dsn.notify" //default to nothing...appended as
+ // NOTIFY= after RCPT TO line.
+
+ SMTPTransport transport = null;
+ try {
+ transport = (SMTPTransport) session.getTransport(outgoingMailServer);
+ transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
+ try {
+ if (configuration.getAuthUser() != null) {
+ transport.connect(outgoingMailServer.getHostName(), configuration.getAuthUser(), configuration.getAuthPass());
+ } else {
+ transport.connect();
+ }
+ } catch (MessagingException me) {
+ // Any error on connect should cause the mailet to
+ // attempt
+ // to connect to the next SMTP server associated
+ // with this
+ // MX record. Just log the exception. We'll worry
+ // about
+ // failing the message at the end of the loop.
+
+ // Also include the stacktrace if debug is enabled. See JAMES-1257
+ if (configuration.isDebug()) {
+ logger.debug(me.getMessage(), me.getCause());
+ } else {
+ logger.info(me.getMessage());
+ }
+ continue;
+ }
+ // if the transport is a SMTPTransport (from sun) some
+ // performance enhancement can be done.
+ if (transport.getClass().getName().endsWith(".SMTPTransport")) {
+ boolean supports8bitmime = false;
+ try {
+ Method supportsExtension = transport.getClass().getMethod("supportsExtension", new Class[]{String.class});
+ supports8bitmime = (Boolean) supportsExtension.invoke(transport, "8BITMIME");
+ } catch (NoSuchMethodException nsme) {
+ // An SMTPAddressFailedException with no
+ // getAddress method.
+ } catch (IllegalAccessException iae) {
+ } catch (IllegalArgumentException iae) {
+ } catch (InvocationTargetException ite) {
+ // Other issues with getAddress invokation.
+ }
+
+ // if the message is alredy 8bit or binary and the
+ // server doesn't support the 8bit extension it has
+ // to be converted to 7bit. Javamail api doesn't
+ // perform
+ // that conversion, but it is required to be a
+ // rfc-compliant smtp server.
+
+ // Temporarily disabled. See JAMES-638
+ if (!supports8bitmime) {
+ try {
+ convertTo7Bit(message);
+ } catch (IOException e) {
+ // An error has occured during the 7bit
+ // conversion.
+ // The error is logged and the message is
+ // sent anyway.
+
+ logger.error("Error during the conversion to 7 bit.", e);
+ }
+ }
+ } else {
+ // If the transport is not the one
+ // developed by Sun we are not sure of how it
+ // handles the 8 bit mime stuff,
+ // so I convert the message to 7bit.
+ try {
+ convertTo7Bit(message);
+ } catch (IOException e) {
+ logger.error("Error during the conversion to 7 bit.", e);
+ }
+ }
+ transport.sendMessage(message, addr);
+ } finally {
+ if (transport != null) {
+ try {
+ // James-899: transport.close() sends QUIT to
+ // the server; if that fails
+ // (e.g. because the server has already closed
+ // the connection) the message
+ // should be considered to be delivered because
+ // the error happened outside
+ // of the mail transaction (MAIL, RCPT, DATA).
+ transport.close();
+ } catch (MessagingException e) {
+ logger.error("Warning: could not close the SMTP transport after sending mail (" + mail.getName() + ") to " + outgoingMailServer.getHostName() + " at " + outgoingMailServer.getHost() + " for " + mail.getRecipients() + "; probably the server has already closed the "
+ + "connection. Message is considered to be delivered. Exception: " + e.getMessage());
+ }
+ transport = null;
+ }
+ }
+ logMessageBuffer = new StringBuilder(256).append("Mail (").append(mail.getName()).append(") sent successfully to ").append(outgoingMailServer.getHostName()).append(" at ").append(outgoingMailServer.getHost()).append(" from ").append(props.get("mail.smtp.from")).append(" for ")
+ .append(mail.getRecipients());
+ logger.debug(logMessageBuffer.toString());
+ outgoingMailsMetric.increment();
+ return true;
+ } catch (SendFailedException sfe) {
+ logSendFailedException(sfe);
+
+ if (sfe.getValidSentAddresses() != null) {
+ Address[] validSent = sfe.getValidSentAddresses();
+ if (validSent.length > 0) {
+ String logMessageBuffer = "Mail (" + mail.getName() + ") sent successfully for " + Arrays.asList(validSent);
+ logger.debug(logMessageBuffer);
+ }
+ }
+
+ /*
+ * SMTPSendFailedException introduced in JavaMail 1.3.2, and
+ * provides detailed protocol reply code for the operation
+ */
+ if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
+ try {
+ int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
+ // if 5xx, terminate this delivery attempt by
+ // re-throwing the exception.
+ if (returnCode >= 500 && returnCode <= 599)
+ throw sfe;
+ } catch (ClassCastException cce) {
+ } catch (IllegalArgumentException iae) {
+ }
+ }
+
+ if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) {
+ if (configuration.isDebug())
+ logger.debug("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers");
+ lastError = sfe;
+ } else {
+ // There are no valid addresses left to send, so rethrow
+ throw sfe;
+ }
+ } catch (MessagingException me) {
+ // MessagingException are horribly difficult to figure out
+ // what actually happened.
+ String exceptionBuffer = "Exception delivering message (" + mail.getName() + ") - " + me.getMessage();
+ logger.debug(exceptionBuffer);
+ if ((me.getNextException() != null) && (me.getNextException() instanceof java.io.IOException)) {
+ // This is more than likely a temporary failure
+
+ // If it's an IO exception with no nested exception,
+ // it's probably
+ // some socket or weird I/O related problem.
+ lastError = me;
+ continue;
+ }
+ // This was not a connection or I/O error particular to one
+ // SMTP server of an MX set. Instead, it is almost certainly
+ // a protocol level error. In this case we assume that this
+ // is an error we'd encounter with any of the SMTP servers
+ // associated with this MX record, and we pass the exception
+ // to the code in the outer block that determines its
+ // severity.
+ throw me;
+ }
+ } // end while
+ // If we encountered an exception while looping through,
+ // throw the last MessagingException we caught. We only
+ // do this if we were unable to send the message to any
+ // server. If sending eventually succeeded, we exit
+ // deliver() though the return at the end of the try
+ // block.
+ if (lastError != null) {
+ throw lastError;
+ }
+ } catch (SendFailedException sfe) {
+ logSendFailedException(sfe);
+
+ // Copy the recipients as direct modification may not be possible
+ Collection<MailAddress> recipients = new ArrayList<MailAddress>(mail.getRecipients());
+
+ boolean deleteMessage = false;
+
+ /*
+ * If you send a message that has multiple invalid addresses, you'll
+ * get a top-level SendFailedException that that has the valid,
+ * valid-unsent, and invalid address lists, with all of the server
+ * response messages will be contained within the nested exceptions.
+ * [Note: the content of the nested exceptions is implementation
+ * dependent.]
+ *
+ * sfe.getInvalidAddresses() should be considered permanent.
+ * sfe.getValidUnsentAddresses() should be considered temporary.
+ *
+ * JavaMail v1.3 properly populates those collections based upon the
+ * 4xx and 5xx response codes to RCPT TO. Some servers, such as
+ * Yahoo! don't respond to the RCPT TO, and provide a 5xx reply
+ * after DATA. In that case, we will pick up the failure from
+ * SMTPSendFailedException.
+ */
+
+ /*
+ * SMTPSendFailedException introduced in JavaMail 1.3.2, and
+ * provides detailed protocol reply code for the operation
+ */
+ try {
+ if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
+ int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
+ // If we got an SMTPSendFailedException, use its RetCode to
+ // determine default permanent/temporary failure
+ deleteMessage = (returnCode >= 500 && returnCode <= 599);
+ } else {
+ // Sometimes we'll get a normal SendFailedException with
+ // nested SMTPAddressFailedException, so use the latter
+ // RetCode
+ MessagingException me = sfe;
+ Exception ne;
+ while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
+ me = (MessagingException) ne;
+ if (me.getClass().getName().endsWith(".SMTPAddressFailedException")) {
+ int returnCode = (Integer) invokeGetter(me, "getReturnCode");
+ deleteMessage = (returnCode >= 500 && returnCode <= 599);
+ }
+ }
+ }
+ } catch (IllegalStateException ise) {
+ // unexpected exception (not a compatible javamail
+ // implementation)
+ } catch (ClassCastException cce) {
+ // unexpected exception (not a compatible javamail
+ // implementation)
+ }
+
+ // log the original set of intended recipients
+ if (configuration.isDebug())
+ logger.debug("Recipients: " + recipients);
+
+ if (sfe.getInvalidAddresses() != null) {
+ Address[] address = sfe.getInvalidAddresses();
+ if (address.length > 0) {
+ recipients.clear();
+ for (Address addres : address) {
+ try {
+ recipients.add(new MailAddress(addres.toString()));
+ } catch (ParseException pe) {
+ // this should never happen ... we should have
+ // caught malformed addresses long before we
+ // got to this code.
+ logger.debug("Can't parse invalid address: " + pe.getMessage());
+ }
+ }
+ // Set the recipients for the mail
+ mail.setRecipients(recipients);
+
+ if (configuration.isDebug())
+ logger.debug("Invalid recipients: " + recipients);
+ deleteMessage = failMessage(mail, sfe, true);
+ }
+ }
+
+ if (sfe.getValidUnsentAddresses() != null) {
+ Address[] address = sfe.getValidUnsentAddresses();
+ if (address.length > 0) {
+ recipients.clear();
+ for (Address addres : address) {
+ try {
+ recipients.add(new MailAddress(addres.toString()));
+ } catch (ParseException pe) {
+ // this should never happen ... we should have
+ // caught malformed addresses long before we
+ // got to this code.
+ logger.debug("Can't parse unsent address: " + pe.getMessage());
+ }
+ }
+ // Set the recipients for the mail
+ mail.setRecipients(recipients);
+ if (configuration.isDebug())
+ logger.debug("Unsent recipients: " + recipients);
+ if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
+ int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
+ deleteMessage = failMessage(mail, sfe, returnCode >= 500 && returnCode <= 599);
+ } else {
+ deleteMessage = failMessage(mail, sfe, false);
+ }
+ }
+ }
+
+
+ return deleteMessage;
+ } catch (MessagingException ex) {
+ // We should do a better job checking this... if the failure is a
+ // general
+ // connect exception, this is less descriptive than more specific
+ // SMTP command
+ // failure... have to lookup and see what are the various Exception
+ // possibilities
+
+ // Unable to deliver message after numerous tries... fail
+ // accordingly
+
+ // We check whether this is a 5xx error message, which
+ // indicates a permanent failure (like account doesn't exist
+ // or mailbox is full or domain is setup wrong).
+ // We fail permanently if this was a 5xx error
+ return failMessage(mail, ex, ('5' == ex.getMessage().charAt(0)));
+ } catch (Exception ex) {
+ logger.error("Generic exception = permanent failure: "+ex.getMessage(), ex);
+ // Generic exception = permanent failure
+ return failMessage(mail, ex, true);
+ }
+
+ /*
+ * If we get here, we've exhausted the loop of servers without sending
+ * the message or throwing an exception. One case where this might
+ * happen is if we get a MessagingException on each transport.connect(),
+ * e.g., if there is only one server and we get a connect exception.
+ */
+ return failMessage(mail, new MessagingException("No mail server(s) available at this time."), false);
+ }
+
+ /**
+ * Returns the javamail Session object.
+ *
+ * @param props
+ * @return the java mail session
+ */
+ protected Session obtainSession(Properties props) {
+ return Session.getInstance(props);
+ }
+
+
+ /**
+ * This method returns, given a retry-count, the next delay time to use.
+ *
+ * @param retry_count the current retry_count.
+ * @return the next delay time to use, given the retry count
+ */
+ private long getNextDelay(int retry_count) {
+ if (retry_count > configuration.getDelayTimes().size()) {
+ return Delay.DEFAULT_DELAY_TIME;
+ }
+ return configuration.getDelayTimes().get(retry_count - 1);
+ }
+
+
+ /**
+ * Utility method used to invoke getters for javamail implementation
+ * specific classes.
+ *
+ * @param target the object whom method will be invoked
+ * @param getter the no argument method name
+ * @return the result object
+ * @throws IllegalStateException on invocation error
+ */
+ private Object invokeGetter(Object target, String getter) {
+ try {
+ Method getAddress = target.getClass().getMethod(getter);
+ return getAddress.invoke(target);
+ } catch (NoSuchMethodException nsme) {
+ // An SMTPAddressFailedException with no getAddress method.
+ } catch (IllegalAccessException iae) {
+ } catch (IllegalArgumentException iae) {
+ } catch (InvocationTargetException ite) {
+ // Other issues with getAddress invokation.
+ }
+ return new IllegalStateException("Exception invoking " + getter + " on a " + target.getClass() + " object");
+ }
+
+ /*
+ * private method to log the extended SendFailedException introduced in
+ * JavaMail 1.3.2.
+ */
+ private void logSendFailedException(SendFailedException sfe) {
+ if (configuration.isDebug()) {
+ MessagingException me = sfe;
+ if (me.getClass().getName().endsWith(".SMTPSendFailedException")) {
+ try {
+ String command = (String) invokeGetter(sfe, "getCommand");
+ Integer returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
+ logger.debug("SMTP SEND FAILED:");
+ logger.debug(sfe.toString());
+ logger.debug(" Command: " + command);
+ logger.debug(" RetCode: " + returnCode);
+ logger.debug(" Response: " + sfe.getMessage());
+ } catch (IllegalStateException ise) {
+ // Error invoking the getAddress method
+ logger.debug("Send failed: " + me.toString());
+ } catch (ClassCastException cce) {
+ // The getAddress method returned something different than
+ // InternetAddress
+ logger.debug("Send failed: " + me.toString());
+ }
+ } else {
+ logger.debug("Send failed: " + me.toString());
+ }
+ Exception ne;
+ while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
+ me = (MessagingException) ne;
+ if (me.getClass().getName().endsWith(".SMTPAddressFailedException") || me.getClass().getName().endsWith(".SMTPAddressSucceededException")) {
+ try {
+ String action = me.getClass().getName().endsWith(".SMTPAddressFailedException") ? "FAILED" : "SUCCEEDED";
+ InternetAddress address = (InternetAddress) invokeGetter(me, "getAddress");
+ String command = (String) invokeGetter(me, "getCommand");
+ Integer returnCode = (Integer) invokeGetter(me, "getReturnCode");
+ logger.debug("ADDRESS " + action + ":");
+ logger.debug(me.toString());
+ logger.debug(" Address: " + address);
+ logger.debug(" Command: " + command);
+ logger.debug(" RetCode: " + returnCode);
+ logger.debug(" Response: " + me.getMessage());
+ } catch (IllegalStateException ise) {
+ // Error invoking the getAddress method
+ } catch (ClassCastException cce) {
+ // A method returned something different than expected
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Converts a message to 7 bit.
+ *
+ * @param part
+ */
+ private void convertTo7Bit(MimePart part) throws MessagingException, IOException {
+ if (part.isMimeType("multipart/*")) {
+ MimeMultipart parts = (MimeMultipart) part.getContent();
+ int count = parts.getCount();
+ for (int i = 0; i < count; i++) {
+ convertTo7Bit((MimePart) parts.getBodyPart(i));
+ }
+ } else if ("8bit".equals(part.getEncoding())) {
+ // The content may already be in encoded the form (likely with mail
+ // created from a
+ // stream). In that case, just changing the encoding to
+ // quoted-printable will mangle
+ // the result when this is transmitted. We must first convert the
+ // content into its
+ // native format, set it back, and only THEN set the transfer
+ // encoding to force the
+ // content to be encoded appropriately.
+
+ // if the part doesn't contain text it will be base64 encoded.
+ String contentTransferEncoding = part.isMimeType("text/*") ? "quoted-printable" : "base64";
+ part.setContent(part.getContent(), part.getContentType());
+ part.setHeader("Content-Transfer-Encoding", contentTransferEncoding);
+ part.addHeader("X-MIME-Autoconverted", "from 8bit to " + contentTransferEncoding + " by " + mailetContext.getServerInfo());
+ }
+ }
+
+ /**
+ * Insert the method's description here.
+ *
+ * @param mail org.apache.james.core.MailImpl
+ * @param ex javax.mail.MessagingException
+ * @param permanent
+ * @return boolean Whether the message failed fully and can be deleted
+ */
+ private boolean failMessage(Mail mail, Exception ex, boolean permanent) {
+ StringWriter sout = new StringWriter();
+ PrintWriter out = new PrintWriter(sout, true);
+ if (permanent) {
+ out.print("Permanent");
+ } else {
+ out.print("Temporary");
+ }
+
+ String exceptionLog = exceptionToLogString(ex);
+
+ StringBuilder logBuffer = new StringBuilder(64).append(" exception delivering mail (").append(mail.getName());
+
+ if (exceptionLog != null) {
+ logBuffer.append(". ");
+ logBuffer.append(exceptionLog);
+ }
+
+ logBuffer.append(": ");
+ out.print(logBuffer.toString());
+ if (configuration.isDebug())
+ ex.printStackTrace(out);
+ logger.debug(sout.toString());
+ if (!permanent) {
+ if (!mail.getState().equals(Mail.ERROR)) {
+ mail.setState(Mail.ERROR);
+ mail.setErrorMessage("0");
+ mail.setLastUpdated(new Date());
+ }
+
+ int retries = 0;
+ try {
+ retries = Integer.parseInt(mail.getErrorMessage());
+ } catch (NumberFormatException e) {
+ // Something strange was happen with the errorMessage..
+ }
+
+ if (retries < configuration.getMaxRetries()) {
+ logBuffer = new StringBuilder(128).append("Storing message ").append(mail.getName()).append(" into outgoing after ").append(retries).append(" retries");
+ logger.debug(logBuffer.toString());
+ ++retries;
+ mail.setErrorMessage(retries + "");
+ mail.setLastUpdated(new Date());
+ return false;
+ } else {
+ logBuffer = new StringBuilder(128).append("Bouncing message ").append(mail.getName()).append(" after ").append(retries).append(" retries");
+ logger.debug(logBuffer.toString());
+ }
+ }
+
+ if (mail.getSender() == null) {
+ logger.debug("Null Sender: no bounce will be generated for " + mail.getName());
+ return true;
+ }
+
+ if (configuration.getBounceProcessor() != null) {
+ // do the new DSN bounce
+ // setting attributes for DSN mailet
+ String cause;
+ if (ex instanceof MessagingException) {
+ cause = getErrorMsg((MessagingException) ex);
+ } else {
+ cause = ex.getMessage();
+ }
+ mail.setAttribute("delivery-error", cause);
+ mail.setState(configuration.getBounceProcessor());
+ // re-insert the mail into the spool for getting it passed to the
+ // dsn-processor
+ MailetContext mc = mailetContext;
+ try {
+ mc.sendMail(mail);
+ } catch (MessagingException e) {
+ // we shouldn't get an exception, because the mail was already
+ // processed
+ logger.debug("Exception re-inserting failed mail: ", e);
+ }
+ } else {
+ // do an old style bounce
+ bounce(mail, ex);
+ }
+ return true;
+ }
+
+
+ /**
+ * Try to return a usefull logString created of the Exception which was
+ * given. Return null if nothing usefull could be done
+ *
+ * @param e The MessagingException to use
+ * @return logString
+ */
+ private String exceptionToLogString(Exception e) {
+ if (e.getClass().getName().endsWith(".SMTPSendFailedException")) {
+ return "RemoteHost said: " + e.getMessage();
+ } else if (e instanceof SendFailedException) {
+ SendFailedException exception = (SendFailedException) e;
+
+ // No error
+ if (exception.getInvalidAddresses().length == 0 && exception.getValidUnsentAddresses().length == 0)
+ return null;
+
+ Exception ex;
+ StringBuilder sb = new StringBuilder();
+ boolean smtpExFound = false;
+ sb.append("RemoteHost said:");
+
+ if (e instanceof MessagingException)
+ while ((ex = ((MessagingException) e).getNextException()) != null && ex instanceof MessagingException) {
+ e = ex;
+ if (ex.getClass().getName().endsWith(".SMTPAddressFailedException")) {
+ try {
+ InternetAddress ia = (InternetAddress) invokeGetter(ex, "getAddress");
+ sb.append(" ( ").append(ia).append(" - [").append(ex.getMessage().replaceAll("\\n", "")).append("] )");
+ smtpExFound = true;
+ } catch (IllegalStateException ise) {
+ // Error invoking the getAddress method
+ } catch (ClassCastException cce) {
+ // The getAddress method returned something
+ // different than InternetAddress
+ }
+ }
+ }
+ if (!smtpExFound) {
+ boolean invalidAddr = false;
+ sb.append(" ( ");
+
+ if (exception.getInvalidAddresses().length > 0) {
+ sb.append(Arrays.toString(exception.getInvalidAddresses()));
+ invalidAddr = true;
+ }
+ if (exception.getValidUnsentAddresses().length > 0) {
+ if (invalidAddr)
+ sb.append(" ");
+ sb.append(Arrays.toString(exception.getValidUnsentAddresses()));
+ }
+ sb.append(" - [");
+ sb.append(exception.getMessage().replaceAll("\\n", ""));
+ sb.append("] )");
+ }
+ return sb.toString();
+ }
+ return null;
+ }
+
+ /**
+ * Utility method for getting the error message from the (nested) exception.
+ *
+ * @param me MessagingException
+ * @return error message
+ */
+ protected String getErrorMsg(MessagingException me) {
+ if (me.getNextException() == null) {
+ return me.getMessage().trim();
+ } else {
+ Exception ex1 = me.getNextException();
+ return ex1.getMessage().trim();
+ }
+ }
+
+ private void bounce(Mail mail, Exception ex) {
+ StringWriter sout = new StringWriter();
+ PrintWriter out = new PrintWriter(sout, true);
+ String machine;
+ try {
+ machine = configuration.getHeloNameProvider().getHeloName();
+
+ } catch (Exception e) {
+ machine = "[address unknown]";
+ }
+ String bounceBuffer = "Hi. This is the James mail server at " + machine + ".";
+ out.println(bounceBuffer);
+ out.println("I'm afraid I wasn't able to deliver your message to the following addresses.");
+ out.println("This is a permanent error; I've given up. Sorry it didn't work out. Below");
+ out.println("I include the list of recipients and the reason why I was unable to deliver");
+ out.println("your message.");
+ out.println();
+ for (MailAddress mailAddress : mail.getRecipients()) {
+ out.println(mailAddress);
+ }
+ if (ex instanceof MessagingException) {
+ if (((MessagingException) ex).getNextException() == null) {
+ out.println(ex.getMessage().trim());
+ } else {
+ Exception ex1 = ((MessagingException) ex).getNextException();
+ if (ex1 instanceof SendFailedException) {
+ out.println("Remote mail server told me: " + ex1.getMessage().trim());
+ } else if (ex1 instanceof UnknownHostException) {
+ out.println("Unknown host: " + ex1.getMessage().trim());
+ out.println("This could be a DNS server error, a typo, or a problem with the recipient's mail server.");
+ } else if (ex1 instanceof ConnectException) {
+ // Already formatted as "Connection timed out: connect"
+ out.println(ex1.getMessage().trim());
+ } else if (ex1 instanceof SocketException) {
+ out.println("Socket exception: " + ex1.getMessage().trim());
+ } else {
+ out.println(ex1.getMessage().trim());
+ }
+ }
+ }
+ out.println();
+
+ logger.debug("Sending failure message " + mail.getName());
+ try {
+ mailetContext.bounce(mail, sout.toString());
+ } catch (MessagingException me) {
+ logger.debug("Encountered unexpected messaging exception while bouncing message: " + me.getMessage());
+ } catch (Exception e) {
+ logger.debug("Encountered unexpected exception while bouncing message: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Returns an Iterator over org.apache.mailet.HostAddress, a specialized
+ * subclass of javax.mail.URLName, which provides location information for
+ * servers that are specified as mail handlers for the given hostname. If no
+ * host is found, the Iterator returned will be empty and the first call to
+ * hasNext() will return false. The Iterator is a nested iterator: the outer
+ * iteration is over each gateway, and the inner iteration is over
+ * potentially multiple A records for each gateway.
+ *
+ * @param gatewayServers - Collection of host[:port] Strings
+ * @return an Iterator over HostAddress instances, sorted by priority
+ * @since v2.2.0a16-unstable
+ */
+ private Iterator<HostAddress> getGatewaySMTPHostAddresses(Collection<String> gatewayServers) {
+ Iterator<String> gateways = gatewayServers.iterator();
+
+ return new MXHostAddressIterator(gateways, dnsServer, false, logger);
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/4a5a4ba6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyed.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyed.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyed.java
new file mode 100644
index 0000000..19d4b36
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyed.java
@@ -0,0 +1,36 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+public class VolatileIsDestroyed {
+ private volatile boolean isDestroyed;
+
+ public VolatileIsDestroyed() {
+ this.isDestroyed = false;
+ }
+
+ public boolean isDestroyed() {
+ return isDestroyed;
+ }
+
+ public void markAsDestroyed() {
+ isDestroyed = true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/4a5a4ba6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyedTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyedTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyedTest.java
new file mode 100644
index 0000000..dd10c8c
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/VolatileIsDestroyedTest.java
@@ -0,0 +1,41 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+public class VolatileIsDestroyedTest {
+
+ @Test
+ public void isDestroyedShouldBeFalseByDefault() {
+ assertThat(new VolatileIsDestroyed().isDestroyed()).isFalse();
+ }
+
+ @Test
+ public void isDestroyedShouldBeTrueWhenMarkedAsDestroyed() {
+ VolatileIsDestroyed volatileIsDestroyed = new VolatileIsDestroyed();
+
+ volatileIsDestroyed.markAsDestroyed();
+
+ assertThat(volatileIsDestroyed.isDestroyed()).isTrue();
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[19/50] [abbrv] james-project git commit: JAMES-1877 Extract 7 bit
conversion
Posted by ro...@apache.org.
JAMES-1877 Extract 7 bit conversion
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/a62e460e
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/a62e460e
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/a62e460e
Branch: refs/heads/master
Commit: a62e460e668c72bd2a3e71624a8446c9e456a1aa
Parents: 3b02d3f
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 15:50:50 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:49 2017 +0700
----------------------------------------------------------------------
.../mailets/remoteDelivery/Converter7Bit.java | 65 ++++++++++++++++++++
.../remoteDelivery/DeliveryRunnable.java | 39 ++----------
2 files changed, 69 insertions(+), 35 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/a62e460e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Converter7Bit.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Converter7Bit.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Converter7Bit.java
new file mode 100644
index 0000000..ab798e6
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Converter7Bit.java
@@ -0,0 +1,65 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.io.IOException;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMultipart;
+import javax.mail.internet.MimePart;
+
+import org.apache.mailet.MailetContext;
+
+public class Converter7Bit {
+
+ private final MailetContext mailetContext;
+
+ public Converter7Bit(MailetContext mailetContext) {
+ this.mailetContext = mailetContext;
+ }
+
+ public MimePart convertTo7Bit(MimePart part) throws MessagingException, IOException {
+ if (part.isMimeType("multipart/*")) {
+ MimeMultipart parts = (MimeMultipart) part.getContent();
+ int count = parts.getCount();
+ for (int i = 0; i < count; i++) {
+ convertTo7Bit((MimePart) parts.getBodyPart(i));
+ }
+ } else if ("8bit".equals(part.getEncoding())) {
+ // The content may already be in encoded the form (likely with mail
+ // created from a
+ // stream). In that case, just changing the encoding to
+ // quoted-printable will mangle
+ // the result when this is transmitted. We must first convert the
+ // content into its
+ // native format, set it back, and only THEN set the transfer
+ // encoding to force the
+ // content to be encoded appropriately.
+
+ // if the part doesn't contain text it will be base64 encoded.
+ String contentTransferEncoding = part.isMimeType("text/*") ? "quoted-printable" : "base64";
+ part.setContent(part.getContent(), part.getContentType());
+ part.setHeader("Content-Transfer-Encoding", contentTransferEncoding);
+ part.addHeader("X-MIME-Autoconverted", "from 8bit to " + contentTransferEncoding + " by " + mailetContext.getServerInfo());
+ }
+ return part;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/a62e460e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index 9c31696..d9db12c 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -36,8 +36,6 @@ import javax.mail.SendFailedException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMultipart;
-import javax.mail.internet.MimePart;
import javax.mail.internet.ParseException;
import org.apache.james.dnsservice.api.DNSService;
@@ -69,6 +67,7 @@ public class DeliveryRunnable implements Runnable {
private final MailetContext mailetContext;
private final VolatileIsDestroyed volatileIsDestroyed;
private final MessageComposer messageComposer;
+ private final Converter7Bit converter7Bit;
public DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, DNSService dnsServer, Metric outgoingMailsMetric, Logger logger, MailetContext mailetContext, VolatileIsDestroyed volatileIsDestroyed) {
this.queue = queue;
@@ -79,6 +78,7 @@ public class DeliveryRunnable implements Runnable {
this.mailetContext = mailetContext;
this.volatileIsDestroyed = volatileIsDestroyed;
this.messageComposer = new MessageComposer(configuration);
+ this.converter7Bit = new Converter7Bit(mailetContext);
}
/**
@@ -486,7 +486,7 @@ public class DeliveryRunnable implements Runnable {
// Temporarily disabled. See JAMES-638
if (!transport.supportsExtension(BIT_MIME_8)) {
try {
- convertTo7Bit(message);
+ converter7Bit.convertTo7Bit(message);
} catch (IOException e) {
// An error has occured during the 7bit conversion.
// The error is logged and the message is sent anyway.
@@ -498,7 +498,7 @@ public class DeliveryRunnable implements Runnable {
// If the transport is not the one developed by Sun we are not sure of how it
// handles the 8 bit mime stuff, so I convert the message to 7bit.
try {
- convertTo7Bit(message);
+ converter7Bit.convertTo7Bit(message);
} catch (IOException e) {
logger.error("Error during the conversion to 7 bit.", e);
}
@@ -647,37 +647,6 @@ public class DeliveryRunnable implements Runnable {
}
/**
- * Converts a message to 7 bit.
- *
- * @param part
- */
- private void convertTo7Bit(MimePart part) throws MessagingException, IOException {
- if (part.isMimeType("multipart/*")) {
- MimeMultipart parts = (MimeMultipart) part.getContent();
- int count = parts.getCount();
- for (int i = 0; i < count; i++) {
- convertTo7Bit((MimePart) parts.getBodyPart(i));
- }
- } else if ("8bit".equals(part.getEncoding())) {
- // The content may already be in encoded the form (likely with mail
- // created from a
- // stream). In that case, just changing the encoding to
- // quoted-printable will mangle
- // the result when this is transmitted. We must first convert the
- // content into its
- // native format, set it back, and only THEN set the transfer
- // encoding to force the
- // content to be encoded appropriately.
-
- // if the part doesn't contain text it will be base64 encoded.
- String contentTransferEncoding = part.isMimeType("text/*") ? "quoted-printable" : "base64";
- part.setContent(part.getContent(), part.getContentType());
- part.setHeader("Content-Transfer-Encoding", contentTransferEncoding);
- part.addHeader("X-MIME-Autoconverted", "from 8bit to " + contentTransferEncoding + " by " + mailetContext.getServerInfo());
- }
- }
-
- /**
* Insert the method's description here.
*
* @param mail org.apache.james.core.MailImpl
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[38/50] [abbrv] james-project git commit: JAMES-1877 Bounce on
invalid addresses before discarding them
Posted by ro...@apache.org.
JAMES-1877 Bounce on invalid addresses before discarding them
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/96465710
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/96465710
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/96465710
Branch: refs/heads/master
Commit: 9646571062ae917dd678c4c15c90012a648c2ab8
Parents: 1c6d1d0
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Dec 7 10:13:38 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 18:14:17 2017 +0700
----------------------------------------------------------------------
.../org/apache/mailet/base/test/FakeMail.java | 18 +++++++---
.../james/transport/mailets/RemoteDelivery.java | 38 ++++++++++----------
.../remoteDelivery/DeliveryRunnable.java | 6 ++--
.../mailets/remoteDelivery/MailDelivrer.java | 8 ++++-
.../remoteDelivery/MailDelivrerTest.java | 24 ++++++++++++-
.../remoteDelivery/RemoteDeliveryTest.java | 5 ++-
6 files changed, 67 insertions(+), 32 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/96465710/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java
index 661882a..59a3b89 100644
--- a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java
+++ b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java
@@ -58,6 +58,19 @@ public class FakeMail implements Mail {
new ByteArrayInputStream(text.getBytes(javaEncodingCharset))))
.build();
}
+
+ public static FakeMail fromMail(Mail mail) throws MessagingException {
+ return new FakeMail(mail.getMessage(),
+ Lists.newArrayList(mail.getRecipients()),
+ mail.getName(),
+ mail.getSender(),
+ mail.getState(),
+ mail.getErrorMessage(),
+ mail.getLastUpdated(),
+ attributes(mail),
+ mail.getMessageSize(),
+ mail.getRemoteAddr());
+ }
public static Builder builder() {
return new Builder();
@@ -212,11 +225,6 @@ public class FakeMail implements Mail {
this.remoteAddr = remoteAddr;
}
- public FakeMail(Mail mail) throws MessagingException {
- this(mail.getMessage(), Lists.newArrayList(mail.getRecipients()), mail.getName(), mail.getSender(), mail.getState(), mail.getErrorMessage(),
- mail.getLastUpdated(), attributes(mail), mail.getMessageSize(), mail.getRemoteAddr());
- }
-
@Override
public String getName() {
return name;
http://git-wip-us.apache.org/repos/asf/james-project/blob/96465710/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index 8a40298..3a1f17d 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -23,7 +23,8 @@ import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Locale;
import java.util.Map;
-import java.util.Vector;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import javax.inject.Inject;
import javax.mail.MessagingException;
@@ -36,6 +37,7 @@ import org.apache.james.queue.api.MailPrioritySupport;
import org.apache.james.queue.api.MailQueue;
import org.apache.james.queue.api.MailQueue.MailQueueException;
import org.apache.james.queue.api.MailQueueFactory;
+import org.apache.james.transport.mailets.remoteDelivery.Bouncer;
import org.apache.james.transport.mailets.remoteDelivery.DeliveryRunnable;
import org.apache.james.transport.mailets.remoteDelivery.RemoteDeliveryConfiguration;
import org.apache.james.transport.mailets.remoteDelivery.RemoteDeliverySocketFactory;
@@ -119,34 +121,37 @@ import com.google.common.collect.HashMultimap;
*/
public class RemoteDelivery extends GenericMailet {
+ public enum THREAD_STATE {
+ START_THREADS,
+ DO_NOT_START_THREADS
+ }
+
private static final String OUTGOING_MAILS = "outgoingMails";
- private static final boolean DEFAULT_START_THREADS = true;
public static final String NAME_JUNCTION = "-to-";
private final DNSService dnsServer;
private final DomainList domainList;
private final MailQueueFactory queueFactory;
private final Metric outgoingMailsMetric;
- private final Collection<Thread> workersThreads;
private final VolatileIsDestroyed volatileIsDestroyed;
- private final boolean startThreads;
+ private final THREAD_STATE startThreads;
private MailQueue queue;
private Logger logger;
private RemoteDeliveryConfiguration configuration;
+ private ExecutorService executor;
@Inject
public RemoteDelivery(DNSService dnsServer, DomainList domainList, MailQueueFactory queueFactory, MetricFactory metricFactory) {
- this(dnsServer, domainList, queueFactory, metricFactory, DEFAULT_START_THREADS);
+ this(dnsServer, domainList, queueFactory, metricFactory, THREAD_STATE.START_THREADS);
}
- public RemoteDelivery(DNSService dnsServer, DomainList domainList, MailQueueFactory queueFactory, MetricFactory metricFactory, boolean startThreads) {
+ public RemoteDelivery(DNSService dnsServer, DomainList domainList, MailQueueFactory queueFactory, MetricFactory metricFactory, THREAD_STATE startThreads) {
this.dnsServer = dnsServer;
this.domainList = domainList;
this.queueFactory = queueFactory;
this.outgoingMailsMetric = metricFactory.generate(OUTGOING_MAILS);
this.volatileIsDestroyed = new VolatileIsDestroyed();
- this.workersThreads = new Vector<Thread>();
this.startThreads = startThreads;
}
@@ -160,25 +165,23 @@ public class RemoteDelivery extends GenericMailet {
} catch (UnknownHostException e) {
log("Invalid bind setting (" + configuration.getBindAddress() + "): " + e.toString());
}
- if (startThreads) {
+ if (startThreads == THREAD_STATE.START_THREADS) {
initDeliveryThreads();
}
}
private void initDeliveryThreads() {
+ executor = Executors.newFixedThreadPool(configuration.getWorkersThreadCount());
for (int a = 0; a < configuration.getWorkersThreadCount(); a++) {
- String threadName = "Remote delivery thread (" + a + ")";
- Thread t = new Thread(
+ executor.execute(
new DeliveryRunnable(queue,
configuration,
dnsServer,
outgoingMailsMetric,
logger,
getMailetContext(),
- volatileIsDestroyed),
- threadName);
- t.start();
- workersThreads.add(t);
+ new Bouncer(configuration, getMailetContext(), logger),
+ volatileIsDestroyed));
}
}
@@ -255,12 +258,9 @@ public class RemoteDelivery extends GenericMailet {
*/
@Override
public synchronized void destroy() {
- if (startThreads) {
+ if (startThreads == THREAD_STATE.START_THREADS) {
volatileIsDestroyed.markAsDestroyed();
- // Wake up all threads from waiting for an accept
- for (Thread t : workersThreads) {
- t.interrupt();
- }
+ executor.shutdown();
notifyAll();
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/96465710/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index bc01245..7af269b 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -54,9 +54,9 @@ public class DeliveryRunnable implements Runnable {
private final Supplier<Date> dateSupplier;
public DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, DNSService dnsServer, Metric outgoingMailsMetric,
- Logger logger, MailetContext mailetContext, VolatileIsDestroyed volatileIsDestroyed) {
- this(queue, configuration, outgoingMailsMetric, logger, new Bouncer(configuration, mailetContext, logger),
- new MailDelivrer(configuration, new MailDelivrerToHost(configuration, mailetContext, logger), dnsServer, logger),
+ Logger logger, MailetContext mailetContext, Bouncer bouncer, VolatileIsDestroyed volatileIsDestroyed) {
+ this(queue, configuration, outgoingMailsMetric, logger, bouncer,
+ new MailDelivrer(configuration, new MailDelivrerToHost(configuration, mailetContext, logger), dnsServer, bouncer, logger),
volatileIsDestroyed, CURRENT_DATE_SUPPLIER);
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/96465710/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
index c89a2a0..bb03b62 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
@@ -45,11 +45,13 @@ public class MailDelivrer {
private final MailDelivrerToHost mailDelivrerToHost;
private final DnsHelper dnsHelper;
private final MessageComposer messageComposer;
+ private final Bouncer bouncer;
private final Logger logger;
- public MailDelivrer(RemoteDeliveryConfiguration configuration, MailDelivrerToHost mailDelivrerToHost, DNSService dnsServer, Logger logger) {
+ public MailDelivrer(RemoteDeliveryConfiguration configuration, MailDelivrerToHost mailDelivrerToHost, DNSService dnsServer, Bouncer bouncer, Logger logger) {
this.configuration = configuration;
this.mailDelivrerToHost = mailDelivrerToHost;
+ this.bouncer = bouncer;
this.dnsHelper = new DnsHelper(dnsServer, configuration, logger);
this.messageComposer = new MessageComposer(configuration);
this.logger = logger;
@@ -191,6 +193,10 @@ public class MailDelivrer {
}
}
if (!validUnsentAddresses.isEmpty()) {
+ if (!invalidAddresses.isEmpty()) {
+ mail.setRecipients(invalidAddresses);
+ bouncer.bounce(mail, sfe);
+ }
mail.setRecipients(validUnsentAddresses);
if (enhancedMessagingException.hasReturnCode()) {
boolean isPermanent = enhancedMessagingException.isServerError();
http://git-wip-us.apache.org/repos/asf/james-project/blob/96465710/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
index 9c5fe69..c96e9a1 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
@@ -21,6 +21,8 @@ package org.apache.james.transport.mailets.remoteDelivery;
import static org.mockito.Mockito.mock;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import javax.mail.Address;
import javax.mail.SendFailedException;
@@ -42,10 +44,12 @@ public class MailDelivrerTest {
private static final Logger LOGGER = LoggerFactory.getLogger(MailDelivrerTest.class);
private MailDelivrer testee;
+ private Bouncer bouncer;
@Before
public void setUp() {
- testee = new MailDelivrer(mock(RemoteDeliveryConfiguration.class), mock(MailDelivrerToHost.class), mock(DNSService.class), LOGGER);
+ bouncer = mock(Bouncer.class);
+ testee = new MailDelivrer(mock(RemoteDeliveryConfiguration.class), mock(MailDelivrerToHost.class), mock(DNSService.class), bouncer, LOGGER);
}
@Test
@@ -180,4 +184,22 @@ public class MailDelivrerTest {
assertThat(mail.getRecipients()).containsOnly(MailAddressFixture.OTHER_AT_JAMES);
}
+
+ @Test
+ public void handleSenderFailedExceptionShouldBounceInvalidAddressesOnBothInvalidAndValidUnsent() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ Address[] validSent = {};
+ Address[] validUnsent = {new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())};
+ Address[] invalid = {new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString())};
+ SendFailedException sfe = new SendFailedException("Message",
+ new Exception(),
+ validSent,
+ validUnsent,
+ invalid);
+ testee.handleSenderFailedException(mail, sfe);
+
+ verify(bouncer).bounce(mail, sfe);
+ verifyNoMoreInteractions(bouncer);
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/96465710/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryTest.java
index 2012a2e..6e944e3 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryTest.java
@@ -66,7 +66,7 @@ public class RemoteDeliveryTest {
@Override
public void enQueue(Mail mail) throws MailQueueException {
try {
- enqueuedMail.add(new FakeMail(mail));
+ enqueuedMail.add(FakeMail.fromMail(mail));
} catch (MessagingException e) {
throw Throwables.propagate(e);
}
@@ -82,7 +82,6 @@ public class RemoteDeliveryTest {
}
}
- public static final boolean DONT_START_THREADS = false;
private RemoteDelivery remoteDelivery;
private FakeMailQueue mailQueue;
@@ -91,7 +90,7 @@ public class RemoteDeliveryTest {
MailQueueFactory queueFactory = mock(MailQueueFactory.class);
mailQueue = new FakeMailQueue();
when(queueFactory.getQueue(RemoteDeliveryConfiguration.OUTGOING)).thenReturn(mailQueue);
- remoteDelivery = new RemoteDelivery(mock(DNSService.class), mock(DomainList.class), queueFactory, mock(MetricFactory.class), DONT_START_THREADS);
+ remoteDelivery = new RemoteDelivery(mock(DNSService.class), mock(DomainList.class), queueFactory, mock(MetricFactory.class), RemoteDelivery.THREAD_STATE.DO_NOT_START_THREADS);
}
@Test
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[13/50] [abbrv] james-project git commit: JAMES-1877 Inspection is
not needed to see if 8 bit is supported
Posted by ro...@apache.org.
JAMES-1877 Inspection is not needed to see if 8 bit is supported
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/63bb3074
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/63bb3074
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/63bb3074
Branch: refs/heads/master
Commit: 63bb307449633acc0bfb2a0c9a7ac908ccead9e0
Parents: b839f8b
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 14:11:15 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:48 2017 +0700
----------------------------------------------------------------------
.../mailets/remoteDelivery/DeliveryRunnable.java | 19 ++-----------------
1 file changed, 2 insertions(+), 17 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/63bb3074/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index cb189d0..ea35f7c 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -59,6 +59,7 @@ import com.sun.mail.smtp.SMTPTransport;
public class DeliveryRunnable implements Runnable {
public static final boolean PERMANENT_FAILURE = true;
+ public static final String BIT_MIME_8 = "8BITMIME";
private final MailQueue queue;
private final RemoteDeliveryConfiguration configuration;
private final DNSService dnsServer;
@@ -407,7 +408,7 @@ public class DeliveryRunnable implements Runnable {
// that conversion, but it is required to be a rfc-compliant smtp server.
// Temporarily disabled. See JAMES-638
- if (!isSupports8bitmime(transport)) {
+ if (!transport.supportsExtension(BIT_MIME_8)) {
try {
convertTo7Bit(message);
} catch (IOException e) {
@@ -513,22 +514,6 @@ public class DeliveryRunnable implements Runnable {
return null;
}
- private boolean isSupports8bitmime(SMTPTransport transport) {
- boolean supports8bitmime = false;
- try {
- Method supportsExtension = transport.getClass().getMethod("supportsExtension", new Class[]{String.class});
- supports8bitmime = (Boolean) supportsExtension.invoke(transport, "8BITMIME");
- } catch (NoSuchMethodException nsme) {
- // An SMTPAddressFailedException with no
- // getAddress method.
- } catch (IllegalAccessException iae) {
- } catch (IllegalArgumentException iae) {
- } catch (InvocationTargetException ite) {
- // Other issues with getAddress invokation.
- }
- return supports8bitmime;
- }
-
private boolean handleTemporaryResolutionException(Mail mail, String host) {
logger.info("Temporary problem looking up mail server for host: " + host);
// temporary problems
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[25/50] [abbrv] james-project git commit: JAMES-1877 Simplify
MessageComposer API with ExecutionResult
Posted by ro...@apache.org.
JAMES-1877 Simplify MessageComposer API with ExecutionResult
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/942cdfc6
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/942cdfc6
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/942cdfc6
Branch: refs/heads/master
Commit: 942cdfc66265af6a966b5814b5366fda26433e7e
Parents: 26c6d9c
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 18:45:36 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:50 2017 +0700
----------------------------------------------------------------------
.../remoteDelivery/DeliveryRunnable.java | 108 +++++--------------
.../mailets/remoteDelivery/ExecutionResult.java | 76 +++++++++++++
.../mailets/remoteDelivery/MessageComposer.java | 8 +-
3 files changed, 110 insertions(+), 82 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/942cdfc6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index 39b38d0..f497767 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -51,65 +51,11 @@ import org.apache.mailet.MailAddress;
import org.apache.mailet.MailetContext;
import org.slf4j.Logger;
-import com.google.common.base.Optional;
import com.sun.mail.smtp.SMTPTransport;
@SuppressWarnings("deprecation")
public class DeliveryRunnable implements Runnable {
- private static ExecutionResult success() {
- return new ExecutionResult(ExecutionState.SUCCESS, Optional.<Exception>absent());
- }
-
- private static ExecutionResult temporaryFailure(Exception e) {
- return new ExecutionResult(ExecutionState.TEMPORARY_FAILURE, Optional.of(e));
- }
-
- private static ExecutionResult permanentFailure(Exception e) {
- return new ExecutionResult(ExecutionState.PERMANENT_FAILURE, Optional.of(e));
- }
-
- private static ExecutionResult temporaryFailure() {
- return new ExecutionResult(ExecutionState.TEMPORARY_FAILURE, Optional.<Exception>absent());
- }
-
- private static ExecutionResult permanentFailure() {
- return new ExecutionResult(ExecutionState.PERMANENT_FAILURE, Optional.<Exception>absent());
- }
-
- private static class ExecutionResult {
- private final ExecutionState executionState;
- private final Optional<Exception> exception;
-
- public ExecutionResult(ExecutionState executionState, Optional<Exception> exception) {
- this.executionState = executionState;
- this.exception = exception;
- }
-
- public ExecutionState getExecutionState() {
- return executionState;
- }
-
- public Optional<Exception> getException() {
- return exception;
- }
- }
-
- private enum ExecutionState {
- SUCCESS,
- PERMANENT_FAILURE,
- TEMPORARY_FAILURE
- }
-
- private static ExecutionResult onFailure(boolean permanent, Exception exeption) {
- if (permanent) {
- return permanentFailure(exeption);
- } else {
- return temporaryFailure(exeption);
- }
- }
-
- public static final boolean PERMANENT_FAILURE = true;
public static final String BIT_MIME_8 = "8BITMIME";
private final MailQueue queue;
private final RemoteDeliveryConfiguration configuration;
@@ -251,20 +197,22 @@ public class DeliveryRunnable implements Runnable {
// or mailbox is full or domain is setup wrong). We fail permanently if this was a 5xx error
boolean isPermanent = '5' == ex.getMessage().charAt(0);
- logger.debug(messageComposer.composeFailLogMessage(mail, ex, isPermanent));
- return onFailure(isPermanent, ex);
+ ExecutionResult executionResult = ExecutionResult.onFailure(isPermanent, ex);
+ logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
+ return executionResult;
} catch (Exception ex) {
logger.error("Generic exception = permanent failure: " + ex.getMessage(), ex);
// Generic exception = permanent failure
- logger.debug(messageComposer.composeFailLogMessage(mail, ex, PERMANENT_FAILURE));
- return permanentFailure(ex);
+ ExecutionResult executionResult = ExecutionResult.permanentFailure(ex);
+ logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
+ return executionResult;
}
}
private ExecutionResult tryDeliver(Mail mail, Session session) throws MessagingException {
if (mail.getRecipients().isEmpty()) {
logger.info("No recipients specified... not sure how this could have happened.");
- return permanentFailure(new Exception("No recipients specified for " + mail.getName() + " sent by " + mail.getSender()));
+ return ExecutionResult.permanentFailure(new Exception("No recipients specified for " + mail.getName() + " sent by " + mail.getSender()));
}
if (configuration.isDebug()) {
logger.debug("Attempting to deliver " + mail.getName());
@@ -299,7 +247,7 @@ public class DeliveryRunnable implements Runnable {
while (targetServers.hasNext()) {
try {
if (tryDeliveryToHost(mail, session, message, addr, targetServers.next())) {
- return success();
+ return ExecutionResult.success();
}
} catch (SendFailedException sfe) {
lastError = handleSendFailException(mail, sfe);
@@ -316,7 +264,7 @@ public class DeliveryRunnable implements Runnable {
if (lastError != null) {
throw lastError;
}
- return temporaryFailure();
+ return ExecutionResult.temporaryFailure();
}
private boolean tryDeliveryToHost(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException {
@@ -382,7 +330,7 @@ public class DeliveryRunnable implements Runnable {
// Copy the recipients as direct modification may not be possible
Collection<MailAddress> recipients = new ArrayList<MailAddress>(mail.getRecipients());
- ExecutionResult deleteMessage = temporaryFailure();
+ ExecutionResult deleteMessage = ExecutionResult.temporaryFailure();
/*
* If you send a message that has multiple invalid addresses, you'll
@@ -411,7 +359,7 @@ public class DeliveryRunnable implements Runnable {
int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
// If we got an SMTPSendFailedException, use its RetCode to
// determine default permanent/temporary failure
- deleteMessage = onFailure(returnCode >= 500 && returnCode <= 599, sfe);
+ deleteMessage = ExecutionResult.onFailure(returnCode >= 500 && returnCode <= 599, sfe);
} else {
// Sometimes we'll get a normal SendFailedException with
// nested SMTPAddressFailedException, so use the latter
@@ -422,7 +370,7 @@ public class DeliveryRunnable implements Runnable {
me = (MessagingException) ne;
if (me.getClass().getName().endsWith(".SMTPAddressFailedException")) {
int returnCode = (Integer) invokeGetter(me, "getReturnCode");
- deleteMessage = onFailure(returnCode >= 500 && returnCode <= 599, sfe);
+ deleteMessage = ExecutionResult.onFailure(returnCode >= 500 && returnCode <= 599, sfe);
}
}
}
@@ -457,8 +405,8 @@ public class DeliveryRunnable implements Runnable {
if (configuration.isDebug())
logger.debug("Invalid recipients: " + recipients);
- logger.debug(messageComposer.composeFailLogMessage(mail, sfe, true));
- deleteMessage = permanentFailure(sfe);
+ deleteMessage = ExecutionResult.permanentFailure(sfe);
+ logger.debug(messageComposer.composeFailLogMessage(mail, deleteMessage));
}
}
@@ -484,11 +432,11 @@ public class DeliveryRunnable implements Runnable {
if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) {
int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
boolean isPermanent = returnCode >= 500 && returnCode <= 599;
- logger.debug(messageComposer.composeFailLogMessage(mail, sfe, isPermanent));
- deleteMessage = onFailure(isPermanent, sfe);
+ deleteMessage = ExecutionResult.onFailure(isPermanent, sfe);
+ logger.debug(messageComposer.composeFailLogMessage(mail, deleteMessage));
} else {
- logger.debug(messageComposer.composeFailLogMessage(mail, sfe, false));
- deleteMessage = temporaryFailure(sfe);
+ deleteMessage = ExecutionResult.temporaryFailure(sfe);
+ logger.debug(messageComposer.composeFailLogMessage(mail, deleteMessage));
}
}
}
@@ -615,25 +563,27 @@ public class DeliveryRunnable implements Runnable {
}
private ExecutionResult handleTemporaryResolutionException(Mail mail, String host) {
- MessagingException messagingException = new MessagingException("Temporary problem looking up mail server for host: " + host + ". I cannot determine where to send this message.");
- logger.debug(messageComposer.composeFailLogMessage(mail, messagingException, false));
- return temporaryFailure(messagingException);
+ ExecutionResult executionResult = ExecutionResult.temporaryFailure(new MessagingException("Temporary problem looking " +
+ "up mail server for host: " + host + ". I cannot determine where to send this message."));
+ logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
+ return executionResult;
}
private ExecutionResult handleNoTargetServer(Mail mail, String host) {
logger.info("No mail server found for: " + host);
String exceptionBuffer = "There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.";
+ MessagingException messagingException = new MessagingException(exceptionBuffer);
int retry = DeliveryRetriesHelper.retrieveRetries(mail);
if (retry == 0 || retry > configuration.getDnsProblemRetry()) {
// The domain has no dns entry.. Return a permanent error
- MessagingException messagingException = new MessagingException(exceptionBuffer);
- logger.debug(messageComposer.composeFailLogMessage(mail, messagingException, true));
- return permanentFailure(messagingException);
+ ExecutionResult executionResult = ExecutionResult.permanentFailure(messagingException);
+ logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
+ return executionResult;
} else {
- MessagingException messagingException = new MessagingException(exceptionBuffer);
- logger.debug(messageComposer.composeFailLogMessage(mail, messagingException, false));
- return temporaryFailure(messagingException);
+ ExecutionResult executionResult = ExecutionResult.temporaryFailure(messagingException);
+ logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
+ return executionResult;
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/942cdfc6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/ExecutionResult.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/ExecutionResult.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/ExecutionResult.java
new file mode 100644
index 0000000..f984fd1
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/ExecutionResult.java
@@ -0,0 +1,76 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import com.google.common.base.Optional;
+
+public class ExecutionResult {
+
+ public enum ExecutionState {
+ SUCCESS,
+ PERMANENT_FAILURE,
+ TEMPORARY_FAILURE
+ }
+
+ public static ExecutionResult success() {
+ return new ExecutionResult(ExecutionState.SUCCESS, Optional.<Exception>absent());
+ }
+
+ public static ExecutionResult temporaryFailure(Exception e) {
+ return new ExecutionResult(ExecutionState.TEMPORARY_FAILURE, Optional.of(e));
+ }
+
+ public static ExecutionResult permanentFailure(Exception e) {
+ return new ExecutionResult(ExecutionState.PERMANENT_FAILURE, Optional.of(e));
+ }
+
+ public static ExecutionResult temporaryFailure() {
+ return new ExecutionResult(ExecutionState.TEMPORARY_FAILURE, Optional.<Exception>absent());
+ }
+
+ public static ExecutionResult onFailure(boolean permanent, Exception exeption) {
+ if (permanent) {
+ return permanentFailure(exeption);
+ } else {
+ return temporaryFailure(exeption);
+ }
+ }
+
+ private final ExecutionState executionState;
+ private final Optional<Exception> exception;
+
+ public ExecutionResult(ExecutionState executionState, Optional<Exception> exception) {
+ this.executionState = executionState;
+ this.exception = exception;
+ }
+
+ public ExecutionState getExecutionState() {
+ return executionState;
+ }
+
+ public Optional<Exception> getException() {
+ return exception;
+ }
+
+ public boolean isPermanent() {
+ return executionState == ExecutionState.PERMANENT_FAILURE;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/james-project/blob/942cdfc6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
index a323ba9..3e6d861 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MessageComposer.java
@@ -122,12 +122,14 @@ public class MessageComposer {
}
}
- public String composeFailLogMessage(Mail mail, Exception ex, boolean permanent) {
+ public String composeFailLogMessage(Mail mail, ExecutionResult executionResult) {
StringWriter sout = new StringWriter();
PrintWriter out = new PrintWriter(sout, true);
- out.print(permanentAsString(permanent) + " exception delivering mail (" + mail.getName() + ")" + retrieveExceptionLog(ex) + ": " );
+ out.print(permanentAsString(executionResult.isPermanent()) + " exception delivering mail (" + mail.getName()
+ + ")" + retrieveExceptionLog(executionResult.getException().orNull()) + ": " );
if (configuration.isDebug()) {
- ex.printStackTrace(out);
+ if (executionResult.getException().isPresent())
+ executionResult.getException().get().printStackTrace(out);
}
return sout.toString();
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[31/50] [abbrv] james-project git commit: JAMES-1877 Create
mailDelivrer
Posted by ro...@apache.org.
JAMES-1877 Create mailDelivrer
Its responsibility :
- Resolve MXs addresses for a set of domains
- Try host to host delivery
- Report execution
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/9790170c
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/9790170c
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/9790170c
Branch: refs/heads/master
Commit: 9790170cd133537194f82b16b8e89f5f16cdb504
Parents: 1467986
Author: Benoit Tellier <bt...@linagora.com>
Authored: Fri Dec 2 10:40:19 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:51 2017 +0700
----------------------------------------------------------------------
.../mailets/remoteDelivery/Bouncer.java | 4 +-
.../remoteDelivery/DeliveryRunnable.java | 434 ++-----------------
.../mailets/remoteDelivery/MailDelivrer.java | 399 +++++++++++++++++
3 files changed, 440 insertions(+), 397 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/9790170c/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
index feebf84..da90b08 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
@@ -41,9 +41,9 @@ public class Bouncer {
private final MailetContext mailetContext;
private final Logger logger;
- public Bouncer(RemoteDeliveryConfiguration configuration, MessageComposer messageComposer, MailetContext mailetContext, Logger logger) {
+ public Bouncer(RemoteDeliveryConfiguration configuration, MailetContext mailetContext, Logger logger) {
this.configuration = configuration;
- this.messageComposer = messageComposer;
+ this.messageComposer = new MessageComposer(configuration);
this.mailetContext = mailetContext;
this.logger = logger;
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/9790170c/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index 6317209..d46a9f5 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -19,98 +19,45 @@
package org.apache.james.transport.mailets.remoteDelivery;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.Date;
-import java.util.Iterator;
import java.util.concurrent.TimeUnit;
-import javax.mail.Address;
-import javax.mail.MessagingException;
-import javax.mail.SendFailedException;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
-import javax.mail.internet.ParseException;
-
import org.apache.james.dnsservice.api.DNSService;
-import org.apache.james.dnsservice.api.TemporaryResolutionException;
-import org.apache.james.dnsservice.library.MXHostAddressIterator;
import org.apache.james.lifecycle.api.LifecycleUtil;
import org.apache.james.metrics.api.Metric;
import org.apache.james.queue.api.MailPrioritySupport;
import org.apache.james.queue.api.MailQueue;
-import org.apache.mailet.HostAddress;
import org.apache.mailet.Mail;
-import org.apache.mailet.MailAddress;
import org.apache.mailet.MailetContext;
import org.slf4j.Logger;
-@SuppressWarnings("deprecation")
public class DeliveryRunnable implements Runnable {
private final MailQueue queue;
private final RemoteDeliveryConfiguration configuration;
- private final DNSService dnsServer;
private final Metric outgoingMailsMetric;
private final Logger logger;
private final Bouncer bouncer;
- private final MailDelivrerToHost mailDelivrerToHost;
+ private final MailDelivrer mailDelivrer;
private final VolatileIsDestroyed volatileIsDestroyed;
- private final MessageComposer messageComposer;
public DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, DNSService dnsServer, Metric outgoingMailsMetric,
Logger logger, MailetContext mailetContext, VolatileIsDestroyed volatileIsDestroyed) {
this.queue = queue;
this.configuration = configuration;
- this.dnsServer = dnsServer;
this.outgoingMailsMetric = outgoingMailsMetric;
this.logger = logger;
this.volatileIsDestroyed = volatileIsDestroyed;
- this.messageComposer = new MessageComposer(configuration);
- this.bouncer = new Bouncer(configuration, messageComposer, mailetContext, logger);
- this.mailDelivrerToHost = new MailDelivrerToHost(configuration, mailetContext, logger);
+ this.bouncer = new Bouncer(configuration, mailetContext, logger);
+ MailDelivrerToHost mailDelivrerToHost = new MailDelivrerToHost(configuration, mailetContext, logger);
+ this.mailDelivrer = new MailDelivrer(configuration, mailDelivrerToHost, dnsServer, logger);
}
- /**
- * Handles checking the outgoing spool for new mail and delivering them if
- * there are any
- */
@Override
public void run() {
try {
while (!Thread.interrupted() && !volatileIsDestroyed.isDestroyed()) {
- try {
- // Get the 'mail' object that is ready for deliverying. If no message is
- // ready, the 'accept' will block until message is ready.
- // The amount of time to block is determined by the 'getWaitTime' method of the MultipleDelayFilter.
- MailQueue.MailQueueItem queueItem = queue.deQueue();
- Mail mail = queueItem.getMail();
-
- try {
- if (configuration.isDebug()) {
- logger.debug(Thread.currentThread().getName() + " will process mail " + mail.getName());
- }
- attemptDelivery(mail);
- LifecycleUtil.dispose(mail);
- mail = null;
- queueItem.done(true);
- } catch (Exception e) {
- // Prevent unexpected exceptions from causing looping by removing message from outgoing.
- // DO NOT CHANGE THIS to catch Error!
- // For example, if there were an OutOfMemory condition caused because
- // something else in the server was abusing memory, we would not want to start purging the retrying spool!
- logger.error("Exception caught in RemoteDelivery.run()", e);
- LifecycleUtil.dispose(mail);
- queueItem.done(false);
- }
-
- } catch (Throwable e) {
- if (!volatileIsDestroyed.isDestroyed()) {
- logger.error("Exception caught in RemoteDelivery.run()", e);
- }
- }
+ runStep();
}
} finally {
// Restore the thread state to non-interrupted.
@@ -118,8 +65,41 @@ public class DeliveryRunnable implements Runnable {
}
}
+ private void runStep() {
+ try {
+ // Get the 'mail' object that is ready for deliverying. If no message is
+ // ready, the 'accept' will block until message is ready.
+ // The amount of time to block is determined by the 'getWaitTime' method of the MultipleDelayFilter.
+ MailQueue.MailQueueItem queueItem = queue.deQueue();
+ Mail mail = queueItem.getMail();
+
+ try {
+ if (configuration.isDebug()) {
+ logger.debug(Thread.currentThread().getName() + " will process mail " + mail.getName());
+ }
+ attemptDelivery(mail);
+ LifecycleUtil.dispose(mail);
+ mail = null;
+ queueItem.done(true);
+ } catch (Exception e) {
+ // Prevent unexpected exceptions from causing looping by removing message from outgoing.
+ // DO NOT CHANGE THIS to catch Error!
+ // For example, if there were an OutOfMemory condition caused because
+ // something else in the server was abusing memory, we would not want to start purging the retrying spool!
+ logger.error("Exception caught in RemoteDelivery.run()", e);
+ LifecycleUtil.dispose(mail);
+ queueItem.done(false);
+ }
+
+ } catch (Throwable e) {
+ if (!volatileIsDestroyed.isDestroyed()) {
+ logger.error("Exception caught in RemoteDelivery.run()", e);
+ }
+ }
+ }
+
private void attemptDelivery(Mail mail) throws MailQueue.MailQueueException {
- ExecutionResult executionResult = deliver(mail);
+ ExecutionResult executionResult = mailDelivrer.deliver(mail);
switch (executionResult.getExecutionState()) {
case SUCCESS:
outgoingMailsMetric.increment();
@@ -163,346 +143,10 @@ public class DeliveryRunnable implements Runnable {
queue.enQueue(mail, delay, TimeUnit.MILLISECONDS);
}
- /**
- * We can assume that the recipients of this message are all going to the
- * same mail server. We will now rely on the DNS server to do DNS MX record
- * lookup and try to deliver to the multiple mail servers. If it fails, it
- * should throw an exception.
- *
- * @param mail org.apache.james.core.MailImpl
- * @param session javax.mail.Session
- * @return boolean Whether the delivery was successful and the message can
- * be deleted
- */
- private ExecutionResult deliver(Mail mail) {
- try {
- return tryDeliver(mail);
- } catch (SendFailedException sfe) {
- return handleSenderFailedException(mail, sfe);
- } catch (MessagingException ex) {
- // We should do a better job checking this... if the failure is a general
- // connect exception, this is less descriptive than more specific SMTP command
- // failure... have to lookup and see what are the various Exception possibilities
-
- // Unable to deliver message after numerous tries... fail accordingly
-
- // We check whether this is a 5xx error message, which indicates a permanent failure (like account doesn't exist
- // or mailbox is full or domain is setup wrong). We fail permanently if this was a 5xx error
-
- boolean isPermanent = '5' == ex.getMessage().charAt(0);
- ExecutionResult executionResult = ExecutionResult.onFailure(isPermanent, ex);
- logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
- return executionResult;
- } catch (Exception ex) {
- logger.error("Generic exception = permanent failure: " + ex.getMessage(), ex);
- // Generic exception = permanent failure
- ExecutionResult executionResult = ExecutionResult.permanentFailure(ex);
- logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
- return executionResult;
- }
- }
-
- private ExecutionResult tryDeliver(Mail mail) throws MessagingException {
- if (mail.getRecipients().isEmpty()) {
- logger.info("No recipients specified... not sure how this could have happened.");
- return ExecutionResult.permanentFailure(new Exception("No recipients specified for " + mail.getName() + " sent by " + mail.getSender()));
- }
- if (configuration.isDebug()) {
- logger.debug("Attempting to deliver " + mail.getName());
- }
-
- // Figure out which servers to try to send to. This collection
- // will hold all the possible target servers
- Iterator<HostAddress> targetServers;
- if (configuration.getGatewayServer().isEmpty()) {
- MailAddress rcpt = mail.getRecipients().iterator().next();
- String host = rcpt.getDomain();
-
- // Lookup the possible targets
- try {
- targetServers = new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logger);
- } catch (TemporaryResolutionException e) {
- return handleTemporaryResolutionException(mail, host);
- }
- if (!targetServers.hasNext()) {
- return handleNoTargetServer(mail, host);
- }
- } else {
- targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer());
- }
-
- return doDeliver(mail, mail.getMessage(), convertToInetAddr(mail.getRecipients()), targetServers);
- }
-
- private ExecutionResult doDeliver(Mail mail, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException {
- MessagingException lastError = null;
-
- while (targetServers.hasNext()) {
- try {
- if (mailDelivrerToHost.tryDeliveryToHost(mail, message, addr, targetServers.next())) {
- return ExecutionResult.success();
- }
- } catch (SendFailedException sfe) {
- lastError = handleSendFailException(mail, sfe);
- } catch (MessagingException me) {
- lastError = handleMessagingException(mail, me);
- if (configuration.isDebug()) {
- logger.debug(me.getMessage(), me.getCause());
- } else {
- logger.info(me.getMessage());
- }
- }
- }
- // If we encountered an exception while looping through,
- // throw the last MessagingException we caught. We only
- // do this if we were unable to send the message to any
- // server. If sending eventually succeeded, we exit
- // deliver() though the return at the end of the try
- // block.
- if (lastError != null) {
- throw lastError;
- }
- return ExecutionResult.temporaryFailure();
- }
-
- private MessagingException handleMessagingException(Mail mail, MessagingException me) throws MessagingException {
- logger.debug("Exception delivering message (" + mail.getName() + ") - " + me.getMessage());
- if ((me.getNextException() != null) && (me.getNextException() instanceof IOException)) {
- // This is more than likely a temporary failure
-
- // If it's an IO exception with no nested exception, it's probably
- // some socket or weird I/O related problem.
- return me;
- } else {
- // This was not a connection or I/O error particular to one
- // SMTP server of an MX set. Instead, it is almost certainly
- // a protocol level error. In this case we assume that this
- // is an error we'd encounter with any of the SMTP servers
- // associated with this MX record, and we pass the exception
- // to the code in the outer block that determines its
- // severity.
- throw me;
- }
- }
-
- private ExecutionResult handleSenderFailedException(Mail mail, SendFailedException sfe) {
- logSendFailedException(sfe);
-
- // Copy the recipients as direct modification may not be possible
- Collection<MailAddress> recipients = new ArrayList<MailAddress>(mail.getRecipients());
-
- ExecutionResult deleteMessage = ExecutionResult.temporaryFailure();
- EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
-
- /*
- * If you send a message that has multiple invalid addresses, you'll
- * get a top-level SendFailedException that that has the valid,
- * valid-unsent, and invalid address lists, with all of the server
- * response messages will be contained within the nested exceptions.
- * [Note: the content of the nested exceptions is implementation
- * dependent.]
- *
- * sfe.getInvalidAddresses() should be considered permanent.
- * sfe.getValidUnsentAddresses() should be considered temporary.
- *
- * JavaMail v1.3 properly populates those collections based upon the
- * 4xx and 5xx response codes to RCPT TO. Some servers, such as
- * Yahoo! don't respond to the RCPT TO, and provide a 5xx reply
- * after DATA. In that case, we will pick up the failure from
- * SMTPSendFailedException.
- */
-
- /*
- * SMTPSendFailedException introduced in JavaMail 1.3.2, and
- * provides detailed protocol reply code for the operation
- */
- if (enhancedMessagingException.hasReturnCode()) {
- if (enhancedMessagingException.isServerError()) {
- deleteMessage = ExecutionResult.permanentFailure(sfe);
- } else {
- deleteMessage = ExecutionResult.temporaryFailure(sfe);
- }
- }
-
- // log the original set of intended recipients
- if (configuration.isDebug())
- logger.debug("Recipients: " + recipients);
-
- if (sfe.getInvalidAddresses() != null) {
- Address[] address = sfe.getInvalidAddresses();
- if (address.length > 0) {
- recipients.clear();
- for (Address addres : address) {
- try {
- recipients.add(new MailAddress(addres.toString()));
- } catch (ParseException pe) {
- // this should never happen ... we should have
- // caught malformed addresses long before we
- // got to this code.
- logger.debug("Can't parse invalid address: " + pe.getMessage());
- }
- }
- // Set the recipients for the mail
- mail.setRecipients(recipients);
-
- if (configuration.isDebug())
- logger.debug("Invalid recipients: " + recipients);
- deleteMessage = ExecutionResult.permanentFailure(sfe);
- logger.debug(messageComposer.composeFailLogMessage(mail, deleteMessage));
- }
- }
-
- if (sfe.getValidUnsentAddresses() != null) {
- Address[] address = sfe.getValidUnsentAddresses();
- if (address.length > 0) {
- recipients.clear();
- for (Address addres : address) {
- try {
- recipients.add(new MailAddress(addres.toString()));
- } catch (ParseException pe) {
- // this should never happen ... we should have
- // caught malformed addresses long before we
- // got to this code.
- logger.debug("Can't parse unsent address: " + pe.getMessage());
- }
- }
- // Set the recipients for the mail
- mail.setRecipients(recipients);
- if (configuration.isDebug())
- logger.debug("Unsent recipients: " + recipients);
-
- if (enhancedMessagingException.hasReturnCode()) {
- boolean isPermanent = enhancedMessagingException.isServerError();
- deleteMessage = ExecutionResult.onFailure(isPermanent, sfe);
- logger.debug(messageComposer.composeFailLogMessage(mail, deleteMessage));
- } else {
- deleteMessage = ExecutionResult.temporaryFailure(sfe);
- logger.debug(messageComposer.composeFailLogMessage(mail, deleteMessage));
- }
- }
- }
-
-
- return deleteMessage;
- }
-
- private MessagingException handleSendFailException(Mail mail, SendFailedException sfe) throws SendFailedException {
- logSendFailedException(sfe);
-
- if (sfe.getValidSentAddresses() != null) {
- Address[] validSent = sfe.getValidSentAddresses();
- if (validSent.length > 0) {
- logger.debug( "Mail (" + mail.getName() + ") sent successfully for " + Arrays.asList(validSent));
- }
- }
-
- /*
- * SMTPSendFailedException introduced in JavaMail 1.3.2, and
- * provides detailed protocol reply code for the operation
- */
- EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
- if (enhancedMessagingException.isServerError()) {
- throw sfe;
- }
-
- if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) {
- if (configuration.isDebug())
- logger.debug("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers");
- return sfe;
- } else {
- // There are no valid addresses left to send, so rethrow
- throw sfe;
- }
- }
-
- private InternetAddress[] convertToInetAddr(Collection<MailAddress> recipients) {
- InternetAddress addr[] = new InternetAddress[recipients.size()];
- int j = 0;
- for (Iterator<MailAddress> i = recipients.iterator(); i.hasNext(); j++) {
- MailAddress rcpt = i.next();
- addr[j] = rcpt.toInternetAddress();
- }
- return addr;
- }
-
- private ExecutionResult handleTemporaryResolutionException(Mail mail, String host) {
- ExecutionResult executionResult = ExecutionResult.temporaryFailure(new MessagingException("Temporary problem looking " +
- "up mail server for host: " + host + ". I cannot determine where to send this message."));
- logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
- return executionResult;
- }
-
- private ExecutionResult handleNoTargetServer(Mail mail, String host) {
- logger.info("No mail server found for: " + host);
- String exceptionBuffer = "There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.";
-
- MessagingException messagingException = new MessagingException(exceptionBuffer);
- int retry = DeliveryRetriesHelper.retrieveRetries(mail);
- if (retry == 0 || retry > configuration.getDnsProblemRetry()) {
- // The domain has no dns entry.. Return a permanent error
- ExecutionResult executionResult = ExecutionResult.permanentFailure(messagingException);
- logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
- return executionResult;
- } else {
- ExecutionResult executionResult = ExecutionResult.temporaryFailure(messagingException);
- logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
- return executionResult;
- }
- }
-
private long getNextDelay(int retry_count) {
if (retry_count > configuration.getDelayTimes().size()) {
return Delay.DEFAULT_DELAY_TIME;
}
return configuration.getDelayTimes().get(retry_count - 1);
}
-
- private void logSendFailedException(SendFailedException sfe) {
- if (configuration.isDebug()) {
- EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
- if (enhancedMessagingException.hasReturnCode()) {
- logger.debug("SMTP SEND FAILED:");
- logger.debug(sfe.toString());
- logger.debug(" Command: " + enhancedMessagingException.computeCommand());
- logger.debug(" RetCode: " + enhancedMessagingException.getReturnCode());
- logger.debug(" Response: " + sfe.getMessage());
- } else {
- logger.debug("Send failed: " + sfe.toString());
- }
- logLevels(sfe);
- }
- }
-
- private void logLevels(MessagingException me) {
- Exception ne;
- while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
- me = (MessagingException) ne;
- EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(me);
- if (me.getClass().getName().endsWith(".SMTPAddressFailedException") || me.getClass().getName().endsWith(".SMTPAddressSucceededException")) {
- logger.debug("ADDRESS " + enhancedMessagingException.computeAction() + ":");
- logger.debug(me.toString());
- logger.debug(" Address: " + enhancedMessagingException.computeAddress());
- logger.debug(" Command: " + enhancedMessagingException.computeCommand());
- logger.debug(" RetCode: " + enhancedMessagingException.getReturnCode());
- logger.debug(" Response: " + me.getMessage());
- }
- }
- }
-
- /**
- * Returns an Iterator over org.apache.mailet.HostAddress, a specialized
- * subclass of javax.mail.URLName, which provides location information for
- * servers that are specified as mail handlers for the given hostname. If no
- * host is found, the Iterator returned will be empty and the first call to
- * hasNext() will return false. The Iterator is a nested iterator: the outer
- * iteration is over each gateway, and the inner iteration is over
- * potentially multiple A records for each gateway.
- *
- * @param gatewayServers - Collection of host[:port] Strings
- * @return an Iterator over HostAddress instances, sorted by priority
- * @since v2.2.0a16-unstable
- */
- private Iterator<HostAddress> getGatewaySMTPHostAddresses(Collection<String> gatewayServers) {
- return new MXHostAddressIterator(gatewayServers.iterator(), dnsServer, false, logger);
- }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/9790170c/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
new file mode 100644
index 0000000..bcfe330
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
@@ -0,0 +1,399 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.mail.Address;
+import javax.mail.MessagingException;
+import javax.mail.SendFailedException;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.ParseException;
+
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.TemporaryResolutionException;
+import org.apache.james.dnsservice.library.MXHostAddressIterator;
+import org.apache.mailet.HostAddress;
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+import org.slf4j.Logger;
+
+import com.google.common.base.Optional;
+
+public class MailDelivrer {
+
+ private final RemoteDeliveryConfiguration configuration;
+ private final MailDelivrerToHost mailDelivrerToHost;
+ private final DNSService dnsServer;
+ private final MessageComposer messageComposer;
+ private final Logger logger;
+
+ public MailDelivrer(RemoteDeliveryConfiguration configuration, MailDelivrerToHost mailDelivrerToHost, DNSService dnsServer, Logger logger) {
+ this.configuration = configuration;
+ this.mailDelivrerToHost = mailDelivrerToHost;
+ this.dnsServer = dnsServer;
+ this.messageComposer = new MessageComposer(configuration);
+ this.logger = logger;
+ }
+
+ /**
+ * We can assume that the recipients of this message are all going to the
+ * same mail server. We will now rely on the DNS server to do DNS MX record
+ * lookup and try to deliver to the multiple mail servers. If it fails, it
+ * should throw an exception.
+ *
+ * @param mail org.apache.james.core.MailImpl
+ * @param session javax.mail.Session
+ * @return boolean Whether the delivery was successful and the message can
+ * be deleted
+ */
+ public ExecutionResult deliver(Mail mail) {
+ try {
+ return tryDeliver(mail);
+ } catch (SendFailedException sfe) {
+ return handleSenderFailedException(mail, sfe);
+ } catch (MessagingException ex) {
+ // We should do a better job checking this... if the failure is a general
+ // connect exception, this is less descriptive than more specific SMTP command
+ // failure... have to lookup and see what are the various Exception possibilities
+
+ // Unable to deliver message after numerous tries... fail accordingly
+
+ // We check whether this is a 5xx error message, which indicates a permanent failure (like account doesn't exist
+ // or mailbox is full or domain is setup wrong). We fail permanently if this was a 5xx error
+
+ boolean isPermanent = '5' == ex.getMessage().charAt(0);
+ ExecutionResult executionResult = ExecutionResult.onFailure(isPermanent, ex);
+ logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
+ return executionResult;
+ } catch (Exception ex) {
+ logger.error("Generic exception = permanent failure: " + ex.getMessage(), ex);
+ // Generic exception = permanent failure
+ ExecutionResult executionResult = ExecutionResult.permanentFailure(ex);
+ logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
+ return executionResult;
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ private ExecutionResult tryDeliver(Mail mail) throws MessagingException {
+ if (mail.getRecipients().isEmpty()) {
+ logger.info("No recipients specified... not sure how this could have happened.");
+ return ExecutionResult.permanentFailure(new Exception("No recipients specified for " + mail.getName() + " sent by " + mail.getSender()));
+ }
+ if (configuration.isDebug()) {
+ logger.debug("Attempting to deliver " + mail.getName());
+ }
+
+ // Figure out which servers to try to send to. This collection
+ // will hold all the possible target servers
+ Iterator<HostAddress> targetServers;
+ if (configuration.getGatewayServer().isEmpty()) {
+ MailAddress rcpt = mail.getRecipients().iterator().next();
+ String host = rcpt.getDomain();
+
+ // Lookup the possible targets
+ try {
+ targetServers = new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logger);
+ } catch (TemporaryResolutionException e) {
+ return handleTemporaryResolutionException(mail, host);
+ }
+ if (!targetServers.hasNext()) {
+ return handleNoTargetServer(mail, host);
+ }
+ } else {
+ targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer());
+ }
+
+ return doDeliver(mail, mail.getMessage(), convertToInetAddr(mail.getRecipients()), targetServers);
+ }
+
+ @SuppressWarnings("deprecation")
+ private ExecutionResult doDeliver(Mail mail, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException {
+ MessagingException lastError = null;
+
+ while (targetServers.hasNext()) {
+ try {
+ if (mailDelivrerToHost.tryDeliveryToHost(mail, message, addr, targetServers.next())) {
+ return ExecutionResult.success();
+ }
+ } catch (SendFailedException sfe) {
+ lastError = handleSendFailException(mail, sfe);
+ } catch (MessagingException me) {
+ lastError = handleMessagingException(mail, me);
+ if (configuration.isDebug()) {
+ logger.debug(me.getMessage(), me.getCause());
+ } else {
+ logger.info(me.getMessage());
+ }
+ }
+ }
+ // If we encountered an exception while looping through,
+ // throw the last MessagingException we caught. We only
+ // do this if we were unable to send the message to any
+ // server. If sending eventually succeeded, we exit
+ // deliver() though the return at the end of the try
+ // block.
+ if (lastError != null) {
+ throw lastError;
+ }
+ return ExecutionResult.temporaryFailure();
+ }
+
+ private MessagingException handleMessagingException(Mail mail, MessagingException me) throws MessagingException {
+ logger.debug("Exception delivering message (" + mail.getName() + ") - " + me.getMessage());
+ if ((me.getNextException() != null) && (me.getNextException() instanceof IOException)) {
+ // This is more than likely a temporary failure
+
+ // If it's an IO exception with no nested exception, it's probably
+ // some socket or weird I/O related problem.
+ return me;
+ } else {
+ // This was not a connection or I/O error particular to one
+ // SMTP server of an MX set. Instead, it is almost certainly
+ // a protocol level error. In this case we assume that this
+ // is an error we'd encounter with any of the SMTP servers
+ // associated with this MX record, and we pass the exception
+ // to the code in the outer block that determines its
+ // severity.
+ throw me;
+ }
+ }
+
+ private ExecutionResult handleSenderFailedException(Mail mail, SendFailedException sfe) {
+ logSendFailedException(sfe);
+
+ // Copy the recipients as direct modification may not be possible
+ Collection<MailAddress> recipients = new ArrayList<MailAddress>(mail.getRecipients());
+
+ ExecutionResult deleteMessage = ExecutionResult.temporaryFailure();
+ EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
+
+ /*
+ * If you send a message that has multiple invalid addresses, you'll
+ * get a top-level SendFailedException that that has the valid,
+ * valid-unsent, and invalid address lists, with all of the server
+ * response messages will be contained within the nested exceptions.
+ * [Note: the content of the nested exceptions is implementation
+ * dependent.]
+ *
+ * sfe.getInvalidAddresses() should be considered permanent.
+ * sfe.getValidUnsentAddresses() should be considered temporary.
+ *
+ * JavaMail v1.3 properly populates those collections based upon the
+ * 4xx and 5xx response codes to RCPT TO. Some servers, such as
+ * Yahoo! don't respond to the RCPT TO, and provide a 5xx reply
+ * after DATA. In that case, we will pick up the failure from
+ * SMTPSendFailedException.
+ */
+
+ /*
+ * SMTPSendFailedException introduced in JavaMail 1.3.2, and
+ * provides detailed protocol reply code for the operation
+ */
+ if (enhancedMessagingException.hasReturnCode() || enhancedMessagingException.hasNestedReturnCode()) {
+ if (enhancedMessagingException.isServerError()) {
+ deleteMessage = ExecutionResult.permanentFailure(sfe);
+ } else {
+ deleteMessage = ExecutionResult.temporaryFailure(sfe);
+ }
+ }
+
+ // log the original set of intended recipients
+ if (configuration.isDebug())
+ logger.debug("Recipients: " + recipients);
+
+ if (sfe.getInvalidAddresses() != null) {
+ Address[] address = sfe.getInvalidAddresses();
+ if (address.length > 0) {
+ recipients.clear();
+ for (Address addres : address) {
+ try {
+ recipients.add(new MailAddress(addres.toString()));
+ } catch (ParseException pe) {
+ // this should never happen ... we should have
+ // caught malformed addresses long before we
+ // got to this code.
+ logger.debug("Can't parse invalid address: " + pe.getMessage());
+ }
+ }
+ // Set the recipients for the mail
+ mail.setRecipients(recipients);
+
+ if (configuration.isDebug())
+ logger.debug("Invalid recipients: " + recipients);
+ deleteMessage = ExecutionResult.permanentFailure(sfe);
+ logger.debug(messageComposer.composeFailLogMessage(mail, deleteMessage));
+ }
+ }
+
+ if (sfe.getValidUnsentAddresses() != null) {
+ Address[] address = sfe.getValidUnsentAddresses();
+ if (address.length > 0) {
+ recipients.clear();
+ for (Address addres : address) {
+ try {
+ recipients.add(new MailAddress(addres.toString()));
+ } catch (ParseException pe) {
+ // this should never happen ... we should have
+ // caught malformed addresses long before we
+ // got to this code.
+ logger.debug("Can't parse unsent address: " + pe.getMessage());
+ }
+ }
+ // Set the recipients for the mail
+ mail.setRecipients(recipients);
+ if (configuration.isDebug())
+ logger.debug("Unsent recipients: " + recipients);
+
+ if (enhancedMessagingException.hasReturnCode()) {
+ boolean isPermanent = enhancedMessagingException.isServerError();
+ deleteMessage = ExecutionResult.onFailure(isPermanent, sfe);
+ logger.debug(messageComposer.composeFailLogMessage(mail, deleteMessage));
+ } else {
+ deleteMessage = ExecutionResult.temporaryFailure(sfe);
+ logger.debug(messageComposer.composeFailLogMessage(mail, deleteMessage));
+ }
+ }
+ }
+
+
+ return deleteMessage;
+ }
+
+ private MessagingException handleSendFailException(Mail mail, SendFailedException sfe) throws SendFailedException {
+ logSendFailedException(sfe);
+
+ if (sfe.getValidSentAddresses() != null) {
+ Address[] validSent = sfe.getValidSentAddresses();
+ if (validSent.length > 0) {
+ logger.debug( "Mail (" + mail.getName() + ") sent successfully for " + Arrays.asList(validSent));
+ }
+ }
+
+ /*
+ * SMTPSendFailedException introduced in JavaMail 1.3.2, and
+ * provides detailed protocol reply code for the operation
+ */
+ EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
+ if (enhancedMessagingException.isServerError()) {
+ throw sfe;
+ }
+
+ if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) {
+ if (configuration.isDebug())
+ logger.debug("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers");
+ return sfe;
+ } else {
+ // There are no valid addresses left to send, so rethrow
+ throw sfe;
+ }
+ }
+
+ private InternetAddress[] convertToInetAddr(Collection<MailAddress> recipients) {
+ InternetAddress addr[] = new InternetAddress[recipients.size()];
+ int j = 0;
+ for (Iterator<MailAddress> i = recipients.iterator(); i.hasNext(); j++) {
+ MailAddress rcpt = i.next();
+ addr[j] = rcpt.toInternetAddress();
+ }
+ return addr;
+ }
+
+ private ExecutionResult handleTemporaryResolutionException(Mail mail, String host) {
+ ExecutionResult executionResult = ExecutionResult.temporaryFailure(new MessagingException("Temporary problem looking " +
+ "up mail server for host: " + host + ". I cannot determine where to send this message."));
+ logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
+ return executionResult;
+ }
+
+ private ExecutionResult handleNoTargetServer(Mail mail, String host) {
+ logger.info("No mail server found for: " + host);
+ String exceptionBuffer = "There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.";
+
+ MessagingException messagingException = new MessagingException(exceptionBuffer);
+ int retry = DeliveryRetriesHelper.retrieveRetries(mail);
+ if (retry == 0 || retry > configuration.getDnsProblemRetry()) {
+ // The domain has no dns entry.. Return a permanent error
+ ExecutionResult executionResult = ExecutionResult.permanentFailure(messagingException);
+ logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
+ return executionResult;
+ } else {
+ ExecutionResult executionResult = ExecutionResult.temporaryFailure(messagingException);
+ logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
+ return executionResult;
+ }
+ }
+
+ /**
+ * Returns an Iterator over org.apache.mailet.HostAddress, a specialized
+ * subclass of javax.mail.URLName, which provides location information for
+ * servers that are specified as mail handlers for the given hostname. If no
+ * host is found, the Iterator returned will be empty and the first call to
+ * hasNext() will return false. The Iterator is a nested iterator: the outer
+ * iteration is over each gateway, and the inner iteration is over
+ * potentially multiple A records for each gateway.
+ *
+ * @param gatewayServers - Collection of host[:port] Strings
+ * @return an Iterator over HostAddress instances, sorted by priority
+ * @since v2.2.0a16-unstable
+ */
+ @SuppressWarnings("deprecation")
+ private Iterator<HostAddress> getGatewaySMTPHostAddresses(Collection<String> gatewayServers) {
+ return new MXHostAddressIterator(gatewayServers.iterator(), dnsServer, false, logger);
+ }
+
+ private void logSendFailedException(SendFailedException sfe) {
+ if (configuration.isDebug()) {
+ EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
+ if (enhancedMessagingException.hasReturnCode()) {
+ logger.debug("SMTP SEND FAILED:");
+ logger.debug(sfe.toString());
+ logger.debug(" Command: " + enhancedMessagingException.computeCommand());
+ logger.debug(" RetCode: " + enhancedMessagingException.getReturnCode());
+ logger.debug(" Response: " + sfe.getMessage());
+ } else {
+ logger.debug("Send failed: " + sfe.toString());
+ }
+ logLevels(sfe);
+ }
+ }
+
+ private void logLevels(MessagingException me) {
+ Exception ne;
+ while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
+ me = (MessagingException) ne;
+ EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(me);
+ if (me.getClass().getName().endsWith(".SMTPAddressFailedException") || me.getClass().getName().endsWith(".SMTPAddressSucceededException")) {
+ logger.debug("ADDRESS " + enhancedMessagingException.computeAction() + ":");
+ logger.debug(me.toString());
+ logger.debug(" Address: " + enhancedMessagingException.computeAddress());
+ logger.debug(" Command: " + enhancedMessagingException.computeCommand());
+ logger.debug(" RetCode: " + enhancedMessagingException.getReturnCode());
+ logger.debug(" Response: " + me.getMessage());
+ }
+ }
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[30/50] [abbrv] james-project git commit: JAMES-1877 Simplify
handleMessagingException of DeliveryRunnable
Posted by ro...@apache.org.
JAMES-1877 Simplify handleMessagingException of DeliveryRunnable
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/1467986e
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/1467986e
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/1467986e
Branch: refs/heads/master
Commit: 1467986ea395c04603b02ac09c692cc99745daca
Parents: f567a5a
Author: Benoit Tellier <bt...@linagora.com>
Authored: Fri Dec 2 10:26:14 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:51 2017 +0700
----------------------------------------------------------------------
.../james/transport/mailets/remoteDelivery/DeliveryRunnable.java | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/1467986e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index 37ae531..6317209 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -266,14 +266,13 @@ public class DeliveryRunnable implements Runnable {
}
private MessagingException handleMessagingException(Mail mail, MessagingException me) throws MessagingException {
- MessagingException lastError;// MessagingException are horribly difficult to figure out what actually happened.
logger.debug("Exception delivering message (" + mail.getName() + ") - " + me.getMessage());
if ((me.getNextException() != null) && (me.getNextException() instanceof IOException)) {
// This is more than likely a temporary failure
// If it's an IO exception with no nested exception, it's probably
// some socket or weird I/O related problem.
- lastError = me;
+ return me;
} else {
// This was not a connection or I/O error particular to one
// SMTP server of an MX set. Instead, it is almost certainly
@@ -284,7 +283,6 @@ public class DeliveryRunnable implements Runnable {
// severity.
throw me;
}
- return lastError;
}
private ExecutionResult handleSenderFailedException(Mail mail, SendFailedException sfe) {
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[24/50] [abbrv] james-project git commit: JAMES-1877 Adding an
enumeration for keeping track of the status of Delivery
Posted by ro...@apache.org.
JAMES-1877 Adding an enumeration for keeping track of the status of Delivery
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/c8a3dd97
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/c8a3dd97
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/c8a3dd97
Branch: refs/heads/master
Commit: c8a3dd97832007bf7403b8670b5ce499efc94ff1
Parents: f5fc475
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 1 17:30:55 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:50 2017 +0700
----------------------------------------------------------------------
.../remoteDelivery/DeliveryRunnable.java | 115 ++++++++++++++-----
1 file changed, 88 insertions(+), 27 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/c8a3dd97/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index f6763ef..45169a1 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -57,6 +57,58 @@ import com.sun.mail.smtp.SMTPTransport;
@SuppressWarnings("deprecation")
public class DeliveryRunnable implements Runnable {
+ private static ExecutionResult success() {
+ return new ExecutionResult(ExecutionState.SUCCESS, Optional.<Exception>absent());
+ }
+
+ private static ExecutionResult temporaryFailure(Exception e) {
+ return new ExecutionResult(ExecutionState.TEMPORARY_FAILURE, Optional.of(e));
+ }
+
+ private static ExecutionResult permanentFailure(Exception e) {
+ return new ExecutionResult(ExecutionState.PERMANENT_FAILURE, Optional.of(e));
+ }
+
+ private static ExecutionResult temporaryFailure() {
+ return new ExecutionResult(ExecutionState.TEMPORARY_FAILURE, Optional.<Exception>absent());
+ }
+
+ private static ExecutionResult permanentFailure() {
+ return new ExecutionResult(ExecutionState.PERMANENT_FAILURE, Optional.<Exception>absent());
+ }
+
+ private static class ExecutionResult {
+ private final ExecutionState executionState;
+ private final Optional<Exception> exception;
+
+ public ExecutionResult(ExecutionState executionState, Optional<Exception> exception) {
+ this.executionState = executionState;
+ this.exception = exception;
+ }
+
+ public ExecutionState getExecutionState() {
+ return executionState;
+ }
+
+ public Optional<Exception> getException() {
+ return exception;
+ }
+ }
+
+ private enum ExecutionState {
+ SUCCESS,
+ PERMANENT_FAILURE,
+ TEMPORARY_FAILURE
+ }
+
+ private static ExecutionResult onFailure(boolean permanent, Exception exeption) {
+ if (permanent) {
+ return permanentFailure(exeption);
+ } else {
+ return temporaryFailure(exeption);
+ }
+ }
+
public static final boolean PERMANENT_FAILURE = true;
public static final String BIT_MIME_8 = "8BITMIME";
private final MailQueue queue;
@@ -128,15 +180,25 @@ public class DeliveryRunnable implements Runnable {
}
private void attemptDelivery(Session session, Mail mail) throws MailQueue.MailQueueException {
- if (!deliver(mail, session)) {
- // Something happened that will delay delivery. Store it back in the retry repository.
- long delay = getNextDelay(DeliveryRetriesHelper.retrieveRetries(mail));
-
- if (configuration.isUsePriority()) {
- // Use lowest priority for retries. See JAMES-1311
- mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY);
- }
- queue.enQueue(mail, delay, TimeUnit.MILLISECONDS);
+ ExecutionResult executionResult = deliver(mail, session);
+ switch (executionResult.getExecutionState()) {
+ case SUCCESS:
+ outgoingMailsMetric.increment();
+ break;
+ case TEMPORARY_FAILURE:
+ // TODO move the incrementing of retries here instead of in fail message
+ // Something happened that will delay delivery. Store it back in the retry repository.
+ long delay = getNextDelay(DeliveryRetriesHelper.retrieveRetries(mail));
+
+ if (configuration.isUsePriority()) {
+ // Use lowest priority for retries. See JAMES-1311
+ mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY);
+ }
+ queue.enQueue(mail, delay, TimeUnit.MILLISECONDS);
+ break;
+ case PERMANENT_FAILURE:
+ // TODO move boucing logic here
+ break;
}
}
@@ -151,7 +213,7 @@ public class DeliveryRunnable implements Runnable {
* @return boolean Whether the delivery was successful and the message can
* be deleted
*/
- private boolean deliver(Mail mail, Session session) {
+ private ExecutionResult deliver(Mail mail, Session session) {
try {
return Optional.fromNullable(tryDeliver(mail, session))
.or(failMessage(mail, new MessagingException("No mail server(s) available at this time."), false));
@@ -180,10 +242,10 @@ public class DeliveryRunnable implements Runnable {
}
}
- private Boolean tryDeliver(Mail mail, Session session) throws MessagingException {
+ private ExecutionResult tryDeliver(Mail mail, Session session) throws MessagingException {
if (mail.getRecipients().isEmpty()) {
logger.info("No recipients specified... not sure how this could have happened.");
- return true;
+ return permanentFailure(new Exception("No recipients specified for " + mail.getName() + " sent by " + mail.getSender()));
}
if (configuration.isDebug()) {
logger.debug("Attempting to deliver " + mail.getName());
@@ -212,20 +274,20 @@ public class DeliveryRunnable implements Runnable {
return doDeliver(mail, session, mail.getMessage(), convertToInetAddr(mail.getRecipients()), targetServers);
}
- private Boolean doDeliver(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException {
+ private ExecutionResult doDeliver(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException {
MessagingException lastError = null;
while (targetServers.hasNext()) {
try {
if (tryDeliveryToHost(mail, session, message, addr, targetServers.next())) {
- return true;
+ return success();
}
} catch (SendFailedException sfe) {
lastError = handleSendFailException(mail, sfe);
} catch (MessagingException me) {
lastError = handleMessagingException(mail, me);
}
- } // end while
+ }
// If we encountered an exception while looping through,
// throw the last MessagingException we caught. We only
// do this if we were unable to send the message to any
@@ -235,7 +297,7 @@ public class DeliveryRunnable implements Runnable {
if (lastError != null) {
throw lastError;
}
- return null;
+ return temporaryFailure();
}
private boolean tryDeliveryToHost(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException {
@@ -269,7 +331,6 @@ public class DeliveryRunnable implements Runnable {
success = true;
logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() +
" at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients());
- outgoingMailsMetric.increment();
} finally {
closeTransport(mail, outgoingMailServer, transport);
}
@@ -298,13 +359,13 @@ public class DeliveryRunnable implements Runnable {
return lastError;
}
- private boolean handleSenderFailedException(Mail mail, SendFailedException sfe) {
+ private ExecutionResult handleSenderFailedException(Mail mail, SendFailedException sfe) {
logSendFailedException(sfe);
// Copy the recipients as direct modification may not be possible
Collection<MailAddress> recipients = new ArrayList<MailAddress>(mail.getRecipients());
- boolean deleteMessage = false;
+ ExecutionResult deleteMessage = temporaryFailure();
/*
* If you send a message that has multiple invalid addresses, you'll
@@ -333,7 +394,7 @@ public class DeliveryRunnable implements Runnable {
int returnCode = (Integer) invokeGetter(sfe, "getReturnCode");
// If we got an SMTPSendFailedException, use its RetCode to
// determine default permanent/temporary failure
- deleteMessage = (returnCode >= 500 && returnCode <= 599);
+ deleteMessage = onFailure(returnCode >= 500 && returnCode <= 599, sfe);
} else {
// Sometimes we'll get a normal SendFailedException with
// nested SMTPAddressFailedException, so use the latter
@@ -344,7 +405,7 @@ public class DeliveryRunnable implements Runnable {
me = (MessagingException) ne;
if (me.getClass().getName().endsWith(".SMTPAddressFailedException")) {
int returnCode = (Integer) invokeGetter(me, "getReturnCode");
- deleteMessage = (returnCode >= 500 && returnCode <= 599);
+ deleteMessage = onFailure(returnCode >= 500 && returnCode <= 599, sfe);
}
}
}
@@ -531,7 +592,7 @@ public class DeliveryRunnable implements Runnable {
}
}
- private boolean handleTemporaryResolutionException(Mail mail, String host) {
+ private ExecutionResult handleTemporaryResolutionException(Mail mail, String host) {
logger.info("Temporary problem looking up mail server for host: " + host);
// temporary problems
return failMessage(mail,
@@ -539,7 +600,7 @@ public class DeliveryRunnable implements Runnable {
false);
}
- private boolean handleNoTargetServer(Mail mail, String host) {
+ private ExecutionResult handleNoTargetServer(Mail mail, String host) {
logger.info("No mail server found for: " + host);
String exceptionBuffer = "There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.";
@@ -632,7 +693,7 @@ public class DeliveryRunnable implements Runnable {
* @param permanent
* @return boolean Whether the message failed fully and can be deleted
*/
- private boolean failMessage(Mail mail, Exception ex, boolean permanent) {
+ private ExecutionResult failMessage(Mail mail, Exception ex, boolean permanent) {
logger.debug(messageComposer.composeFailLogMessage(mail, ex, permanent));
if (!permanent) {
if (!mail.getState().equals(Mail.ERROR)) {
@@ -647,7 +708,7 @@ public class DeliveryRunnable implements Runnable {
logger.debug("Storing message " + mail.getName() + " into outgoing after " + retries + " retries");
DeliveryRetriesHelper.incrementRetries(mail);
mail.setLastUpdated(new Date());
- return false;
+ return temporaryFailure();
} else {
logger.debug("Bouncing message " + mail.getName() + " after " + retries + " retries");
}
@@ -655,7 +716,7 @@ public class DeliveryRunnable implements Runnable {
if (mail.getSender() == null) {
logger.debug("Null Sender: no bounce will be generated for " + mail.getName());
- return true;
+ return permanentFailure(ex);
}
if (configuration.getBounceProcessor() != null) {
@@ -674,7 +735,7 @@ public class DeliveryRunnable implements Runnable {
// do an old style bounce
bounce(mail, ex);
}
- return true;
+ return permanentFailure(ex);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[46/50] [abbrv] james-project git commit: JAMES-1877 Provide tests
for DNS error handling
Posted by ro...@apache.org.
JAMES-1877 Provide tests for DNS error handling
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/9898e18e
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/9898e18e
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/9898e18e
Branch: refs/heads/master
Commit: 9898e18e475c7a672ba8e88c8fa4c1504d3c2531
Parents: 70ad233
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Dec 7 10:53:01 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 18:14:27 2017 +0700
----------------------------------------------------------------------
.../mailets/remoteDelivery/MailDelivrer.java | 33 +++---
.../remoteDelivery/MailDelivrerTest.java | 109 ++++++++++++++++++-
2 files changed, 119 insertions(+), 23 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/9898e18e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
index e6f1ec3..27f66aa 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
@@ -49,11 +49,16 @@ public class MailDelivrer {
private final Logger logger;
public MailDelivrer(RemoteDeliveryConfiguration configuration, MailDelivrerToHost mailDelivrerToHost, DNSService dnsServer, Bouncer bouncer, Logger logger) {
+ this(configuration, mailDelivrerToHost, new DnsHelper(dnsServer, configuration, logger), bouncer, logger);
+ }
+
+ @VisibleForTesting
+ MailDelivrer(RemoteDeliveryConfiguration configuration, MailDelivrerToHost mailDelivrerToHost, DnsHelper dnsHelper, Bouncer bouncer, Logger logger) {
this.configuration = configuration;
this.mailDelivrerToHost = mailDelivrerToHost;
- this.bouncer = bouncer;
- this.dnsHelper = new DnsHelper(dnsServer, configuration, logger);
+ this.dnsHelper = dnsHelper;
this.messageComposer = new MessageComposer(configuration);
+ this.bouncer = bouncer;
this.logger = logger;
}
@@ -116,7 +121,8 @@ public class MailDelivrer {
}
return doDeliver(mail, mail.getMessage(), InternetAddressConverter.convert(mail.getRecipients()), targetServers);
} catch (TemporaryResolutionException e) {
- return handleTemporaryResolutionException(mail, host);
+ return logAndReturn(mail, ExecutionResult.temporaryFailure(new MessagingException("Temporary problem looking " +
+ "up mail server for host: " + host + ". I cannot determine where to send this message.")));
}
}
@@ -252,28 +258,15 @@ public class MailDelivrer {
}
}
- private ExecutionResult handleTemporaryResolutionException(Mail mail, String host) {
- ExecutionResult executionResult = ExecutionResult.temporaryFailure(new MessagingException("Temporary problem looking " +
- "up mail server for host: " + host + ". I cannot determine where to send this message."));
- logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
- return executionResult;
- }
-
private ExecutionResult handleNoTargetServer(Mail mail, String host) {
logger.info("No mail server found for: " + host);
- String exceptionBuffer = "There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.";
-
- MessagingException messagingException = new MessagingException(exceptionBuffer);
+ MessagingException messagingException = new MessagingException("There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.");
int retry = DeliveryRetriesHelper.retrieveRetries(mail);
+ System.out.println("retyry " + retry);
if (retry == 0 || retry > configuration.getDnsProblemRetry()) {
- // The domain has no dns entry.. Return a permanent error
- ExecutionResult executionResult = ExecutionResult.permanentFailure(messagingException);
- logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
- return executionResult;
+ return logAndReturn(mail, ExecutionResult.permanentFailure(messagingException));
} else {
- ExecutionResult executionResult = ExecutionResult.temporaryFailure(messagingException);
- logger.debug(messageComposer.composeFailLogMessage(mail, executionResult));
- return executionResult;
+ return logAndReturn(mail, ExecutionResult.temporaryFailure(messagingException));
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/9898e18e/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
index 477d945..27de817 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerTest.java
@@ -19,24 +19,31 @@
package org.apache.james.transport.mailets.remoteDelivery;
-import static org.mockito.Mockito.mock;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
import javax.mail.Address;
import javax.mail.SendFailedException;
import javax.mail.internet.InternetAddress;
-import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.TemporaryResolutionException;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.mailet.HostAddress;
import org.apache.mailet.Mail;
import org.apache.mailet.base.MailAddressFixture;
import org.apache.mailet.base.test.FakeMail;
+import org.apache.mailet.base.test.FakeMailetConfig;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.UnmodifiableIterator;
import com.sun.mail.smtp.SMTPSenderFailedException;
public class MailDelivrerTest {
@@ -44,11 +51,13 @@ public class MailDelivrerTest {
private MailDelivrer testee;
private Bouncer bouncer;
+ private DnsHelper dnsHelper;
@Before
public void setUp() {
bouncer = mock(Bouncer.class);
- testee = new MailDelivrer(mock(RemoteDeliveryConfiguration.class), mock(MailDelivrerToHost.class), mock(DNSService.class), bouncer, LOGGER);
+ dnsHelper = mock(DnsHelper.class);
+ testee = new MailDelivrer(mock(RemoteDeliveryConfiguration.class), mock(MailDelivrerToHost.class), dnsHelper, bouncer, LOGGER);
}
@Test
@@ -200,4 +209,98 @@ public class MailDelivrerTest {
verify(bouncer).bounce(mail, sfe);
verifyNoMoreInteractions(bouncer);
}
+
+ @Test
+ public void deliverShouldReturnTemporaryFailureOnTemporaryResolutionException() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+
+ when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenThrow(new TemporaryResolutionException());
+
+ ExecutionResult executionResult = testee.deliver(mail);
+
+ assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.TEMPORARY_FAILURE);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ @Ignore("Fails if first delivery attempt")
+ public void deliverShouldReturnTemporaryErrorWhenFirstDNSProblem() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "3")
+ .build();
+ testee = new MailDelivrer(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)), mock(MailDelivrerToHost.class), dnsHelper, bouncer, LOGGER);
+
+ UnmodifiableIterator<HostAddress> empty = ImmutableList.<HostAddress>of().iterator();
+ when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(empty);
+
+ ExecutionResult executionResult = testee.deliver(mail);
+
+ assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.TEMPORARY_FAILURE);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void deliverShouldReturnTemporaryErrorWhenToleratedDNSProblem() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "3")
+ .build();
+ DeliveryRetriesHelper.incrementRetries(mail);
+ testee = new MailDelivrer(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)), mock(MailDelivrerToHost.class), dnsHelper, bouncer, LOGGER);
+
+ UnmodifiableIterator<HostAddress> empty = ImmutableList.<HostAddress>of().iterator();
+ when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(empty);
+
+ ExecutionResult executionResult = testee.deliver(mail);
+
+ assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.TEMPORARY_FAILURE);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ @Ignore("One more failure is tolerated than specified by the configuration")
+ public void deliverShouldReturnPermanentErrorWhenLimitDNSProblemReached() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "3")
+ .build();
+ DeliveryRetriesHelper.incrementRetries(mail);
+ DeliveryRetriesHelper.incrementRetries(mail);
+ DeliveryRetriesHelper.incrementRetries(mail);
+ testee = new MailDelivrer(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)), mock(MailDelivrerToHost.class), dnsHelper, bouncer, LOGGER);
+
+ UnmodifiableIterator<HostAddress> empty = ImmutableList.<HostAddress>of().iterator();
+ when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(empty);
+
+ ExecutionResult executionResult = testee.deliver(mail);
+
+ assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.PERMANENT_FAILURE);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void deliverShouldReturnPermanentErrorWhenLimitDNSProblemExceeded() throws Exception {
+ Mail mail = FakeMail.builder().recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES).build();
+ FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
+ .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1")
+ .setProperty(RemoteDeliveryConfiguration.MAX_DNS_PROBLEM_RETRIES, "3")
+ .build();
+ DeliveryRetriesHelper.incrementRetries(mail);
+ DeliveryRetriesHelper.incrementRetries(mail);
+ DeliveryRetriesHelper.incrementRetries(mail);
+ DeliveryRetriesHelper.incrementRetries(mail);
+ testee = new MailDelivrer(new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)), mock(MailDelivrerToHost.class), dnsHelper, bouncer, LOGGER);
+
+ UnmodifiableIterator<HostAddress> empty = ImmutableList.<HostAddress>of().iterator();
+ when(dnsHelper.retrieveHostAddressIterator(MailAddressFixture.JAMES_APACHE_ORG)).thenReturn(empty);
+
+ ExecutionResult executionResult = testee.deliver(mail);
+
+ assertThat(executionResult.getExecutionState()).isEqualTo(ExecutionResult.ExecutionState.PERMANENT_FAILURE);
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[04/50] [abbrv] james-project git commit: JAMES-1877 Extract Delay
Posted by ro...@apache.org.
JAMES-1877 Extract Delay
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/1193b6b4
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/1193b6b4
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/1193b6b4
Branch: refs/heads/master
Commit: 1193b6b4a542a0cd61bd2e7b74567b3a92207554
Parents: 03fc53a
Author: Benoit Tellier <bt...@linagora.com>
Authored: Tue Nov 29 10:56:27 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 14:35:31 2017 +0700
----------------------------------------------------------------------
.../james/transport/mailets/RemoteDelivery.java | 118 +------------
.../transport/mailets/remoteDelivery/Delay.java | 166 +++++++++++++++++++
.../mailets/remoteDelivery/DelayTest.java | 96 +++++++++++
3 files changed, 264 insertions(+), 116 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/1193b6b4/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index 89a4987..b23f79d 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -39,8 +39,6 @@ import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.mail.Address;
@@ -65,10 +63,9 @@ import org.apache.james.queue.api.MailQueue;
import org.apache.james.queue.api.MailQueue.MailQueueException;
import org.apache.james.queue.api.MailQueue.MailQueueItem;
import org.apache.james.queue.api.MailQueueFactory;
+import org.apache.james.transport.mailets.remoteDelivery.Delay;
import org.apache.james.transport.mailets.remoteDelivery.HeloNameProvider;
import org.apache.james.transport.mailets.remoteDelivery.RemoteDeliverySocketFactory;
-import org.apache.james.transport.util.Patterns;
-import org.apache.james.util.TimeConverter;
import org.apache.mailet.HostAddress;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
@@ -151,17 +148,6 @@ import com.sun.mail.smtp.SMTPTransport;
@SuppressWarnings("deprecation")
public class RemoteDelivery extends GenericMailet implements Runnable {
- /**
- * Default Delay Time (Default is 6*60*60*1000 Milliseconds (6 hours)).
- */
- private static final long DEFAULT_DELAY_TIME = 21600000;
-
- /**
- * Pattern to match [attempts*]delay[units].
- */
- private static final String PATTERN_STRING = "\\s*([0-9]*\\s*[\\*])?\\s*([0-9]+)\\s*([a-z,A-Z]*)\\s*";
-
- private static final Pattern PATTERN = Patterns.compilePatternUncheckedException(PATTERN_STRING);
private static final String OUTGOING_MAILS = "outgoingMails";
private final DNSService dnsServer;
@@ -502,111 +488,11 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
*/
private long getNextDelay(int retry_count) {
if (retry_count > delayTimes.length) {
- return DEFAULT_DELAY_TIME;
+ return Delay.DEFAULT_DELAY_TIME;
}
return delayTimes[retry_count - 1];
}
- /**
- * This class is used to hold a delay time and its corresponding number of
- * retries.
- */
- private final static class Delay {
- private int attempts = 1;
-
- private long delayTime = DEFAULT_DELAY_TIME;
-
- /**
- * <p>
- * This constructor expects Strings of the form
- * "[attempt\*]delaytime[unit]".
- * </p>
- * <p>
- * The optional attempt is the number of tries this delay should be used
- * (default = 1). The unit, if present, must be one of
- * (msec,sec,minute,hour,day). The default value of unit is 'msec'.
- * </p>
- * <p>
- * The constructor multiplies the delaytime by the relevant multiplier
- * for the unit, so the delayTime instance variable is always in msec.
- * </p>
- *
- * @param initString the string to initialize this Delay object from
- */
- public Delay(String initString) throws MessagingException {
- // Default unit value to 'msec'.
- String unit = "msec";
-
- Matcher res = PATTERN.matcher(initString);
- if (res.matches()) {
- // The capturing groups will now hold:
- // at 1: attempts * (if present)
- // at 2: delaytime
- // at 3: unit (if present)
- if (res.group(1) != null && !res.group(1).equals("")) {
- // We have an attempt *
- String attemptMatch = res.group(1);
-
- // Strip the * and whitespace.
- attemptMatch = attemptMatch.substring(0, attemptMatch.length() - 1).trim();
- attempts = Integer.parseInt(attemptMatch);
- }
-
- delayTime = Long.parseLong(res.group(2));
-
- if (!res.group(3).equals("")) {
- // We have a value for 'unit'.
- unit = res.group(3).toLowerCase(Locale.US);
- }
- } else {
- throw new MessagingException(initString + " does not match " + PATTERN_STRING);
- }
-
- // calculate delayTime.
- try {
- delayTime = TimeConverter.getMilliSeconds(delayTime, unit);
- } catch (NumberFormatException e) {
- throw new MessagingException(e.getMessage());
- }
- }
-
- /**
- * This constructor makes a default Delay object with attempts = 1 and
- * delayTime = DEFAULT_DELAY_TIME.
- */
- public Delay() {
- }
-
- /**
- * @return the delayTime for this Delay
- */
- public long getDelayTime() {
- return delayTime;
- }
-
- /**
- * @return the number attempts this Delay should be used.
- */
- public int getAttempts() {
- return attempts;
- }
-
- /**
- * Set the number attempts this Delay should be used.
- */
- public void setAttempts(int value) {
- attempts = value;
- }
-
- /**
- * Pretty prints this Delay
- */
- @Override
- public String toString() {
- return getAttempts() + "*" + getDelayTime() + "msecs";
- }
- }
-
@Override
public String getMailetInfo() {
return "RemoteDelivery Mailet";
http://git-wip-us.apache.org/repos/asf/james-project/blob/1193b6b4/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Delay.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Delay.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Delay.java
new file mode 100644
index 0000000..c066a63
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Delay.java
@@ -0,0 +1,166 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.mail.MessagingException;
+
+import org.apache.james.transport.util.Patterns;
+import org.apache.james.util.TimeConverter;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Objects;
+
+/**
+ * This class is used to hold a delay time and its corresponding number of
+ * retries.
+ */
+public class Delay {
+
+ /**
+ * Default Delay Time (Default is 6*60*60*1000 Milliseconds (6 hours)).
+ */
+ public static final long DEFAULT_DELAY_TIME = 21600000;
+ public static final int DEFAULT_ATTEMPTS = 1;
+ /**
+ * Pattern to match [attempts*]delay[units].
+ */
+ private static final String PATTERN_STRING = "\\s*([0-9]*\\s*[\\*])?\\s*([0-9]+)\\s*([a-z,A-Z]*)\\s*";
+ private static final Pattern PATTERN = Patterns.compilePatternUncheckedException(PATTERN_STRING);
+
+ private int attempts = DEFAULT_ATTEMPTS;
+
+ private long delayTime = DEFAULT_DELAY_TIME;
+
+ /**
+ * <p>
+ * This constructor expects Strings of the form
+ * "[attempt\*]delaytime[unit]".
+ * </p>
+ * <p>
+ * The optional attempt is the number of tries this delay should be used
+ * (default = 1). The unit, if present, must be one of
+ * (msec,sec,minute,hour,day). The default value of unit is 'msec'.
+ * </p>
+ * <p>
+ * The constructor multiplies the delaytime by the relevant multiplier
+ * for the unit, so the delayTime instance variable is always in msec.
+ * </p>
+ *
+ * @param initString the string to initialize this Delay object from
+ */
+ public Delay(String initString) throws MessagingException {
+ // Default unit value to 'msec'.
+ String unit = "msec";
+
+ Matcher res = PATTERN.matcher(initString);
+ if (res.matches()) {
+ // The capturing groups will now hold:
+ // at 1: attempts * (if present)
+ // at 2: delaytime
+ // at 3: unit (if present)
+ if (res.group(1) != null && !res.group(1).equals("")) {
+ // We have an attempt *
+ String attemptMatch = res.group(1);
+
+ // Strip the * and whitespace.
+ attemptMatch = attemptMatch.substring(0, attemptMatch.length() - 1).trim();
+ attempts = Integer.parseInt(attemptMatch);
+ }
+
+ delayTime = Long.parseLong(res.group(2));
+
+ if (!res.group(3).equals("")) {
+ // We have a value for 'unit'.
+ unit = res.group(3).toLowerCase(Locale.US);
+ }
+ } else {
+ throw new MessagingException(initString + " does not match " + PATTERN_STRING);
+ }
+
+ // calculate delayTime.
+ try {
+ delayTime = TimeConverter.getMilliSeconds(delayTime, unit);
+ } catch (NumberFormatException e) {
+ throw new MessagingException(e.getMessage());
+ }
+ }
+
+ /**
+ * This constructor makes a default Delay object with attempts = 1 and
+ * delayTime = DEFAULT_DELAY_TIME.
+ */
+ public Delay() {
+ }
+
+ @VisibleForTesting
+ Delay(int attempts, long delayTime) {
+ this.attempts = attempts;
+ this.delayTime = delayTime;
+ }
+
+ /**
+ * @return the delayTime for this Delay
+ */
+ public long getDelayTime() {
+ return delayTime;
+ }
+
+ /**
+ * @return the number attempts this Delay should be used.
+ */
+ public int getAttempts() {
+ return attempts;
+ }
+
+ /**
+ * Set the number attempts this Delay should be used.
+ */
+ public void setAttempts(int value) {
+ attempts = value;
+ }
+
+ /**
+ * Pretty prints this Delay
+ */
+ @Override
+ public String toString() {
+ return getAttempts() + "*" + getDelayTime() + "msecs";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof Delay) {
+ Delay that = (Delay) o;
+
+ return Objects.equal(this.attempts, that.attempts)
+ && Objects.equal(this.delayTime, that.delayTime);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(attempts, delayTime);
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/1193b6b4/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
new file mode 100644
index 0000000..92ce97b
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
@@ -0,0 +1,96 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import javax.mail.MessagingException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class DelayTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void defaultConstructorShouldConstructDefaultDelay() {
+ assertThat(new Delay())
+ .isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, Delay.DEFAULT_DELAY_TIME));
+ }
+
+ @Test
+ public void stringConstructorShouldWorkForNumbers() throws Exception {
+ assertThat(new Delay("36")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 36));
+ }
+
+ @Test
+ public void stringConstructorShouldWorkForZero() throws Exception {
+ assertThat(new Delay("0")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 0));
+ }
+
+ @Test
+ public void stringConstructorShouldDefaultToZeroForNegatives() throws Exception {
+ assertThat(new Delay("0")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 0));
+ }
+
+ @Test
+ public void stringConstructorShouldWorkForNumberAndSecond() throws Exception {
+ assertThat(new Delay("1s")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 1000));
+ }
+
+ @Test
+ public void stringConstructorShouldWorkForNumberAndAttempts() throws Exception {
+ assertThat(new Delay("2*36")).isEqualTo(new Delay(2, 36));
+ }
+
+ @Test
+ public void stringConstructorShouldWorkForNumberAndZeroAttempts() throws Exception {
+ assertThat(new Delay("0*36")).isEqualTo(new Delay(0, 36));
+ }
+
+ @Test
+ public void stringConstructorShouldThrowOnNegativeAttempts() throws Exception {
+ expectedException.expect(MessagingException.class);
+
+ new Delay("-1*36");
+ }
+
+ @Test
+ public void stringConstructorShouldWorkForNumberAttemptsAndUnit() throws Exception {
+ assertThat(new Delay("2*36s")).isEqualTo(new Delay(2, 36000));
+ }
+
+ @Test
+ public void stringConstructorShouldThrowOnInvalidInput() throws Exception {
+ expectedException.expect(MessagingException.class);
+
+ new Delay("invalid");
+ }
+
+ @Test
+ public void stringConstructorShouldThrowOnInvalidUnit() throws Exception {
+ expectedException.expect(MessagingException.class);
+
+ new Delay("36invalid");
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[05/50] [abbrv] james-project git commit: JAMES-1877 Extract delays
and max retries calculations from RemoteDelivery
Posted by ro...@apache.org.
JAMES-1877 Extract delays and max retries calculations from RemoteDelivery
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/8a8af97a
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/8a8af97a
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/8a8af97a
Branch: refs/heads/master
Commit: 8a8af97a5f569fb01f24b72bfbb8e481e4c26f26
Parents: 1193b6b
Author: Benoit Tellier <bt...@linagora.com>
Authored: Tue Nov 29 12:02:07 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 14:35:32 2017 +0700
----------------------------------------------------------------------
.../james/transport/mailets/RemoteDelivery.java | 107 +-----------
.../remoteDelivery/DelaysAndMaxRetry.java | 166 +++++++++++++++++++
.../mailets/remoteDelivery/DelayTest.java | 21 +++
.../remoteDelivery/DelaysAndMaxRetryTest.java | 136 +++++++++++++++
4 files changed, 329 insertions(+), 101 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/8a8af97a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index b23f79d..9ffd164 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -64,6 +64,7 @@ import org.apache.james.queue.api.MailQueue.MailQueueException;
import org.apache.james.queue.api.MailQueue.MailQueueItem;
import org.apache.james.queue.api.MailQueueFactory;
import org.apache.james.transport.mailets.remoteDelivery.Delay;
+import org.apache.james.transport.mailets.remoteDelivery.DelaysAndMaxRetry;
import org.apache.james.transport.mailets.remoteDelivery.HeloNameProvider;
import org.apache.james.transport.mailets.remoteDelivery.RemoteDeliverySocketFactory;
import org.apache.mailet.HostAddress;
@@ -170,7 +171,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
/**
* Maximum no. of retries (Defaults to 5).
*/
- private int maxRetries = 5;
+ private int maxRetries;
/**
* Default number of ms to timeout on smtp delivery
@@ -264,61 +265,11 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
logger = getMailetContext().getLogger();
- // Create list of Delay Times.
- ArrayList<Delay> delayTimesList = new ArrayList<Delay>();
try {
- if (getInitParameter("delayTime") != null) {
-
- // parses delayTimes specified in config file.
- String delayTimesParm = getInitParameter("delayTime");
-
- // Split on commas
- StringTokenizer st = new StringTokenizer(delayTimesParm, ",");
- while (st.hasMoreTokens()) {
- String delayTime = st.nextToken();
- delayTimesList.add(new Delay(delayTime));
- }
- } else {
- // Use default delayTime.
- delayTimesList.add(new Delay());
- }
- } catch (Exception e) {
- log("Invalid delayTime setting: " + getInitParameter("delayTime"));
- }
-
- try {
- // Get No. of Max Retries.
- if (getInitParameter("maxRetries") != null) {
- maxRetries = Integer.parseInt(getInitParameter("maxRetries"));
- }
-
- // Check consistency of 'maxRetries' with delayTimesList attempts.
- int totalAttempts = calcTotalAttempts(delayTimesList);
-
- // If inconsistency found, fix it.
- if (totalAttempts > maxRetries) {
- log("Total number of delayTime attempts exceeds maxRetries specified. " + " Increasing maxRetries from " + maxRetries + " to " + totalAttempts);
- maxRetries = totalAttempts;
- } else {
- int extra = maxRetries - totalAttempts;
- if (extra != 0) {
- log("maxRetries is larger than total number of attempts specified. " + "Increasing last delayTime with " + extra + " attempts ");
-
- // Add extra attempts to the last delayTime.
- if (delayTimesList.size() != 0) {
- // Get the last delayTime.
- Delay delay = delayTimesList.get(delayTimesList.size() - 1);
-
- // Increase no. of attempts.
- delay.setAttempts(delay.getAttempts() + extra);
- log("Delay of " + delay.getDelayTime() + " msecs is now attempted: " + delay.getAttempts() + " times");
- } else {
- throw new MessagingException("No delaytimes, cannot continue");
- }
- }
- }
- delayTimes = expandDelays(delayTimesList);
-
+ int intendedMaxRetries = Integer.parseInt(getInitParameter("maxRetries", "5"));
+ DelaysAndMaxRetry delaysAndMaxRetry = DelaysAndMaxRetry.from(intendedMaxRetries, getInitParameter("delayTime"));
+ maxRetries = delaysAndMaxRetry.getMaxRetries();
+ delayTimes = delaysAndMaxRetry.getExpendedDelays();
} catch (Exception e) {
log("Invalid maxRetries setting: " + getInitParameter("maxRetries"));
}
@@ -435,52 +386,6 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
}
/**
- * Calculates Total no. of attempts for the specified delayList.
- *
- * @param delayList list of 'Delay' objects
- * @return total no. of retry attempts
- */
- private int calcTotalAttempts(ArrayList<Delay> delayList) {
- int sum = 0;
- for (Delay delay : delayList) {
- sum += delay.getAttempts();
- }
- return sum;
- }
-
- /**
- * <p>
- * This method expands an ArrayList containing Delay objects into an array
- * holding the only delaytime in the order.
- * </p>
- * <p/>
- * So if the list has 2 Delay objects the first having attempts=2 and
- * delaytime 4000 the second having attempts=1 and delaytime=300000 will be
- * expanded into this array:
- * <p/>
- * <pre>
- * long[0] = 4000
- * long[1] = 4000
- * long[2] = 300000
- * </pre>
- *
- * @param list the list to expand
- * @return the expanded list
- */
- private long[] expandDelays(ArrayList<Delay> list) {
- long[] delays = new long[calcTotalAttempts(list)];
- Iterator<Delay> i = list.iterator();
- int idx = 0;
- while (i.hasNext()) {
- Delay delay = i.next();
- for (int j = 0; j < delay.getAttempts(); j++) {
- delays[idx++] = delay.getDelayTime();
- }
- }
- return delays;
- }
-
- /**
* This method returns, given a retry-count, the next delay time to use.
*
* @param retry_count the current retry_count.
http://git-wip-us.apache.org/repos/asf/james-project/blob/8a8af97a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetry.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetry.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetry.java
new file mode 100644
index 0000000..10b6cca
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetry.java
@@ -0,0 +1,166 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.mail.MessagingException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+
+public class DelaysAndMaxRetry {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DelaysAndMaxRetry.class);
+
+ public static DelaysAndMaxRetry from(int intendedMaxRetries, String delaysAsString) throws MessagingException {
+ // Create list of Delay Times.
+ ArrayList<Delay> delayTimesList = createDelayList(delaysAsString);
+
+ // Check consistency of 'maxRetries' with delayTimesList attempts.
+ int totalAttempts = calcTotalAttempts(delayTimesList);
+
+ // If inconsistency found, fix it.
+ if (totalAttempts > intendedMaxRetries) {
+ LOGGER.warn("Total number of delayTime attempts exceeds maxRetries specified. " + " Increasing maxRetries from " + intendedMaxRetries + " to " + totalAttempts);
+ return new DelaysAndMaxRetry(totalAttempts, delayTimesList);
+ } else {
+ int extra = intendedMaxRetries - totalAttempts;
+ if (extra != 0) {
+ LOGGER.warn("maxRetries is larger than total number of attempts specified. " + "Increasing last delayTime with " + extra + " attempts ");
+
+ // Add extra attempts to the last delayTime.
+ if (delayTimesList.size() != 0) {
+ // Get the last delayTime.
+ Delay delay = delayTimesList.get(delayTimesList.size() - 1);
+
+ // Increase no. of attempts.
+ delay.setAttempts(delay.getAttempts() + extra);
+ LOGGER.warn("Delay of " + delay.getDelayTime() + " msecs is now attempted: " + delay.getAttempts() + " times");
+ } else {
+ throw new MessagingException("No delaytimes, cannot continue");
+ }
+ }
+ return new DelaysAndMaxRetry(intendedMaxRetries, delayTimesList);
+ }
+ }
+
+ private static ArrayList<Delay> createDelayList(String delaysAsString) {
+ ArrayList<Delay> delayTimesList = new ArrayList<Delay>();
+ try {
+ if (delaysAsString != null) {
+
+ // Split on commas
+ StringTokenizer st = new StringTokenizer(delaysAsString, ",");
+ while (st.hasMoreTokens()) {
+ String delayTime = st.nextToken();
+ delayTimesList.add(new Delay(delayTime));
+ }
+ } else {
+ // Use default delayTime.
+ delayTimesList.add(new Delay());
+ }
+ } catch (Exception e) {
+ LOGGER.warn("Invalid delayTime setting: " + delaysAsString);
+ }
+ return delayTimesList;
+ }
+
+ /**
+ * Calculates Total no. of attempts for the specified delayList.
+ *
+ * @param delayList list of 'Delay' objects
+ * @return total no. of retry attempts
+ */
+ private static int calcTotalAttempts(List<Delay> delayList) {
+ int sum = 0;
+ for (Delay delay : delayList) {
+ sum += delay.getAttempts();
+ }
+ return sum;
+ }
+
+ private final int maxRetries;
+ private final List<Delay> delays;
+
+ @VisibleForTesting
+ DelaysAndMaxRetry(int maxRetries, List<Delay> delays) {
+ this.maxRetries = maxRetries;
+ this.delays = ImmutableList.copyOf(delays);
+ }
+
+ public int getMaxRetries() {
+ return maxRetries;
+ }
+
+ /**
+ * <p>
+ * This method expands an ArrayList containing Delay objects into an array
+ * holding the only delaytime in the order.
+ * </p>
+ * <p/>
+ * So if the list has 2 Delay objects the first having attempts=2 and
+ * delaytime 4000 the second having attempts=1 and delaytime=300000 will be
+ * expanded into this array:
+ * <p/>
+ * <pre>
+ * long[0] = 4000
+ * long[1] = 4000
+ * long[2] = 300000
+ * </pre>
+ *
+ * @param list the list to expand
+ * @return the expanded list
+ */
+ public long[] getExpendedDelays() {
+ long[] delaysAsLong = new long[calcTotalAttempts(delays)];
+ Iterator<Delay> i = delays.iterator();
+ int idx = 0;
+ while (i.hasNext()) {
+ Delay delay = i.next();
+ for (int j = 0; j < delay.getAttempts(); j++) {
+ delaysAsLong[idx++] = delay.getDelayTime();
+ }
+ }
+ return delaysAsLong;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof DelaysAndMaxRetry) {
+ DelaysAndMaxRetry that = (DelaysAndMaxRetry) o;
+ return Objects.equal(this.maxRetries, that.maxRetries)
+ && Objects.equal(this.delays, that.delays);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(maxRetries, delays);
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/8a8af97a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
index 92ce97b..f23c918 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
@@ -76,6 +76,20 @@ public class DelayTest {
}
@Test
+ public void stringConstructorShouldThrowWhenAttemptsOmitted() throws Exception {
+ expectedException.expect(NumberFormatException.class);
+
+ new Delay("*36");
+ }
+
+ @Test
+ public void stringConstructorShouldThrowWhenDelayOmitted() throws Exception {
+ expectedException.expect(MessagingException.class);
+
+ new Delay("2*");
+ }
+
+ @Test
public void stringConstructorShouldWorkForNumberAttemptsAndUnit() throws Exception {
assertThat(new Delay("2*36s")).isEqualTo(new Delay(2, 36000));
}
@@ -93,4 +107,11 @@ public class DelayTest {
new Delay("36invalid");
}
+
+ @Test
+ public void stringConstructorShouldThrowOnEmptyString() throws Exception {
+ expectedException.expect(MessagingException.class);
+
+ new Delay("");
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/8a8af97a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetryTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetryTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetryTest.java
new file mode 100644
index 0000000..da4ecda
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetryTest.java
@@ -0,0 +1,136 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import javax.mail.MessagingException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import com.google.common.collect.ImmutableList;
+
+public class DelaysAndMaxRetryTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void fromShouldParseSingleDelay() throws Exception {
+ DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(1, "1s");
+
+ DelaysAndMaxRetry expected = new DelaysAndMaxRetry(1, ImmutableList.of(new Delay(1, 1000)));
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void fromShouldParseTwoDelays() throws Exception {
+ DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(2, "1s,2s");
+
+ DelaysAndMaxRetry expected = new DelaysAndMaxRetry(2, ImmutableList.of(new Delay(1, 1000), new Delay(1, 2000)));
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void fromShouldAdaptMaxRetriesWhenUnderAttempts() throws Exception {
+ DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(1, "1s,2*2s");
+
+ DelaysAndMaxRetry expected = new DelaysAndMaxRetry(3, ImmutableList.of(new Delay(1, 1000), new Delay(2, 2000)));
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void fromShouldAdaptDelaysWhenUnderMaxRetries() throws Exception {
+ DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(4, "1s,2*2s");
+
+ DelaysAndMaxRetry expected = new DelaysAndMaxRetry(4, ImmutableList.of(new Delay(1, 1000), new Delay(3, 2000)));
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void fromShouldHandleNullValuesForDelayAsString() throws Exception {
+ DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(1, null);
+
+ DelaysAndMaxRetry expected = new DelaysAndMaxRetry(1, ImmutableList.of(new Delay(Delay.DEFAULT_ATTEMPTS, Delay.DEFAULT_DELAY_TIME)));
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void fromShouldIgnoreEmptyDelay() throws Exception {
+ DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(1, "1s,,2s");
+
+ DelaysAndMaxRetry expected = new DelaysAndMaxRetry(2, ImmutableList.of(new Delay(1, 1000), new Delay(1, 2000)));
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void fromShouldHandleParsingFailures() throws Exception {
+ DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(3, "1s,invalid,2s");
+
+ DelaysAndMaxRetry expected = new DelaysAndMaxRetry(3, ImmutableList.of(new Delay(3, 1000)));
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void fromShouldHandleEmptyStringWithZeroMaxRetries() throws Exception {
+ DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(0, "");
+
+ DelaysAndMaxRetry expected = new DelaysAndMaxRetry(0, ImmutableList.<Delay>of());
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void fromShouldThrowOnEmptyStringWithNonZeroMaxRetry() throws Exception {
+ expectedException.expect(MessagingException.class);
+
+ DelaysAndMaxRetry.from(2, "");
+ }
+
+ @Test
+ public void getExpendedDelaysShouldReturnEmptyWhenNoDelay() throws Exception {
+ DelaysAndMaxRetry testee = DelaysAndMaxRetry.from(0, "");
+
+ assertThat(testee.getExpendedDelays()).isEmpty();
+ }
+
+ @Test
+ public void getExpendedDelaysShouldExpandSingleDelays() throws Exception {
+ DelaysAndMaxRetry testee = DelaysAndMaxRetry.from(3, "1*1S,1*2S,1*5S");
+
+ assertThat(testee.getExpendedDelays()).containsExactly(1000, 2000, 5000);
+ }
+
+ @Test
+ public void getExpendedDelaysShouldExpandMultipleDelays() throws Exception {
+ DelaysAndMaxRetry testee = DelaysAndMaxRetry.from(3, "1*1S,2*2S,2*5S");
+
+ assertThat(testee.getExpendedDelays()).containsExactly(1000, 2000, 2000, 5000, 5000);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[49/50] [abbrv] james-project git commit: JAMES-1877 Use placeholder
with loggers
Posted by ro...@apache.org.
JAMES-1877 Use placeholder with loggers
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/c80de0e0
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/c80de0e0
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/c80de0e0
Branch: refs/heads/master
Commit: c80de0e041052f8ac6937e310c49b5a59528f861
Parents: d584c13
Author: Benoit Tellier <bt...@linagora.com>
Authored: Tue Jan 10 14:58:56 2017 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 18:14:32 2017 +0700
----------------------------------------------------------------------
.../AddressesArrayToMailAddressListConverter.java | 2 +-
.../transport/mailets/remoteDelivery/DeliveryRunnable.java | 6 +++---
.../mailets/remoteDelivery/RemoteDeliveryConfiguration.java | 6 +++---
3 files changed, 7 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/c80de0e0/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverter.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverter.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverter.java
index d468947..8d7dcec 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverter.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverter.java
@@ -46,7 +46,7 @@ public class AddressesArrayToMailAddressListConverter {
try {
return Optional.of(new MailAddress(input.toString()));
} catch (AddressException e) {
- logger.debug("Can't parse unsent address: " + e.getMessage());
+ logger.debug("Can't parse unsent address: {}", e.getMessage());
return Optional.absent();
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/c80de0e0/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index 4841402..a7cf23b 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -96,7 +96,7 @@ public class DeliveryRunnable implements Runnable {
try {
if (configuration.isDebug()) {
- logger.debug(Thread.currentThread().getName() + " will process mail " + mail.getName());
+ logger.debug("{} will process mail {}", Thread.currentThread().getName(), mail.getName());
}
attemptDelivery(mail);
LifecycleUtil.dispose(mail);
@@ -146,13 +146,13 @@ public class DeliveryRunnable implements Runnable {
if (retries < configuration.getMaxRetries()) {
reAttemptDelivery(mail, retries);
} else {
- logger.debug("Bouncing message " + mail.getName() + " after " + retries + " retries");
+ logger.debug("Bouncing message {} after {} retries", mail.getName(), retries);
bouncer.bounce(mail, new Exception("Too many retries failure. Bouncing after " + retries + " retries.", executionResult.getException().orNull()));
}
}
private void reAttemptDelivery(Mail mail, int retries) throws MailQueue.MailQueueException {
- logger.debug("Storing message " + mail.getName() + " into outgoing after " + retries + " retries");
+ logger.debug("Storing message {} into outgoing after {} retries", mail.getName(), retries);
DeliveryRetriesHelper.incrementRetries(mail);
mail.setLastUpdated(dateSupplier.get());
// Something happened that will delay delivery. Store it back in the retry repository.
http://git-wip-us.apache.org/repos/asf/james-project/blob/c80de0e0/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java
index 3bfde9e..9b5fb58 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliveryConfiguration.java
@@ -146,7 +146,7 @@ public class RemoteDeliveryConfiguration {
Optional.fromNullable(mailetConfig.getInitParameter(CONNECTIONTIMEOUT))
.or(String.valueOf(DEFAULT_CONNECTION_TIMEOUT)));
} catch (Exception e) {
- LOGGER.warn("Invalid timeout setting: " + mailetConfig.getInitParameter(TIMEOUT));
+ LOGGER.warn("Invalid timeout setting: {}", mailetConfig.getInitParameter(TIMEOUT));
return DEFAULT_CONNECTION_TIMEOUT;
}
}
@@ -159,7 +159,7 @@ public class RemoteDeliveryConfiguration {
return DEFAULT_SMTP_TIMEOUT;
}
} catch (Exception e) {
- LOGGER.warn("Invalid timeout setting: " + mailetConfig.getInitParameter(TIMEOUT));
+ LOGGER.warn("Invalid timeout setting: {}", mailetConfig.getInitParameter(TIMEOUT));
return DEFAULT_SMTP_TIMEOUT;
}
}
@@ -171,7 +171,7 @@ public class RemoteDeliveryConfiguration {
.or(String.valueOf(DEFAULT_MAX_RETRY)));
return DelaysAndMaxRetry.from(intendedMaxRetries, mailetConfig.getInitParameter(DELAY_TIME));
} catch (Exception e) {
- LOGGER.warn("Invalid maxRetries setting: " + mailetConfig.getInitParameter(MAX_RETRIES));
+ LOGGER.warn("Invalid maxRetries setting: {}", mailetConfig.getInitParameter(MAX_RETRIES));
return DelaysAndMaxRetry.defaults();
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[37/50] [abbrv] james-project git commit: JAMES-1877 Enable logging
on mailet tests
Posted by ro...@apache.org.
JAMES-1877 Enable logging on mailet tests
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/dbeea267
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/dbeea267
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/dbeea267
Branch: refs/heads/master
Commit: dbeea267cdf191517535f87dbb68a165995deace
Parents: 730a7ab
Author: Benoit Tellier <bt...@linagora.com>
Authored: Fri Dec 2 13:13:36 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:52 2017 +0700
----------------------------------------------------------------------
server/mailet/mailets/pom.xml | 6 ++++++
.../mailets/src/test/resources/logback-test.xml | 21 ++++++++++++++++++++
2 files changed, 27 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/dbeea267/server/mailet/mailets/pom.xml
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/pom.xml b/server/mailet/mailets/pom.xml
index ea7603c..d519861 100644
--- a/server/mailet/mailets/pom.xml
+++ b/server/mailet/mailets/pom.xml
@@ -148,6 +148,12 @@
</dependency>
<!-- Test dependencies -->
<dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.1.6</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
http://git-wip-us.apache.org/repos/asf/james-project/blob/dbeea267/server/mailet/mailets/src/test/resources/logback-test.xml
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/resources/logback-test.xml b/server/mailet/mailets/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..0210dd6
--- /dev/null
+++ b/server/mailet/mailets/src/test/resources/logback-test.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+ <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
+ <resetJUL>true</resetJUL>
+ </contextListener>
+
+ <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx</pattern>
+ <immediateFlush>false</immediateFlush>
+ </encoder>
+ </appender>
+
+ <root level="DEBUG">
+ <appender-ref ref="CONSOLE" />
+ </root>
+
+ <logger name="org.apache.james" level="DEBUG"/>
+
+</configuration>
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[36/50] [abbrv] james-project git commit: JAMES-1877 Extract DNS
resolution to a DNS helper
Posted by ro...@apache.org.
JAMES-1877 Extract DNS resolution to a DNS helper
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/730a7ab7
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/730a7ab7
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/730a7ab7
Branch: refs/heads/master
Commit: 730a7ab7ef7dea7c2db5b45855f89b31ccb1534a
Parents: 7f8cf9e
Author: Benoit Tellier <bt...@linagora.com>
Authored: Fri Dec 2 10:56:14 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:52 2017 +0700
----------------------------------------------------------------------
.../mailets/remoteDelivery/DnsHelper.java | 69 ++++++++++++++++++++
.../mailets/remoteDelivery/MailDelivrer.java | 51 ++++-----------
2 files changed, 83 insertions(+), 37 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/730a7ab7/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DnsHelper.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DnsHelper.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DnsHelper.java
new file mode 100644
index 0000000..5e92040
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DnsHelper.java
@@ -0,0 +1,69 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.transport.mailets.remoteDelivery;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.TemporaryResolutionException;
+import org.apache.james.dnsservice.library.MXHostAddressIterator;
+import org.apache.mailet.HostAddress;
+import org.slf4j.Logger;
+
+@SuppressWarnings("deprecation")
+public class DnsHelper {
+
+ private final DNSService dnsServer;
+ private final RemoteDeliveryConfiguration configuration;
+ private final Logger logger;
+
+ public DnsHelper(DNSService dnsServer, RemoteDeliveryConfiguration configuration, Logger logger) {
+ this.dnsServer = dnsServer;
+ this.configuration = configuration;
+ this.logger = logger;
+ }
+
+ public Iterator<HostAddress> retrieveHostAddressIterator(String host) throws TemporaryResolutionException {
+ if (configuration.getGatewayServer().isEmpty()) {
+ return new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logger);
+ } else {
+ return getGatewaySMTPHostAddresses(configuration.getGatewayServer());
+ }
+ }
+
+ /**
+ * Returns an Iterator over org.apache.mailet.HostAddress, a specialized
+ * subclass of javax.mail.URLName, which provides location information for
+ * servers that are specified as mail handlers for the given hostname. If no
+ * host is found, the Iterator returned will be empty and the first call to
+ * hasNext() will return false. The Iterator is a nested iterator: the outer
+ * iteration is over each gateway, and the inner iteration is over
+ * potentially multiple A records for each gateway.
+ *
+ * @param gatewayServers - Collection of host[:port] Strings
+ * @return an Iterator over HostAddress instances, sorted by priority
+ * @since v2.2.0a16-unstable
+ */
+ private Iterator<HostAddress> getGatewaySMTPHostAddresses(Collection<String> gatewayServers) {
+ return new MXHostAddressIterator(gatewayServers.iterator(), dnsServer, false, logger);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/730a7ab7/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
index 941ef21..df77eb8 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrer.java
@@ -34,7 +34,6 @@ import javax.mail.internet.ParseException;
import org.apache.james.dnsservice.api.DNSService;
import org.apache.james.dnsservice.api.TemporaryResolutionException;
-import org.apache.james.dnsservice.library.MXHostAddressIterator;
import org.apache.mailet.HostAddress;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
@@ -46,14 +45,14 @@ public class MailDelivrer {
private final RemoteDeliveryConfiguration configuration;
private final MailDelivrerToHost mailDelivrerToHost;
- private final DNSService dnsServer;
+ private final DnsHelper dnsHelper;
private final MessageComposer messageComposer;
private final Logger logger;
public MailDelivrer(RemoteDeliveryConfiguration configuration, MailDelivrerToHost mailDelivrerToHost, DNSService dnsServer, Logger logger) {
this.configuration = configuration;
this.mailDelivrerToHost = mailDelivrerToHost;
- this.dnsServer = dnsServer;
+ this.dnsHelper = new DnsHelper(dnsServer, configuration, logger);
this.messageComposer = new MessageComposer(configuration);
this.logger = logger;
}
@@ -107,27 +106,23 @@ public class MailDelivrer {
logger.debug("Attempting to deliver " + mail.getName());
}
- // Figure out which servers to try to send to. This collection
- // will hold all the possible target servers
- Iterator<HostAddress> targetServers;
- if (configuration.getGatewayServer().isEmpty()) {
- MailAddress rcpt = mail.getRecipients().iterator().next();
- String host = rcpt.getDomain();
-
- // Lookup the possible targets
- try {
- targetServers = new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logger);
- } catch (TemporaryResolutionException e) {
- return handleTemporaryResolutionException(mail, host);
- }
+ String host = retrieveTargetHostname(mail);
+ try {
+ // Figure out which servers to try to send to. This collection
+ // will hold all the possible target servers
+ Iterator<HostAddress> targetServers = dnsHelper.retrieveHostAddressIterator(host);
if (!targetServers.hasNext()) {
return handleNoTargetServer(mail, host);
}
- } else {
- targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer());
+ return doDeliver(mail, mail.getMessage(), InternetAddressConverter.convert(mail.getRecipients()), targetServers);
+ } catch (TemporaryResolutionException e) {
+ return handleTemporaryResolutionException(mail, host);
}
+ }
- return doDeliver(mail, mail.getMessage(), InternetAddressConverter.convert(mail.getRecipients()), targetServers);
+ private String retrieveTargetHostname(Mail mail) {
+ MailAddress rcpt = mail.getRecipients().iterator().next();
+ return rcpt.getDomain();
}
@SuppressWarnings("deprecation")
@@ -337,24 +332,6 @@ public class MailDelivrer {
}
}
- /**
- * Returns an Iterator over org.apache.mailet.HostAddress, a specialized
- * subclass of javax.mail.URLName, which provides location information for
- * servers that are specified as mail handlers for the given hostname. If no
- * host is found, the Iterator returned will be empty and the first call to
- * hasNext() will return false. The Iterator is a nested iterator: the outer
- * iteration is over each gateway, and the inner iteration is over
- * potentially multiple A records for each gateway.
- *
- * @param gatewayServers - Collection of host[:port] Strings
- * @return an Iterator over HostAddress instances, sorted by priority
- * @since v2.2.0a16-unstable
- */
- @SuppressWarnings("deprecation")
- private Iterator<HostAddress> getGatewaySMTPHostAddresses(Collection<String> gatewayServers) {
- return new MXHostAddressIterator(gatewayServers.iterator(), dnsServer, false, logger);
- }
-
private void logSendFailedException(SendFailedException sfe) {
if (configuration.isDebug()) {
EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[50/50] [abbrv] james-project git commit: Merge remote-tracking
branch 'benoit/JAMES-1877'
Posted by ro...@apache.org.
Merge remote-tracking branch 'benoit/JAMES-1877'
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/131c0114
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/131c0114
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/131c0114
Branch: refs/heads/master
Commit: 131c01148ce32c88320a168fdc773c001252603d
Parents: 3b6c5e0 c80de0e
Author: Raphael Ouazana <ra...@linagora.com>
Authored: Tue Jan 10 15:17:23 2017 +0100
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Tue Jan 10 15:17:23 2017 +0100
----------------------------------------------------------------------
mailet/base/pom.xml | 16 +
.../org/apache/mailet/base/GenericMailet.java | 2 +-
.../java/org/apache/mailet/base/MailetUtil.java | 12 +-
.../org/apache/mailet/base/MailetUtilTest.java | 9 +-
.../org/apache/mailet/base/test/FakeMail.java | 64 +
.../mailet/base/test/FakeMailContext.java | 112 +-
.../apache/mailet/base/test/FakeMailTest.java | 41 +
.../transport/mailets/ToProcessorTest.java | 12 +-
.../james/util/streams/IteratorsTest.java | 2 +-
.../org/apache/james/util/TimeConverter.java | 11 +-
.../apache/james/util/TimeConverterTest.java | 252 ++-
server/mailet/mailets/pom.xml | 6 +
.../james/transport/mailets/RemoteDelivery.java | 1561 +-----------------
.../mailets/RemoteDeliverySocketFactory.java | 137 --
...ddressesArrayToMailAddressListConverter.java | 66 +
.../mailets/remoteDelivery/Bouncer.java | 147 ++
.../mailets/remoteDelivery/Converter7Bit.java | 65 +
.../transport/mailets/remoteDelivery/Delay.java | 115 ++
.../remoteDelivery/DelaysAndMaxRetry.java | 161 ++
.../remoteDelivery/DeliveryRetriesHelper.java | 50 +
.../remoteDelivery/DeliveryRunnable.java | 174 ++
.../mailets/remoteDelivery/DnsHelper.java | 52 +
.../EnhancedMessagingException.java | 176 ++
.../mailets/remoteDelivery/ExecutionResult.java | 92 ++
.../remoteDelivery/HeloNameProvider.java | 53 +
.../InternetAddressConverter.java | 44 +
.../mailets/remoteDelivery/MailDelivrer.java | 274 +++
.../remoteDelivery/MailDelivrerToHost.java | 136 ++
.../mailets/remoteDelivery/MessageComposer.java | 143 ++
.../RemoteDeliveryConfiguration.java | 317 ++++
.../RemoteDeliverySocketFactory.java | 137 ++
.../mailets/remoteDelivery/Repeat.java | 37 +
...ssesArrayToMailAddressListConverterTest.java | 59 +
.../mailets/remoteDelivery/BouncerTest.java | 457 +++++
.../mailets/remoteDelivery/DelayTest.java | 118 ++
.../remoteDelivery/DelaysAndMaxRetryTest.java | 136 ++
.../remoteDelivery/DeliveryRetryHelperTest.java | 83 +
.../remoteDelivery/DeliveryRunnableTest.java | 248 +++
.../remoteDelivery/HeloNameProviderTest.java | 79 +
.../InternetAddressConverterTest.java | 62 +
.../remoteDelivery/MailDelivrerTest.java | 462 ++++++
.../RemoteDeliveryConfigurationTest.java | 911 ++++++++++
.../RemoteDeliveryRunningTest.java | 85 +
.../remoteDelivery/RemoteDeliveryTest.java | 207 +++
.../mailets/remoteDelivery/RepeatTest.java | 56 +
.../mailets/src/test/resources/logback-test.xml | 21 +
46 files changed, 5790 insertions(+), 1670 deletions(-)
----------------------------------------------------------------------
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[27/50] [abbrv] james-project git commit: JAMES-1877 Connect do not
need to catch exception
Posted by ro...@apache.org.
JAMES-1877 Connect do not need to catch exception
This exception will not cause doDelivery (which is host specific to fail
This allow a more clean error handling, where errors are handled at the doDelivery for one server error
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/2a4936d3
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/2a4936d3
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/2a4936d3
Branch: refs/heads/master
Commit: 2a4936d339e76ba41a684ae024f9ce33193c4646
Parents: 942cdfc
Author: Benoit Tellier <bt...@linagora.com>
Authored: Fri Dec 2 09:14:02 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 15:12:51 2017 +0700
----------------------------------------------------------------------
.../remoteDelivery/DeliveryRunnable.java | 35 ++++++--------------
1 file changed, 11 insertions(+), 24 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/2a4936d3/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
index f497767..c45e736 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java
@@ -253,6 +253,11 @@ public class DeliveryRunnable implements Runnable {
lastError = handleSendFailException(mail, sfe);
} catch (MessagingException me) {
lastError = handleMessagingException(mail, me);
+ if (configuration.isDebug()) {
+ logger.debug(me.getMessage(), me.getCause());
+ } else {
+ logger.info(me.getMessage());
+ }
}
}
// If we encountered an exception while looping through,
@@ -290,9 +295,7 @@ public class DeliveryRunnable implements Runnable {
try {
transport = (SMTPTransport) session.getTransport(outgoingMailServer);
transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) );
- if (!connect(outgoingMailServer, transport)) {
- return false;
- }
+ connect(outgoingMailServer, transport);
transport.sendMessage(adaptToTransport(message, transport), addr);
logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() +
" at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients());
@@ -538,27 +541,11 @@ public class DeliveryRunnable implements Runnable {
}
}
- private boolean connect(HostAddress outgoingMailServer, SMTPTransport transport) {
- try {
- if (configuration.getAuthUser() != null) {
- transport.connect(outgoingMailServer.getHostName(), configuration.getAuthUser(), configuration.getAuthPass());
- } else {
- transport.connect();
- }
- return true;
- } catch (MessagingException me) {
- // Any error on connect should cause the mailet to attempt
- // to connect to the next SMTP server associated with this
- // MX record. Just log the exception. We'll worry about
- // failing the message at the end of the loop.
-
- // Also include the stacktrace if debug is enabled. See JAMES-1257
- if (configuration.isDebug()) {
- logger.debug(me.getMessage(), me.getCause());
- } else {
- logger.info(me.getMessage());
- }
- return false;
+ private void connect(HostAddress outgoingMailServer, SMTPTransport transport) throws MessagingException {
+ if (configuration.getAuthUser() != null) {
+ transport.connect(outgoingMailServer.getHostName(), configuration.getAuthUser(), configuration.getAuthPass());
+ } else {
+ transport.connect();
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org