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 <[email protected]> Authored: Fri Dec 2 10:06:14 2016 +0700 Committer: Benoit Tellier <[email protected]> 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: [email protected] For additional commands, e-mail: [email protected]
