You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2021/05/24 09:17:18 UTC
[james-project] 02/04: JAMES-3588 Mailet container should support
'propagate'
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 5c61fbcfbcf06e2df31a1874226f055d83f2a317
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu May 20 12:05:10 2021 +0700
JAMES-3588 Mailet container should support 'propagate'
---
.../distributed/configure/mailetcontainer.adoc | 10 ++-
.../org/apache/james/mailets/MailetErrorsTest.java | 97 ++++++++++++++++++++++
.../mailets/OneRuntimeExceptionMailet.java | 40 +++++++++
.../mailets/OneRuntimeExceptionMatcher.java | 40 +++++++++
.../mailetcontainer/impl/camel/CamelProcessor.java | 2 +
.../impl/camel/MatcherSplitter.java | 2 +
src/site/xdoc/server/config-mailetcontainer.xml | 9 +-
7 files changed, 196 insertions(+), 4 deletions(-)
diff --git a/docs/modules/servers/pages/distributed/configure/mailetcontainer.adoc b/docs/modules/servers/pages/distributed/configure/mailetcontainer.adoc
index 06b9bf8..fe7c715 100644
--- a/docs/modules/servers/pages/distributed/configure/mailetcontainer.adoc
+++ b/docs/modules/servers/pages/distributed/configure/mailetcontainer.adoc
@@ -72,8 +72,14 @@ If an exception is encountered during the execution of a mailet or a matcher, th
process the mail using the *error* processor.
The *onMailetException* property allows you to override this behaviour. You can specify another
-processor than the *error* one for handling the errors of this mailet. The *ignore* special value also
-allows to continue processing and ignore the error.
+processor than the *error* one for handling the errors of this mailet.
+
+The *ignore* special value also allows to continue processing and ignore the error.
+
+The *propagate* special value causes the mailet container to rethrow the
+exception, propagating it to the execution context. In an SMTP execution context, the spooler will then requeue
+the item and automatic retries will be setted up - note that attempts will be done for each recipients. In LMTP
+(if LMTP is configured to execute the mailetContainer), the entire mail transaction is reported as failed to the caller.
Moreover, the *onMatcherException* allows you to override matcher error handling. You can
specify another processor than the *error* one for handling the errors of this mailet. The *matchall*
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/MailetErrorsTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/MailetErrorsTest.java
index 700d212..5fcfbe9 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/MailetErrorsTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/MailetErrorsTest.java
@@ -46,6 +46,7 @@ import org.apache.james.transport.mailets.NoopMailet;
import org.apache.james.transport.mailets.Null;
import org.apache.james.transport.mailets.OneRuntimeErrorMailet;
import org.apache.james.transport.mailets.OneRuntimeExceptionMailet;
+import org.apache.james.transport.mailets.OneRuntimeExceptionMatcher;
import org.apache.james.transport.mailets.OneThreadSuicideMailet;
import org.apache.james.transport.mailets.RuntimeErrorMailet;
import org.apache.james.transport.mailets.RuntimeExceptionMailet;
@@ -124,6 +125,102 @@ class MailetErrorsTest {
}
@Test
+ void propagateShouldAllowReprocessing(@TempDir File temporaryFolder) throws Exception {
+ jamesServer = TemporaryJamesServer.builder()
+ .withMailetContainer(MailetContainer.builder()
+ .putProcessor(CommonProcessors.transport())
+ .putProcessor(errorProcessor())
+ .putProcessor(ProcessorConfiguration.root()
+ .addMailet(MailetConfiguration.builder()
+ .matcher(All.class)
+ .mailet(OneRuntimeExceptionMailet.class)
+ .addProperty("onMailetException", "propagate"))
+ .addMailet(MailetConfiguration.TO_TRANSPORT)))
+ .build(temporaryFolder);
+ jamesServer.start();
+ jamesServer.getProbe(DataProbeImpl.class).fluent()
+ .addDomain(DEFAULT_DOMAIN)
+ .addUser(FROM, PASSWORD)
+ .addUser(RECIPIENT, PASSWORD);
+
+ smtpMessageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+ .authenticate(FROM, PASSWORD)
+ .sendMessage(FROM, RECIPIENT);
+
+ testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(RECIPIENT, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitMessage(awaitAtMostOneMinute);
+ }
+
+ @Test
+ void retryExceptionShouldSucceedUponSplittedMail(@TempDir File temporaryFolder) throws Exception {
+ jamesServer = TemporaryJamesServer.builder()
+ .withMailetContainer(MailetContainer.builder()
+ .putProcessor(ProcessorConfiguration.transport()
+ .addMailet(MailetConfiguration.builder()
+ .matcher(RecipientIs.class)
+ .matcherCondition(RECIPIENT)
+ .mailet(OneRuntimeExceptionMailet.class)
+ .addProperty("onMailetException", "propagate"))
+ .addMailetsFrom(CommonProcessors.transport()))
+ .putProcessor(errorProcessor())
+ .putProcessor(CommonProcessors.root()))
+ .build(temporaryFolder);
+ jamesServer.start();
+ jamesServer.getProbe(DataProbeImpl.class).fluent()
+ .addDomain(DEFAULT_DOMAIN)
+ .addUser(FROM, PASSWORD)
+ .addUser(RECIPIENT, PASSWORD);
+
+ smtpMessageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+ .authenticate(FROM, PASSWORD)
+ .sendMessage(FROM, ImmutableList.of(FROM, RECIPIENT));
+
+ assertThat(testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(RECIPIENT, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitMessage(awaitAtMostOneMinute)
+ .getMessageCount(TestIMAPClient.INBOX)).isEqualTo(1);
+
+ assertThat(testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(FROM, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitMessage(awaitAtMostOneMinute)
+ .getMessageCount(TestIMAPClient.INBOX)).isGreaterThanOrEqualTo(1);
+ }
+
+ @Test
+ void retryExceptionShouldSucceedUponSplittedMailForMatcher(@TempDir File temporaryFolder) throws Exception {
+ jamesServer = TemporaryJamesServer.builder()
+ .withMailetContainer(MailetContainer.builder()
+ .putProcessor(ProcessorConfiguration.transport()
+ .addMailet(MailetConfiguration.builder()
+ .matcher(OneRuntimeExceptionMatcher.class)
+ .mailet(NoopMailet.class)
+ .addProperty("onMatchException", "propagate"))
+ .addMailetsFrom(CommonProcessors.transport()))
+ .putProcessor(errorProcessor())
+ .putProcessor(CommonProcessors.root()))
+ .build(temporaryFolder);
+ jamesServer.start();
+ jamesServer.getProbe(DataProbeImpl.class).fluent()
+ .addDomain(DEFAULT_DOMAIN)
+ .addUser(FROM, PASSWORD)
+ .addUser(RECIPIENT, PASSWORD);
+
+ smtpMessageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+ .authenticate(FROM, PASSWORD)
+ .sendMessage(FROM, RECIPIENT);
+
+ assertThat(testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+ .login(RECIPIENT, PASSWORD)
+ .select(TestIMAPClient.INBOX)
+ .awaitMessage(awaitAtMostOneMinute)
+ .getMessageCount(TestIMAPClient.INBOX)).isEqualTo(1);
+ }
+
+ @Test
void matcherProcessingShouldHandleClassNotFoundException(@TempDir File temporaryFolder) throws Exception {
jamesServer = TemporaryJamesServer.builder()
.withBase(SMTP_ONLY_MODULE)
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/OneRuntimeExceptionMailet.java b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/OneRuntimeExceptionMailet.java
new file mode 100644
index 0000000..982f4f8
--- /dev/null
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/OneRuntimeExceptionMailet.java
@@ -0,0 +1,40 @@
+/****************************************************************
+ * 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;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.mail.MessagingException;
+
+import org.apache.mailet.Mail;
+import org.apache.mailet.base.GenericMailet;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
+
+public class OneRuntimeExceptionMailet extends GenericMailet {
+ private final AtomicInteger callCount = new AtomicInteger(0);
+
+ @Override
+ public void service(Mail mail) throws MessagingException {
+ System.out.println("exection " + ImmutableList.copyOf(mail.getRecipients()));
+ if (callCount.getAndIncrement() == 0) {
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/OneRuntimeExceptionMatcher.java b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/OneRuntimeExceptionMatcher.java
new file mode 100644
index 0000000..b0e7c99
--- /dev/null
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/OneRuntimeExceptionMatcher.java
@@ -0,0 +1,40 @@
+/****************************************************************
+ * 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;
+
+import java.util.Collection;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.james.core.MailAddress;
+import org.apache.mailet.Mail;
+import org.apache.mailet.base.GenericMatcher;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
+
+public class OneRuntimeExceptionMatcher extends GenericMatcher {
+ private final AtomicInteger callCount = new AtomicInteger(0);
+
+ @Override
+ public Collection<MailAddress> match(Mail mail) {
+ if (callCount.getAndIncrement() == 0) {
+ throw new RuntimeException();
+ }
+ return ImmutableList.of();
+ }
+}
diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/CamelProcessor.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/CamelProcessor.java
index fef4dc1..51bb14b 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/CamelProcessor.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/CamelProcessor.java
@@ -92,6 +92,8 @@ public class CamelProcessor {
// changed by the mailet
LOGGER.warn("Encountered error while executing mailet {}. Ignoring it.", mailet, ex);
ProcessorUtil.verifyMailAddresses(mail.getRecipients());
+ } else if (onMailetException.equalsIgnoreCase("propagate")) {
+ throw me;
} else {
ProcessorUtil.handleException(me, mail, mailet.getMailetConfig().getMailetName(), onMailetException, LOGGER);
}
diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/MatcherSplitter.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/MatcherSplitter.java
index 91b338f..4dd0d13 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/MatcherSplitter.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/camel/MatcherSplitter.java
@@ -130,6 +130,8 @@ public class MatcherSplitter {
LOGGER.warn("Encountered error while executing matcher {}. matching all.", matcher, ex);
matchedRcpts = mail.getRecipients();
// no need to verify addresses
+ } else if (onMatchException.equalsIgnoreCase("propagate")) {
+ throw new RuntimeException(me);
} else {
ProcessorUtil.handleException(me, mail, matcher.getMatcherConfig().getMatcherName(), onMatchException, LOGGER);
}
diff --git a/src/site/xdoc/server/config-mailetcontainer.xml b/src/site/xdoc/server/config-mailetcontainer.xml
index e80af19..c475f9a 100644
--- a/src/site/xdoc/server/config-mailetcontainer.xml
+++ b/src/site/xdoc/server/config-mailetcontainer.xml
@@ -88,8 +88,13 @@
process the mail using the <strong>error</strong> processor.</p>
<p>The <strong>onMailetException</strong> property allows you to override this behaviour. You can specify another
- processor than the <strong>error</strong> one for handling the errors of this mailet. The <strong>ignore</strong> special value also
- allows to continue processing and ignore the error.</p>
+ processor than the <strong>error</strong> one for handling the errors of this mailet. <br/>
+
+ The <strong>ignore</strong> special value also allows to continue processing and ignore the error. <br/>
+ The <strong>propagate</strong> special value causes the mailet container to rethrow the
+ exception, propagating it to the execution context. In an SMTP execution context, the spooler will then requeue
+ the item and automatic retries will be setted up - note that attempts will be done for each recipients. In LMTP
+ (if LMTP is configured to execute the mailetContainer), the entire mail transaction is reported as failed to the caller.</p>
<p>Moreover, the <strong>onMatcherException</strong> allows you to override matcher error handling. You can
specify another processor than the <strong>error</strong> one for handling the errors of this mailet. The <strong>matchall</strong>
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org