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 cdf0abb48746ca9ea7d7c6cab88afc1507f1e205 Author: Benoit Tellier <[email protected]> AuthorDate: Sat Apr 11 12:24:23 2020 +0700 JAMES-3147 Group localDomain calls for RecipientIsLocal --- .../main/java/org/apache/mailet/MailetContext.java | 8 ++++ .../james/transport/matchers/HostIsLocal.java | 37 ++++++++++++++--- .../james/transport/matchers/RecipientIsLocal.java | 17 ++++---- .../transport/matchers/RecipientIsLocalTest.java | 11 +++-- .../mailetcontainer/impl/JamesMailetContext.java | 5 +++ .../james/mailetcontainer/impl/LocalResources.java | 47 ++++++++++++++++++---- .../impl/JamesMailetContextTest.java | 31 ++++++++++++++ .../mailets/RecipientRewriteTableProcessor.java | 34 +++++++++++++--- 8 files changed, 158 insertions(+), 32 deletions(-) diff --git a/mailet/api/src/main/java/org/apache/mailet/MailetContext.java b/mailet/api/src/main/java/org/apache/mailet/MailetContext.java index 44c0e9a..459dac0 100644 --- a/mailet/api/src/main/java/org/apache/mailet/MailetContext.java +++ b/mailet/api/src/main/java/org/apache/mailet/MailetContext.java @@ -32,6 +32,8 @@ import org.apache.james.core.Domain; import org.apache.james.core.MailAddress; import org.slf4j.Logger; +import com.github.steveash.guavate.Guavate; + /** * Defines a set of methods that can be used to interact with the mailet * container. For example, it can be used to send a new message, to deliver @@ -266,6 +268,12 @@ public interface MailetContext { */ boolean isLocalEmail(MailAddress mailAddress); + default Collection<MailAddress> localRecipients(Collection<MailAddress> recipients) { + return recipients.stream() + .filter(this::isLocalEmail) + .collect(Guavate.toImmutableList()); + } + /** * Returns the hostnames that are specified as mail handlers for * the given domain name. The host names are determined using DNS diff --git a/mailet/standard/src/main/java/org/apache/james/transport/matchers/HostIsLocal.java b/mailet/standard/src/main/java/org/apache/james/transport/matchers/HostIsLocal.java index 46763a9..653bf9c 100644 --- a/mailet/standard/src/main/java/org/apache/james/transport/matchers/HostIsLocal.java +++ b/mailet/standard/src/main/java/org/apache/james/transport/matchers/HostIsLocal.java @@ -21,17 +21,44 @@ package org.apache.james.transport.matchers; +import java.util.Collection; +import java.util.Map; +import java.util.stream.Stream; + +import javax.mail.MessagingException; + +import org.apache.james.core.Domain; import org.apache.james.core.MailAddress; -import org.apache.mailet.base.GenericRecipientMatcher; +import org.apache.mailet.Mail; +import org.apache.mailet.base.GenericMatcher; + +import com.github.steveash.guavate.Guavate; /** * Matches mail to Domains which are local * . */ -public class HostIsLocal extends GenericRecipientMatcher { - +public class HostIsLocal extends GenericMatcher { @Override - public boolean matchRecipient(MailAddress recipient) { - return getMailetContext().isLocalServer(recipient.getDomain()); + public Collection<MailAddress> match(Mail mail) throws MessagingException { + return recipientsByDomains(mail) + .flatMap(this::hasLocalDomain) + .collect(Guavate.toImmutableList()); + } + + private Stream<MailAddress> hasLocalDomain(Map.Entry<Domain, Collection<MailAddress>> entry) { + if (getMailetContext().isLocalServer(entry.getKey())) { + return entry.getValue().stream(); + } + return Stream.empty(); + } + + private Stream<Map.Entry<Domain, Collection<MailAddress>>> recipientsByDomains(Mail mail) { + return mail.getRecipients() + .stream() + .collect(Guavate.toImmutableListMultimap(MailAddress::getDomain)) + .asMap() + .entrySet() + .stream(); } } diff --git a/mailet/standard/src/main/java/org/apache/james/transport/matchers/RecipientIsLocal.java b/mailet/standard/src/main/java/org/apache/james/transport/matchers/RecipientIsLocal.java index e21b056..6e24951 100644 --- a/mailet/standard/src/main/java/org/apache/james/transport/matchers/RecipientIsLocal.java +++ b/mailet/standard/src/main/java/org/apache/james/transport/matchers/RecipientIsLocal.java @@ -21,20 +21,21 @@ package org.apache.james.transport.matchers; +import java.util.Collection; + +import javax.mail.MessagingException; + import org.apache.james.core.MailAddress; -import org.apache.mailet.MailetContext; -import org.apache.mailet.base.GenericRecipientMatcher; +import org.apache.mailet.Mail; +import org.apache.mailet.base.GenericMatcher; /** * Matches mail where the recipient is local. * @version 1.0.0, 24/04/1999 */ -public class RecipientIsLocal extends GenericRecipientMatcher { - +public class RecipientIsLocal extends GenericMatcher { @Override - public boolean matchRecipient(MailAddress recipient) { - MailetContext mailetContext = getMailetContext(); - //This might change after startup - return mailetContext.isLocalEmail(recipient); + public Collection<MailAddress> match(Mail mail) throws MessagingException { + return getMailetContext().localRecipients(mail.getRecipients()); } } diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/RecipientIsLocalTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/RecipientIsLocalTest.java index eb459f7..d00e5cb 100644 --- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/RecipientIsLocalTest.java +++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/RecipientIsLocalTest.java @@ -20,6 +20,7 @@ package org.apache.james.transport.matchers; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -30,6 +31,7 @@ import org.apache.mailet.base.test.FakeMail; import org.apache.mailet.base.test.FakeMatcherConfig; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.testcontainers.shaded.com.google.common.collect.ImmutableList; public class RecipientIsLocalTest { @@ -59,24 +61,21 @@ public class RecipientIsLocalTest { @Test public void matchShouldNotReturnNonExistingAddress() throws Exception { - when(mailetContext.isLocalEmail(mailAddress1)).thenReturn(false); - when(mailetContext.isLocalEmail(mailAddress2)).thenReturn(false); + when(mailetContext.localRecipients(any())).thenReturn(ImmutableList.of()); assertThat(testee.match(mail)).isEmpty(); } @Test public void matchShouldNotReturnNonExistingAddressIfSomeRecipientsExists() throws Exception { - when(mailetContext.isLocalEmail(mailAddress1)).thenReturn(true); - when(mailetContext.isLocalEmail(mailAddress2)).thenReturn(false); + when(mailetContext.localRecipients(any())).thenReturn(ImmutableList.of(mailAddress1)); assertThat(testee.match(mail)).containsOnly(mailAddress1); } @Test public void matchShouldHandleTwoValidAddress() throws Exception { - when(mailetContext.isLocalEmail(mailAddress1)).thenReturn(true); - when(mailetContext.isLocalEmail(mailAddress2)).thenReturn(true); + when(mailetContext.localRecipients(any())).thenReturn(ImmutableList.of(mailAddress1, mailAddress2)); assertThat(testee.match(mail)).containsOnly(mailAddress1, mailAddress2); } diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java index 98eb92f..99f0c5d 100644 --- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java +++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java @@ -240,6 +240,11 @@ public class JamesMailetContext implements MailetContext, Configurable, Disposab } @Override + public Collection<MailAddress> localRecipients(Collection<MailAddress> recipients) { + return localResources.localEmails(recipients); + } + + @Override public MailAddress getPostmaster() { return postmaster; } diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java index 9e76c1b..bd41f84 100644 --- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java +++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java @@ -19,7 +19,10 @@ package org.apache.james.mailetcontainer.impl; +import java.util.Collection; import java.util.EnumSet; +import java.util.Map; +import java.util.stream.Stream; import javax.inject.Inject; import javax.mail.internet.ParseException; @@ -36,6 +39,7 @@ import org.apache.james.user.api.UsersRepository; import org.apache.james.user.api.UsersRepositoryException; import com.github.fge.lambdas.Throwing; +import com.github.steveash.guavate.Guavate; class LocalResources { private static final EnumSet<Mapping.Type> ALIAS_TYPES = EnumSet.of(Mapping.Type.Alias, Mapping.Type.DomainAlias); @@ -78,18 +82,45 @@ class LocalResources { if (!isLocalServer(mailAddress.getDomain())) { return false; } - try { - return isLocaluser(mailAddress) - || isLocalAlias(mailAddress); - } catch (UsersRepositoryException e) { - throw new RuntimeException("Unable to retrieve users", e); - } catch (RecipientRewriteTable.ErrorMappingException | RecipientRewriteTableException e) { - throw new RuntimeException("Unable to retrieve RRTs", e); - } + return belongsToALocalUser(mailAddress); } return false; } + private boolean belongsToALocalUser(MailAddress mailAddress) { + try { + return isLocaluser(mailAddress) + || isLocalAlias(mailAddress); + } catch (UsersRepositoryException e) { + throw new RuntimeException("Unable to retrieve users", e); + } catch (RecipientRewriteTable.ErrorMappingException | RecipientRewriteTableException e) { + throw new RuntimeException("Unable to retrieve RRTs", e); + } + } + + Collection<MailAddress> localEmails(Collection<MailAddress> mailAddresses) { + return addressByDomains(mailAddresses) + .flatMap(this::hasLocalDomain) + .filter(this::belongsToALocalUser) + .collect(Guavate.toImmutableList()); + } + + private Stream<MailAddress> hasLocalDomain(Map.Entry<Domain, Collection<MailAddress>> entry) { + if (isLocalServer(entry.getKey())) { + return entry.getValue().stream(); + } + return Stream.empty(); + } + + private Stream<Map.Entry<Domain, Collection<MailAddress>>> addressByDomains(Collection<MailAddress> mailAddresses) { + return mailAddresses.stream() + .collect(Guavate.toImmutableListMultimap( + MailAddress::getDomain)) + .asMap() + .entrySet() + .stream(); + } + private boolean isLocaluser(MailAddress mailAddress) throws UsersRepositoryException { return localUsers.contains(localUsers.getUsername(mailAddress)); } diff --git a/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java b/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java index ea2320b..0215f09 100644 --- a/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java +++ b/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java @@ -225,6 +225,37 @@ public class JamesMailetContextTest { } @Test + public void localRecipientsShouldReturnAddressWhenUserExists() throws Exception { + domainList.addDomain(DOMAIN_COM); + usersRepository.addUser(USERMAIL, PASSWORD); + + assertThat(testee.localRecipients(ImmutableList.of(mailAddress))).containsOnly(mailAddress); + } + + @Test + public void localRecipientsShouldReturnOnlyExistingUsers() throws Exception { + domainList.addDomain(DOMAIN_COM); + usersRepository.addUser(USERMAIL, PASSWORD); + + assertThat(testee.localRecipients( + ImmutableList.of(mailAddress, + MailAddressFixture.RECIPIENT2))) + .containsOnly(mailAddress); + } + + @Test + public void localRecipientsShouldNotReturnAddressWhenUserDoNotExists() throws Exception { + domainList.addDomain(DOMAIN_COM); + + assertThat(testee.localRecipients(ImmutableList.of(mailAddress))).isEmpty(); + } + + @Test + public void localRecipientsShouldNotReturnAddressWhenDomainDoNotExists() throws Exception { + assertThat(testee.localRecipients(ImmutableList.of(mailAddress))).isEmpty(); + } + + @Test public void isLocalEmailShouldBeFalseWhenMailIsNull() { assertThat(testee.isLocalEmail(null)).isFalse(); } diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessor.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessor.java index dd890c4..2e49953 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessor.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessor.java @@ -26,6 +26,7 @@ import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.mail.MessagingException; @@ -47,9 +48,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.fge.lambdas.Throwing; +import com.github.steveash.guavate.Guavate; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; public class RecipientRewriteTableProcessor { @@ -179,17 +182,38 @@ public class RecipientRewriteTableProcessor { @VisibleForTesting List<MailAddress> handleMappings(Mappings mappings, Mail mail, MailAddress recipient) { boolean isLocal = true; - Map<Boolean, List<MailAddress>> mailAddressSplit = mappings.asStream() - .map(mapping -> mapping.appendDomainIfNone(defaultDomainSupplier)) - .map(Mapping::asMailAddress) - .flatMap(OptionalUtils::toStream) - .collect(Collectors.partitioningBy(mailAddress -> mailetContext.isLocalServer(mailAddress.getDomain()))); + Map<Boolean, List<MailAddress>> mailAddressSplit = splitRemoteMailAddresses(mappings); forwardToRemoteAddress(mail, recipient, mailAddressSplit.get(!isLocal)); return mailAddressSplit.get(isLocal); } + private ImmutableMap<Boolean, List<MailAddress>> splitRemoteMailAddresses(Mappings mappings) { + return mailAddressesPerDomain(mappings) + .collect(Collectors.partitioningBy(entry -> mailetContext.isLocalServer(entry.getKey()))) + .entrySet() + .stream() + .collect(Guavate.toImmutableMap( + Map.Entry::getKey, + entry -> entry.getValue() + .stream() + .flatMap(domainEntry -> domainEntry.getValue().stream()) + .collect(Guavate.toImmutableList()))); + } + + private Stream<Map.Entry<Domain, Collection<MailAddress>>> mailAddressesPerDomain(Mappings mappings) { + return mappings.asStream() + .map(mapping -> mapping.appendDomainIfNone(defaultDomainSupplier)) + .map(Mapping::asMailAddress) + .flatMap(OptionalUtils::toStream) + .collect(Guavate.toImmutableListMultimap( + MailAddress::getDomain)) + .asMap() + .entrySet() + .stream(); + } + private void forwardToRemoteAddress(Mail mail, MailAddress recipient, Collection<MailAddress> remoteRecipients) { if (!remoteRecipients.isEmpty()) { try { --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
