Repository: james-project Updated Branches: refs/heads/master b28423767 -> 9ce8f34ef
JAMES-1773: Refactor RRT and make it's covered by test Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/e7e5476e Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/e7e5476e Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/e7e5476e Branch: refs/heads/master Commit: e7e5476e6e804f628c50f1669c7632a8fb24e9d7 Parents: 538ac51 Author: Quynh Nguyen <[email protected]> Authored: Wed Oct 5 11:15:34 2016 +0700 Committer: Quynh Nguyen <[email protected]> Committed: Wed Nov 30 09:28:39 2016 +0700 ---------------------------------------------------------------------- .../apache/mailet/base/MailAddressFixture.java | 4 +- .../AbstractRecipientRewriteTableMailet.java | 198 ----------- .../james/transport/mailets/LocalDelivery.java | 4 +- .../mailets/RecipientRewriteTable.java | 60 ++-- .../mailets/RecipientRewriteTableProcessor.java | 314 +++++++++++++++++ .../UsersRepositoryAliasingForwarding.java | 91 ++--- .../mailets/RecipientRewriteTableMock.java | 152 --------- .../RecipientRewriteTableProcessorTest.java | 338 +++++++++++++++++++ .../mailets/RecipientRewriteTableTest.java | 135 +++----- 9 files changed, 759 insertions(+), 537 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/e7e5476e/mailet/base/src/test/java/org/apache/mailet/base/MailAddressFixture.java ---------------------------------------------------------------------- diff --git a/mailet/base/src/test/java/org/apache/mailet/base/MailAddressFixture.java b/mailet/base/src/test/java/org/apache/mailet/base/MailAddressFixture.java index f98a160..d3ffb36 100644 --- a/mailet/base/src/test/java/org/apache/mailet/base/MailAddressFixture.java +++ b/mailet/base/src/test/java/org/apache/mailet/base/MailAddressFixture.java @@ -27,10 +27,12 @@ import com.google.common.base.Throwables; public class MailAddressFixture { - + public static final String JAMES_LOCAL = "localhost"; public static final String JAMES_APACHE_ORG = "james.apache.org"; public static final String JAMES2_APACHE_ORG = "james2.apache.org"; + public static final MailAddress ANY_AT_LOCAL = createMailAddress("any@" + JAMES_LOCAL); + public static final MailAddress OTHER_AT_LOCAL = createMailAddress("other@" + JAMES_LOCAL); public static final MailAddress ANY_AT_JAMES = createMailAddress("any@" + JAMES_APACHE_ORG); public static final MailAddress OTHER_AT_JAMES = createMailAddress("other@" + JAMES_APACHE_ORG); public static final MailAddress ANY_AT_JAMES2 = createMailAddress("any@" + JAMES2_APACHE_ORG); http://git-wip-us.apache.org/repos/asf/james-project/blob/e7e5476e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/AbstractRecipientRewriteTableMailet.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/AbstractRecipientRewriteTableMailet.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/AbstractRecipientRewriteTableMailet.java deleted file mode 100644 index ab89250..0000000 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/AbstractRecipientRewriteTableMailet.java +++ /dev/null @@ -1,198 +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; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Vector; - -import javax.inject.Inject; -import javax.mail.MessagingException; -import javax.mail.internet.MimeMessage; - -import org.apache.james.domainlist.api.DomainList; -import org.apache.james.domainlist.api.DomainListException; -import org.apache.james.rrt.lib.Mapping; -import org.apache.james.rrt.lib.Mappings; -import org.apache.mailet.Mail; -import org.apache.mailet.MailAddress; -import org.apache.mailet.MailetContext.LogLevel; -import org.apache.mailet.base.GenericMailet; -import org.apache.mailet.base.RFC2822Headers; - -/** - * Abstract base class which should get extended by classes which handle mapping - * operations based on RecipientRewriteTable implementations - */ -public abstract class AbstractRecipientRewriteTableMailet extends GenericMailet { - - private DomainList domainList; - - @Inject - public void setDomainList(DomainList domainList) { - this.domainList = domainList; - } - - /** - * @see org.apache.mailet.base.GenericMailet#service(org.apache.mailet.Mail) - */ - public void service(Mail mail) throws MessagingException { - Collection<MailAddress> recipients = new ArrayList<MailAddress>(mail.getRecipients()); - Collection<MailAddress> errors = new Vector<MailAddress>(); - - MimeMessage message = mail.getMessage(); - - // Set Return-Path and remove all other Return-Path headers from the - // message - // This only works because there is a placeholder inserted by - // MimeMessageWrapper - message.setHeader(RFC2822Headers.RETURN_PATH, (mail.getSender() == null ? "<>" : "<" + mail.getSender() + ">")); - - Collection<MailAddress> newRecipients = new LinkedList<MailAddress>(); - for (Iterator<MailAddress> i = recipients.iterator(); i.hasNext();) { - MailAddress recipient = i.next(); - try { - Collection<MailAddress> usernames = processMail(mail.getSender(), recipient, message); - - // if the username is null or changed we remove it from the - // remaining recipients - if (usernames == null) { - i.remove(); - } else { - i.remove(); - // if the username has been changed we add a new recipient - // with the new name. - newRecipients.addAll(usernames); - } - - } catch (Exception ex) { - getMailetContext().log(LogLevel.INFO, "Error while storing mail.", ex); - errors.add(recipient); - } - } - - if (newRecipients.size() > 0) { - recipients.addAll(newRecipients); - } - - if (!errors.isEmpty()) { - // If there were errors, we redirect the email to the ERROR - // processor. - // In order for this server to meet the requirements of the SMTP - // specification, mails on the ERROR processor must be returned to - // the sender. Note that this email doesn't include any details - // regarding the details of the failure(s). - // In the future we may wish to address this. - getMailetContext().sendMail(mail.getSender(), errors, message, Mail.ERROR); - } - mail.setRecipients(recipients); - if (recipients.size() == 0) { - // We always consume this message - mail.setState(Mail.GHOST); - } - } - - /** - * Handle the given mappings to map the original recipient to the right one - * - * @param mappings - * a collection of mappings for the given recipient - * @param sender - * the sender of the mail - * @param recipient - * the original recipient of the email - * @param message - * the mail message - * @return a collection of mapped recpient addresses - * - * @throws MessagingException - */ - protected Collection<MailAddress> handleMappings(Mappings mappings, MailAddress sender, MailAddress recipient, MimeMessage message) throws MessagingException { - Iterator<Mapping> i = mappings.iterator(); - Collection<MailAddress> remoteRecipients = new ArrayList<MailAddress>(); - Collection<MailAddress> localRecipients = new ArrayList<MailAddress>(); - while (i.hasNext()) { - Mapping rcpt = i.next(); - - if (!rcpt.hasDomain()) { - // the mapping contains no domain name, use the default domain - try { - rcpt = rcpt.appendDomain(domainList.getDefaultDomain()); - } catch (DomainListException e) { - throw new MessagingException("Unable to access DomainList", e); - } - } - - MailAddress nextMap = new MailAddress(rcpt.asString()); - if (getMailetContext().isLocalServer(nextMap.getDomain())) { - localRecipients.add(nextMap); - } else { - remoteRecipients.add(nextMap); - } - } - - if (remoteRecipients.size() > 0) { - try { - getMailetContext().sendMail(sender, remoteRecipients, message); - StringBuilder logBuffer = new StringBuilder(128).append("Mail for ").append(recipient).append(" forwarded to "); - for (Iterator<MailAddress> j = remoteRecipients.iterator(); j.hasNext();) { - logBuffer.append(j.next()); - if (j.hasNext()) - logBuffer.append(", "); - } - getMailetContext().log(LogLevel.INFO, logBuffer.toString()); - } catch (MessagingException me) { - StringBuilder logBuffer = new StringBuilder(128).append("Error forwarding mail to "); - for (Iterator<MailAddress> j = remoteRecipients.iterator(); j.hasNext();) { - logBuffer.append(j.next()); - if (j.hasNext()) - logBuffer.append(", "); - } - logBuffer.append("attempting local delivery"); - - getMailetContext().log(LogLevel.INFO, logBuffer.toString()); - throw me; - } - } - - if (localRecipients.size() > 0) { - return localRecipients; - } else { - return null; - } - } - - /** - * Process the mail - * - * @param sender - * the sender of the mail - * @param recipient - * the recipient of the mail - * @param message - * the mail message - * @return collection of recipients - * - * @throws MessagingException - */ - public abstract Collection<MailAddress> processMail(MailAddress sender, MailAddress recipient, MimeMessage message) throws MessagingException; -} http://git-wip-us.apache.org/repos/asf/james-project/blob/e7e5476e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/LocalDelivery.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/LocalDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/LocalDelivery.java index 71dd0f5..70a193e 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/LocalDelivery.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/LocalDelivery.java @@ -56,9 +56,7 @@ public class LocalDelivery extends GenericMailet { @Named("mailboxmanager") MailboxManager mailboxManager, DomainList domainList) { this.usersRepository = usersRepository; this.mailboxManager = mailboxManager; - this.recipientRewriteTable = new RecipientRewriteTable(); - recipientRewriteTable.setDomainList(domainList); - recipientRewriteTable.setRecipientRewriteTable(rrt); + this.recipientRewriteTable = new RecipientRewriteTable(rrt, domainList); } public void service(Mail mail) throws MessagingException { http://git-wip-us.apache.org/repos/asf/james-project/blob/e7e5476e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java index eab2e90..f3a356a 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java @@ -19,24 +19,24 @@ package org.apache.james.transport.mailets; -import java.util.ArrayList; -import java.util.Collection; - import javax.inject.Inject; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; -import org.apache.james.rrt.api.RecipientRewriteTable.ErrorMappingException; -import org.apache.james.rrt.api.RecipientRewriteTableException; -import org.apache.james.rrt.lib.Mappings; -import org.apache.mailet.MailAddress; +import org.apache.james.domainlist.api.DomainList; +import org.apache.mailet.Mail; +import org.apache.mailet.base.GenericMailet; + +import com.google.common.base.Preconditions; /** * Mailet which should get used when using RecipientRewriteTable-Store to * implementations for mappings of forwards and aliases. */ -public class RecipientRewriteTable extends AbstractRecipientRewriteTableMailet { - private org.apache.james.rrt.api.RecipientRewriteTable vut; +public class RecipientRewriteTable extends GenericMailet { + private final org.apache.james.rrt.api.RecipientRewriteTable virtualTableStore; + private final DomainList domainList; + private RecipientRewriteTableProcessor processor; /** * Sets the virtual table store. @@ -45,35 +45,37 @@ public class RecipientRewriteTable extends AbstractRecipientRewriteTableMailet { * the vutStore to set, possibly null */ @Inject - public final void setRecipientRewriteTable(org.apache.james.rrt.api.RecipientRewriteTable vut) { - this.vut = vut; + public RecipientRewriteTable(org.apache.james.rrt.api.RecipientRewriteTable virtualTableStore, DomainList domainList) { + this.virtualTableStore = virtualTableStore; + this.domainList = domainList; + } + + @Override + public void init() throws MessagingException { + processor = new RecipientRewriteTableProcessor(virtualTableStore, domainList, getMailetContext()); } + /** - * @see org.apache.james.transport.mailets.AbstractRecipientRewriteTableMailet#processMail(MailAddress, MailAddress, MimeMessage) + * The service rewrite the recipient list of mail. The method should: + * - Set Return-Path and remove all other Return-Path headers from the mail's message. This only works because there is a placeholder inserted by MimeMessageWrapper + * - If there were errors, we redirect the email to the ERROR processor. In order for this server to meet the requirements of the SMTP + * specification, mails on the ERROR processor must be returned to the sender. Note that this email doesn't include any details + * regarding the details of the failure(s). In the future we may wish to address this. + * - Set the mail's state to <code>Mail.GHOST</code> if the recipients be empty after rewriting. */ - public Collection<MailAddress> processMail(MailAddress sender, MailAddress recipient, MimeMessage message) throws MessagingException { - try { - Mappings mappings = vut.getMappings(recipient.getLocalPart(), recipient.getDomain()); + @Override + public void service(Mail mail) throws MessagingException { + Preconditions.checkNotNull(mail); + MimeMessage message = mail.getMessage(); - if (mappings != null) { - return handleMappings(mappings, sender, recipient, message); - } - } catch (ErrorMappingException e) { - String errorBuffer = "A problem as occoured trying to alias and forward user " + recipient + ": " + e.getMessage(); - throw new MessagingException(errorBuffer); - } catch (RecipientRewriteTableException e) { - throw new MessagingException("Unable to access RecipientRewriteTable", e); + if (message != null) { + processor.processMail(mail); } - Collection<MailAddress> rcpts = new ArrayList<MailAddress>(); - rcpts.add(recipient); - return rcpts; } - /** - * @see org.apache.mailet.base.GenericMailet#getMailetInfo() - */ + @Override public String getMailetInfo() { return "RecipientRewriteTable Mailet"; } http://git-wip-us.apache.org/repos/asf/james-project/blob/e7e5476e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessor.java ---------------------------------------------------------------------- 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 new file mode 100644 index 0000000..4edf95b --- /dev/null +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessor.java @@ -0,0 +1,314 @@ +/**************************************************************** + * 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.List; + +import javax.mail.MessagingException; +import javax.mail.internet.AddressException; +import javax.mail.internet.MimeMessage; + +import org.apache.james.domainlist.api.DomainList; +import org.apache.james.domainlist.api.DomainListException; +import org.apache.james.rrt.api.RecipientRewriteTable; +import org.apache.james.rrt.api.RecipientRewriteTable.ErrorMappingException; +import org.apache.james.rrt.api.RecipientRewriteTableException; +import org.apache.james.rrt.lib.Mapping; +import org.apache.james.rrt.lib.Mappings; +import org.apache.mailet.Mail; +import org.apache.mailet.MailAddress; +import org.apache.mailet.MailetContext; +import org.apache.mailet.MailetContext.LogLevel; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; + +public class RecipientRewriteTableProcessor { + private final org.apache.james.rrt.api.RecipientRewriteTable virtualTableStore; + private final DomainList domainList; + private final MailetContext mailetContext; + + private static final Predicate<RrtExecutionResult> recipientWithError = new Predicate<RrtExecutionResult>() { + @Override + public boolean apply(RrtExecutionResult mappingData) { + return mappingData.isError(); + } + }; + + private static final Predicate<RrtExecutionResult> recipientWithoutError = new Predicate<RrtExecutionResult>() { + @Override + public boolean apply(RrtExecutionResult mappingData) { + return !mappingData.isError(); + } + }; + + private static final Predicate<Mapping> noneDomain = new Predicate<Mapping>() { + @Override + public boolean apply(Mapping address) { + return !address.hasDomain(); + } + }; + + private static final Predicate<Mapping> haveDomain = new Predicate<Mapping>() { + @Override + public boolean apply(Mapping address) { + return address.hasDomain(); + } + }; + + private static final Function<RrtExecutionResult, List<MailAddress>> mailAddressesFromMappingData = new Function<RecipientRewriteTableProcessor.RrtExecutionResult, List<MailAddress>>() { + @Override + public List<MailAddress> apply(RrtExecutionResult mappingData) { + return mappingData.getNewRecipients() + .or(mappingData.getRecipientWithError() + .or(ImmutableList.<MailAddress>of())); + } + }; + + private static final Function<Optional<MailAddress>, MailAddress> mailAddressFromOptional = new Function<Optional<MailAddress>, MailAddress>() { + @Override + public MailAddress apply(Optional<MailAddress> mailAddress) { + return mailAddress.get(); + } + }; + + private static final Predicate<Optional<MailAddress>> mailAddressPresent = new Predicate<Optional<MailAddress>>() { + @Override + public boolean apply(Optional<MailAddress> mailAddress) { + return mailAddress.isPresent(); + } + }; + + private static final Function<Mapping, Optional<MailAddress>> mailAddressFromMapping = new Function<Mapping, Optional<MailAddress>>() { + @Override + public Optional<MailAddress> apply(Mapping addressMapping) { + try { + return Optional.of(new MailAddress(addressMapping.asString())); + } catch (AddressException e) { + return Optional.absent(); + } + } + }; + + public RecipientRewriteTableProcessor(RecipientRewriteTable virtualTableStore, DomainList domainList, MailetContext mailetContext) { + this.virtualTableStore = virtualTableStore; + this.domainList = domainList; + this.mailetContext = mailetContext; + } + + public void processMail(Mail mail) throws MessagingException{ + ImmutableList<RrtExecutionResult> mappingDatas = toMappingDatas(mail); + + ImmutableList<MailAddress> newRecipients = getRecipientsByCondition(mappingDatas, recipientWithoutError); + + ImmutableList<MailAddress> errorMailAddresses = getRecipientsByCondition(mappingDatas, recipientWithError); + + if (!errorMailAddresses.isEmpty()) { + mailetContext.sendMail(mail.getSender(), errorMailAddresses, mail.getMessage(), Mail.ERROR); + } + + if (newRecipients.isEmpty()) { + mail.setState(Mail.GHOST); + } + + mail.setRecipients(newRecipients); + } + + private ImmutableList<MailAddress> getRecipientsByCondition(ImmutableList<RrtExecutionResult> mappingDatas, Predicate<RrtExecutionResult> filterCondition) { + return FluentIterable.from(mappingDatas) + .filter(filterCondition) + .transformAndConcat(mailAddressesFromMappingData) + .toList(); + } + + private ImmutableList<RrtExecutionResult> toMappingDatas(final Mail mail) { + Function<MailAddress, RrtExecutionResult> convertToMappingData = new Function<MailAddress, RrtExecutionResult>() { + @Override + public RrtExecutionResult apply(MailAddress recipient) { + Preconditions.checkNotNull(recipient); + + return getRrtExecutionResult(mail, recipient); + } + + }; + + return FluentIterable.from(mail.getRecipients()) + .transform(convertToMappingData) + .toList(); + } + + private RrtExecutionResult getRrtExecutionResult(Mail mail, MailAddress recipient) { + try { + Mappings mappings = virtualTableStore.getMappings(recipient.getLocalPart(), recipient.getDomain()); + + if (mappings != null) { + List<MailAddress> newMailAddresses = handleMappings(mappings, mail.getSender(), recipient, mail.getMessage()); + return new RrtExecutionResult(Optional.of(newMailAddresses), Optional.<List<MailAddress>>absent()); + } + return origin(recipient); + } catch (ErrorMappingException e) { + mailetContext.log(LogLevel.INFO, "Error while process mail.", e); + return error(recipient); + } catch (RecipientRewriteTableException e) { + mailetContext.log(LogLevel.INFO, "Error while process mail.", e); + return error(recipient); + } catch (MessagingException e) { + mailetContext.log(LogLevel.INFO, "Error while process mail.", e); + return error(recipient); + } + } + + @VisibleForTesting + List<MailAddress> handleMappings(Mappings mappings, MailAddress sender, MailAddress recipient, MimeMessage message) + throws MessagingException { + ImmutableList<Mapping> addressMappingWithoutDomains = getAddressWithNoDomain(mappings, domainList); + + ImmutableList<Mapping> newAddressMappings = convertToNewMappings(mappings, addressMappingWithoutDomains); + + ImmutableList<MailAddress> mailAddresses = buildMailAddressFromMappingAddress(newAddressMappings); + + forwardToRemoteAddress(sender, recipient, message, mailAddresses); + + return getLocalAddresses(mailAddresses); + } + + private ImmutableList<Mapping> convertToNewMappings(final Mappings mappings, + ImmutableList<Mapping> addressWithoutDomains) { + return FluentIterable.from(mappings) + .filter(haveDomain) + .append(addressWithoutDomains) + .toList(); + } + + private ImmutableList<MailAddress> getLocalAddresses(ImmutableList<MailAddress> mailAddresses) { + return FluentIterable.from(mailAddresses) + .filter(isLocalServer()) + .toList(); + } + + private ImmutableList<MailAddress> buildMailAddressFromMappingAddress(ImmutableList<Mapping> newMappings) { + return FluentIterable.from(newMappings) + .transform(mailAddressFromMapping) + .filter(mailAddressPresent) + .transform(mailAddressFromOptional) + .toList(); + } + + private ImmutableList<Mapping> getAddressWithNoDomain(Mappings mappings, DomainList domainList) throws MessagingException { + ImmutableList<Mapping> addressWithoutDomains = FluentIterable.from(mappings) + .filter(noneDomain) + .toList(); + + if (!addressWithoutDomains.isEmpty()) { + final String defaultDomain = getDefaultDomain(domainList); + + return FluentIterable.from(addressWithoutDomains) + .transform(appendDefaultDomain(defaultDomain)) + .toList(); + } + return ImmutableList.of(); + } + + private Function<Mapping, Mapping> appendDefaultDomain(final String defaultDomain) { + return new Function<Mapping, Mapping>() { + @Override + public Mapping apply(Mapping address) { + return address.appendDomain(defaultDomain); + } + }; + } + + private Predicate<MailAddress> isLocalServer() { + return new Predicate<MailAddress>() { + @Override + public boolean apply(MailAddress mailAddress) { + return mailetContext.isLocalServer(mailAddress.getDomain()); + } + }; + } + + private Predicate<MailAddress> isNotLocalServer() { + return new Predicate<MailAddress>() { + @Override + public boolean apply(MailAddress mailAddress) { + return !mailetContext.isLocalServer(mailAddress.getDomain()); + } + }; + } + + private void forwardToRemoteAddress(MailAddress sender, MailAddress recipient, MimeMessage message, ImmutableList<MailAddress> mailAddresses) throws MessagingException { + ImmutableList<MailAddress> remoteAddress = FluentIterable.from(mailAddresses) + .filter(isNotLocalServer()) + .toList(); + + if (!remoteAddress.isEmpty()) { + try { + mailetContext.sendMail(sender, remoteAddress, message); + mailetContext.log(LogLevel.INFO, "Mail for " + recipient + " forwarded to " + remoteAddress); + } catch (MessagingException ex) { + mailetContext.log(LogLevel.WARN, "Error forwarding mail to " + remoteAddress); + } + } + } + + private String getDefaultDomain(DomainList domainList) throws MessagingException { + try { + return domainList.getDefaultDomain(); + } catch (DomainListException e) { + throw new MessagingException("Unable to access DomainList", e); + } + } + + private RrtExecutionResult error(MailAddress mailAddress) { + return new RrtExecutionResult(Optional.<List<MailAddress>>absent(), Optional.<List<MailAddress>>of(ImmutableList.of(mailAddress))); + } + + private RrtExecutionResult origin(MailAddress mailAddress) { + return new RrtExecutionResult(Optional.<List<MailAddress>>of(ImmutableList.of(mailAddress)), Optional.<List<MailAddress>>absent()); + } + + class RrtExecutionResult { + private final Optional<List<MailAddress>> newRecipients; + private final Optional<List<MailAddress>> recipientWithError; + + public RrtExecutionResult(Optional<List<MailAddress>> newRecipients, Optional<List<MailAddress>> recipientWithError) { + this.newRecipients = newRecipients; + this.recipientWithError = recipientWithError; + } + + public Optional<List<MailAddress>> getNewRecipients() { + return newRecipients; + } + + public Optional<List<MailAddress>> getRecipientWithError() { + return recipientWithError; + } + + public boolean isError() { + return recipientWithError.isPresent(); + } + + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/e7e5476e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/UsersRepositoryAliasingForwarding.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/UsersRepositoryAliasingForwarding.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/UsersRepositoryAliasingForwarding.java index 466f2df..fd6065a 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/UsersRepositoryAliasingForwarding.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/UsersRepositoryAliasingForwarding.java @@ -19,19 +19,16 @@ package org.apache.james.transport.mailets; -import java.util.ArrayList; -import java.util.Collection; - import javax.inject.Inject; import javax.mail.MessagingException; -import javax.mail.internet.MimeMessage; +import org.apache.james.domainlist.api.DomainList; import org.apache.james.rrt.api.RecipientRewriteTable; -import org.apache.james.rrt.api.RecipientRewriteTable.ErrorMappingException; -import org.apache.james.rrt.api.RecipientRewriteTableException; -import org.apache.james.rrt.lib.Mappings; import org.apache.james.user.api.UsersRepository; -import org.apache.mailet.MailAddress; +import org.apache.mailet.Mail; +import org.apache.mailet.base.GenericMailet; + +import com.google.common.base.Preconditions; /** * Receives a Mail from JamesSpoolManager and takes care of delivery of the @@ -49,65 +46,43 @@ import org.apache.mailet.MailAddress; * @deprecated use org.apache.james.transport.mailets.RecipientRewriteTable */ @Deprecated -public class UsersRepositoryAliasingForwarding extends AbstractRecipientRewriteTableMailet { - - /** - * The user repository for this mail server. Contains all the users with - * inboxes on this server. - */ - private UsersRepository usersRepository; - - /** - * Return a string describing this mailet. - * - * @return a string describing this mailet - */ - public String getMailetInfo() { - return "Local User Aliasing and Forwarding Mailet"; - } +public class UsersRepositoryAliasingForwarding extends GenericMailet { + private final UsersRepository usersRepository; + private final DomainList domainList; + private RecipientRewriteTableProcessor processor; @Inject - public void setUsersRepository(UsersRepository usersRepository) { + public UsersRepositoryAliasingForwarding(UsersRepository usersRepository, DomainList domainList) { this.usersRepository = usersRepository; + this.domainList = domainList; } - /** - * Return null when the mail should be GHOSTed, the username string when it - * should be changed due to the ignoreUser configuration. - * - * @param sender - * @param recipient - * @param message - * @throws MessagingException - */ - public Collection<MailAddress> processMail(MailAddress sender, MailAddress recipient, MimeMessage message) throws MessagingException { - if (recipient == null) { - throw new IllegalArgumentException("Recipient for mail to be spooled cannot be null."); - } - if (message == null) { - throw new IllegalArgumentException("Mail message to be spooled cannot be null."); + @Override + public void init() throws MessagingException { + if (usersRepository instanceof RecipientRewriteTable) { + RecipientRewriteTable virtualTableStore = (RecipientRewriteTable) usersRepository; + processor = new RecipientRewriteTableProcessor(virtualTableStore, domainList, getMailetContext()); + } else { + throw new MessagingException("The user repository is not RecipientRewriteTable"); } + } - if (usersRepository instanceof RecipientRewriteTable) { - Mappings mappings; - try { - mappings = ((RecipientRewriteTable) usersRepository).getMappings(recipient.getLocalPart(), recipient.getDomain()); - } catch (ErrorMappingException e) { - String errorBuffer = "A problem as occoured trying to alias and forward user " + recipient + ": " + e.getMessage(); - throw new MessagingException(errorBuffer); - } catch (RecipientRewriteTableException e) { - String errorBuffer = "A problem as occoured trying to alias and forward user " + recipient + ": " + e.getMessage(); - throw new MessagingException(errorBuffer); - } + @Inject + public final void setProcessor(RecipientRewriteTableProcessor processor) { + this.processor = processor; + } - if (mappings != null) { - return handleMappings(mappings, sender, recipient, message); - } - } - ArrayList<MailAddress> ret = new ArrayList<MailAddress>(); - ret.add(recipient); - return ret; + @Override + public void service(Mail mail) throws MessagingException { + Preconditions.checkNotNull(mail); + Preconditions.checkNotNull(mail.getMessage()); + Preconditions.checkNotNull(processor); + processor.processMail(mail); + } + + public String getMailetInfo() { + return "Local User Aliasing and Forwarding Mailet"; } } http://git-wip-us.apache.org/repos/asf/james-project/blob/e7e5476e/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableMock.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableMock.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableMock.java deleted file mode 100644 index f6a393a..0000000 --- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableMock.java +++ /dev/null @@ -1,152 +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; - -import org.apache.james.rrt.api.RecipientRewriteTableException; -import org.apache.james.rrt.lib.Mappings; -import org.apache.james.rrt.lib.MappingsImpl; -import org.apache.james.rrt.lib.MappingsImpl.Builder; - -import java.util.*; - -/** - * @since 15.12.12 11:40 - */ -public class RecipientRewriteTableMock implements org.apache.james.rrt.api.RecipientRewriteTable { - - public static class Mapping { - public final String address; - public final Mappings target; - - public Mapping(String address, Mappings target) { - this.address = address; - this.target = target; - } - - public Mapping(String address) { - this.address = address; - this.target = null; - } - - public Mapping to(String... target) { - return new Mapping(address, MappingsImpl.fromCollection(Arrays.asList(target))); - } - } - - public static Mapping mapFrom(String from) { - return new Mapping(from); - } - - public static RecipientRewriteTableMock rewriteTableMock(Mapping... mappings) { - return new RecipientRewriteTableMock(Arrays.asList(mappings)); - } - - private final List<Mapping> mappings = new LinkedList<Mapping>(); - - private RecipientRewriteTableMock(List<Mapping> mappings) { - this.mappings.addAll(mappings); - } - - private List<Mapping> findUserDomain(String user, String domain) { - List<Mapping> results = new LinkedList<Mapping>(); - for (Mapping m : mappings) { - String[] parts = m.address.split("@", 2); - if (parts.length == 2) { - if (user.equals(parts[0]) && domain.equals(parts[1])) { - results.add(m); - } - } - } - return results; - } - - @Override - public Mappings getMappings(String user, String domain) throws ErrorMappingException, RecipientRewriteTableException { - Builder builder = MappingsImpl.builder(); - for (Mapping m : findUserDomain(user, domain)) { - builder.addAll(m.target); - } - Mappings recipients = builder.build(); - if (recipients.isEmpty()) { - return null; - } else { - return recipients; - } - } - - @Override - public void addRegexMapping(String user, String domain, String regex) throws RecipientRewriteTableException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void removeRegexMapping(String user, String domain, String regex) throws RecipientRewriteTableException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void addAddressMapping(String user, String domain, String address) throws RecipientRewriteTableException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void removeAddressMapping(String user, String domain, String address) throws RecipientRewriteTableException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void addErrorMapping(String user, String domain, String error) throws RecipientRewriteTableException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void removeErrorMapping(String user, String domain, String error) throws RecipientRewriteTableException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public Mappings getUserDomainMappings(String user, String domain) throws RecipientRewriteTableException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void addMapping(String user, String domain, String mapping) throws RecipientRewriteTableException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void removeMapping(String user, String domain, String mapping) throws RecipientRewriteTableException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public Map<String, Mappings> getAllMappings() throws RecipientRewriteTableException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void addAliasDomainMapping(String aliasDomain, String realDomain) throws RecipientRewriteTableException { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - public void removeAliasDomainMapping(String aliasDomain, String realDomain) throws RecipientRewriteTableException { - throw new UnsupportedOperationException("Not implemented"); - } -} http://git-wip-us.apache.org/repos/asf/james-project/blob/e7e5476e/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessorTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessorTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessorTest.java new file mode 100644 index 0000000..09cd5ef --- /dev/null +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableProcessorTest.java @@ -0,0 +1,338 @@ +/**************************************************************** + * 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 static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.when; + +import java.util.Collection; +import java.util.Properties; + +import javax.mail.MessagingException; +import javax.mail.Session; +import javax.mail.internet.MimeMessage; + +import org.apache.james.domainlist.api.DomainList; +import org.apache.james.domainlist.api.DomainListException; +import org.apache.james.rrt.api.RecipientRewriteTable.ErrorMappingException; +import org.apache.james.rrt.api.RecipientRewriteTableException; +import org.apache.james.rrt.lib.MappingsImpl; +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.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import com.google.common.collect.ImmutableList; + +public class RecipientRewriteTableProcessorTest { + private static final String NONEDOMAIN = "nonedomain"; + private static final String INVALID_MAIL_ADDRESS = "server-dev@"; + + + private FakeMail mail; + private MimeMessage message; + private MappingsImpl mappings; + private FakeMailContext mailetContext; + private MailAddress nonDomainWithDefaultLocal; + + @Mock DomainList domainList; + @Mock org.apache.james.rrt.api.RecipientRewriteTable virtualTableStore; + + private RecipientRewriteTableProcessor processor; + + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + mailetContext = FakeMailContext.defaultContext(); + processor = new RecipientRewriteTableProcessor(virtualTableStore, domainList, mailetContext); + mail = FakeMail.builder().build(); + mappings = MappingsImpl.builder() + .add(MailAddressFixture.ANY_AT_JAMES.toString()) + .build(); + message = new MimeMessage(Session.getDefaultInstance(new Properties())); + + nonDomainWithDefaultLocal = new MailAddress(NONEDOMAIN + "@" + MailAddressFixture.JAMES_LOCAL); + } + + @SuppressWarnings("unchecked") + @Test(expected = MessagingException.class) + public void handleMappingsShouldThrowExceptionWhenMappingsContainAtLeastOneNoneDomainObjectButCannotGetDefaultDomain() throws Exception { + when(domainList.getDefaultDomain()).thenThrow(DomainListException.class); + mappings = MappingsImpl.builder() + .add(MailAddressFixture.ANY_AT_JAMES.toString()) + .add(NONEDOMAIN) + .add(MailAddressFixture.OTHER_AT_JAMES.toString()) + .build(); + + processor.handleMappings(mappings, MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES, message); + } + + @SuppressWarnings("unchecked") + @Test + public void handleMappingsShouldDoNotCareDefaultDomainWhenMappingsDoesNotContainAnyNoneDomainObject() throws Exception { + when(domainList.getDefaultDomain()).thenThrow(DomainListException.class); + mappings = MappingsImpl.builder() + .add(MailAddressFixture.ANY_AT_JAMES.toString()) + .add(MailAddressFixture.OTHER_AT_JAMES.toString()) + .build(); + + processor.handleMappings(mappings, MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES, message); + } + + @Test + public void handleMappingsShouldReturnTheMailAddressBelongToLocalServer() throws Exception { + when(domainList.getDefaultDomain()).thenReturn(MailAddressFixture.JAMES_LOCAL); + mappings = MappingsImpl.builder() + .add(MailAddressFixture.ANY_AT_JAMES.toString()) + .add(NONEDOMAIN) + .add(MailAddressFixture.OTHER_AT_JAMES.toString()) + .build(); + + Collection<MailAddress> result = processor.handleMappings(mappings, MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES, message); + + assertThat(result).containsOnly(nonDomainWithDefaultLocal); + } + + @Test + public void handleMappingsShouldReturnTheOnlyMailAddressBelongToLocalServer() throws Exception { + when(domainList.getDefaultDomain()).thenReturn(MailAddressFixture.JAMES2_APACHE_ORG); + + mappings = MappingsImpl.builder() + .add(MailAddressFixture.ANY_AT_JAMES.toString()) + .add(NONEDOMAIN) + .add(MailAddressFixture.ANY_AT_LOCAL.toString()) + .add(MailAddressFixture.OTHER_AT_JAMES.toString()) + .build(); + + Collection<MailAddress> result = processor.handleMappings(mappings, MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES, message); + + assertThat(result).containsOnly(MailAddressFixture.ANY_AT_LOCAL); + } + + @Test + public void handleMappingsShouldRemoveMappingElementWhenCannotCreateMailAddress() throws Exception { + when(domainList.getDefaultDomain()).thenReturn(MailAddressFixture.JAMES_LOCAL); + mappings = MappingsImpl.builder() + .add(MailAddressFixture.ANY_AT_JAMES.toString()) + .add(NONEDOMAIN) + .add(INVALID_MAIL_ADDRESS) + .add(MailAddressFixture.OTHER_AT_JAMES.toString()) + .build(); + + Collection<MailAddress> result = processor.handleMappings(mappings, MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES, message); + + assertThat(result).containsOnly(nonDomainWithDefaultLocal); + } + + @Test + public void handleMappingsShouldForwardEmailToRemoteServer() throws Exception { + when(domainList.getDefaultDomain()).thenReturn(MailAddressFixture.JAMES_LOCAL); + + mappings = MappingsImpl.builder() + .add(MailAddressFixture.ANY_AT_JAMES.toString()) + .add(NONEDOMAIN) + .add(INVALID_MAIL_ADDRESS) + .add(MailAddressFixture.OTHER_AT_JAMES.toString()) + .build(); + + processor.handleMappings(mappings, MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES, message); + + FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder() + .sender(MailAddressFixture.ANY_AT_JAMES) + .recipients(ImmutableList.of(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES)) + .message(message) + .build(); + + assertThat(mailetContext.getSentMails()).containsOnly(expected); + } + + @Test + public void handleMappingsShouldNotForwardAnyEmailToRemoteServerWhenNoMoreReomoteAddress() throws Exception { + when(domainList.getDefaultDomain()).thenReturn(MailAddressFixture.JAMES_LOCAL); + + mappings = MappingsImpl.builder() + .add(NONEDOMAIN) + .add(INVALID_MAIL_ADDRESS) + .build(); + + processor.handleMappings(mappings, MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES, message); + + assertThat(mailetContext.getSentMails()).isEmpty(); + } + + @Test + public void handleMappingWithOnlyLocalRecipient() throws Exception { + when(domainList.getDefaultDomain()).thenReturn(MailAddressFixture.JAMES_LOCAL); + + mappings = MappingsImpl.builder() + .add(NONEDOMAIN) + .add(INVALID_MAIL_ADDRESS) + .add(MailAddressFixture.ANY_AT_LOCAL.toString()) + .build(); + + Collection<MailAddress> result = processor.handleMappings(mappings, MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES, message); + + assertThat(result).containsOnly(nonDomainWithDefaultLocal, MailAddressFixture.ANY_AT_LOCAL); + } + + @Test + public void handleMappingWithOnlyRemoteRecipient() throws Exception { + when(domainList.getDefaultDomain()).thenReturn(MailAddressFixture.JAMES_LOCAL); + + mappings = MappingsImpl.builder() + .add(MailAddressFixture.ANY_AT_JAMES.toString()) + .add(MailAddressFixture.OTHER_AT_JAMES.toString()) + .build(); + + Collection<MailAddress> result = processor.handleMappings(mappings, MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES, message); + + FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder() + .sender(MailAddressFixture.ANY_AT_JAMES) + .recipients(ImmutableList.of(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES)) + .message(message) + .build(); + + assertThat(mailetContext.getSentMails()).containsOnly(expected); + assertThat(result).isEmpty(); + } + + @Test + public void processShouldNotRewriteRecipientWhenVirtualTableStoreReturnNullMappings() throws Exception { + when(virtualTableStore.getMappings(any(String.class), any(String.class))).thenReturn(null); + + mail = FakeMail.builder() + .mimeMessage(message) + .recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES) + .build(); + + processor.processMail(mail); + + assertThat(mail.getRecipients()).containsOnly(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES); + } + + @SuppressWarnings("unchecked") + @Test + public void processShouldSendMailToAllErrorRecipientsWhenErrorMappingException() throws Exception { + when(virtualTableStore.getMappings(eq("other"), eq(MailAddressFixture.JAMES_LOCAL))).thenThrow(ErrorMappingException.class); + + mail = FakeMail.builder() + .sender(MailAddressFixture.ANY_AT_JAMES) + .mimeMessage(message) + .recipients(MailAddressFixture.OTHER_AT_LOCAL, MailAddressFixture.ANY_AT_LOCAL) + .build(); + + processor.processMail(mail); + + FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder() + .sender(MailAddressFixture.ANY_AT_JAMES) + .recipient(MailAddressFixture.OTHER_AT_LOCAL) + .message(message) + .state(Mail.ERROR) + .build(); + + assertThat(mailetContext.getSentMails()).containsOnly(expected); + assertThat(mail.getRecipients()).containsOnly(MailAddressFixture.ANY_AT_LOCAL); + } + + @SuppressWarnings("unchecked") + @Test + public void processShouldSendMailToAllErrorRecipientsWhenRecipientRewriteTableException() throws Exception { + when(virtualTableStore.getMappings(eq("other"), eq(MailAddressFixture.JAMES_LOCAL))).thenThrow(RecipientRewriteTableException.class); + + mail = FakeMail.builder() + .sender(MailAddressFixture.ANY_AT_JAMES) + .mimeMessage(message) + .recipients(MailAddressFixture.OTHER_AT_LOCAL, MailAddressFixture.ANY_AT_LOCAL) + .build(); + + processor.processMail(mail); + + FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder() + .sender(MailAddressFixture.ANY_AT_JAMES) + .recipient(MailAddressFixture.OTHER_AT_LOCAL) + .message(message) + .state(Mail.ERROR) + .build(); + + assertThat(mailetContext.getSentMails()).containsOnly(expected); + assertThat(mail.getRecipients()).containsOnly(MailAddressFixture.ANY_AT_LOCAL); + } + + @SuppressWarnings("unchecked") + @Test + public void processShouldSendMailToAllErrorRecipientsWhenMessagingException() throws Exception { + when(virtualTableStore.getMappings(eq("other"), eq(MailAddressFixture.JAMES_LOCAL))).thenThrow(MessagingException.class); + + mail = FakeMail.builder() + .sender(MailAddressFixture.ANY_AT_JAMES) + .mimeMessage(message) + .recipients(MailAddressFixture.OTHER_AT_LOCAL, MailAddressFixture.ANY_AT_LOCAL) + .build(); + + processor.processMail(mail); + + FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder() + .sender(MailAddressFixture.ANY_AT_JAMES) + .recipient(MailAddressFixture.OTHER_AT_LOCAL) + .message(message) + .state(Mail.ERROR) + .build(); + + assertThat(mailetContext.getSentMails()).containsOnly(expected); + assertThat(mail.getRecipients()).containsOnly(MailAddressFixture.ANY_AT_LOCAL); + } + + @Test + public void processShouldNotSendMailWhenNoErrorRecipients() throws Exception { + when(virtualTableStore.getMappings(any(String.class), any(String.class))).thenReturn(null); + + mail = FakeMail.builder() + .mimeMessage(message) + .recipients(MailAddressFixture.ANY_AT_JAMES, nonDomainWithDefaultLocal) + .build(); + + processor.processMail(mail); + + assertThat(mailetContext.getSentMails()).isEmpty(); + } + + @Test + public void processShouldResetMailStateToGhostWhenCanNotBuildNewRecipient() throws Exception { + when(virtualTableStore.getMappings(any(String.class), any(String.class))).thenReturn(mappings); + + mail = FakeMail.builder() + .mimeMessage(message) + .recipients(MailAddressFixture.OTHER_AT_JAMES, nonDomainWithDefaultLocal) + .build(); + + processor.processMail(mail); + + assertThat(mail.getState()).isEqualTo(Mail.GHOST); + assertThat(mail.getRecipients()).isEmpty(); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/james-project/blob/e7e5476e/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableTest.java index 766f4c9..375964b 100644 --- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableTest.java +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/RecipientRewriteTableTest.java @@ -18,131 +18,74 @@ ****************************************************************/ package org.apache.james.transport.mailets; -import static org.apache.james.transport.mailets.RecipientRewriteTableMock.mapFrom; -import static org.apache.james.transport.mailets.RecipientRewriteTableMock.rewriteTableMock; -import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; -import java.util.Iterator; import java.util.Properties; -import javax.mail.Address; -import javax.mail.Message; -import javax.mail.MessagingException; import javax.mail.Session; -import javax.mail.internet.AddressException; import javax.mail.internet.MimeMessage; -import org.apache.mailet.Mail; -import org.apache.mailet.MailAddress; +import org.apache.james.domainlist.api.DomainList; import org.apache.mailet.MailetContext; +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.After; import org.junit.Before; import org.junit.Test; - -import com.google.common.base.Function; -import com.google.common.base.Throwables; -import com.google.common.collect.FluentIterable; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; public class RecipientRewriteTableTest { - private static final Session NO_SESSION = null; - - private org.apache.james.transport.mailets.RecipientRewriteTable table; + private RecipientRewriteTable mailet; - @Before - public void setUp() throws Exception { - final FakeMailContext mockMailetContext = FakeMailContext.defaultContext(); + @Mock org.apache.james.rrt.api.RecipientRewriteTable virtualTableStore; + @Mock DomainList domainList; - table = createRecipientRewriteMailet( - rewriteTableMock(mapFrom("test@localhost").to("whatever@localhost", "blah@localhost")), - mockMailetContext - ); - } + private FakeMail mail; + private MimeMessage message; + private FakeMailetConfig mailetConfig; + private MailetContext mailetContext; - private static RecipientRewriteTable createRecipientRewriteMailet( - org.apache.james.rrt.api.RecipientRewriteTable vut, - MailetContext mailContext) throws MessagingException { - RecipientRewriteTable rrt = new org.apache.james.transport.mailets.RecipientRewriteTable(); + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mailet = new RecipientRewriteTable(virtualTableStore, domainList); - FakeMailetConfig mockMailetConfig = new FakeMailetConfig("vut", mailContext, new Properties()); - // mockMailetConfig.put("recipientrewritetable", "vut"); - rrt.setRecipientRewriteTable(vut); - rrt.init(mockMailetConfig); - return rrt; - } + message = new MimeMessage(Session.getDefaultInstance(new Properties())); - @After - public void tearDown() throws Exception { - table = null; + mailetContext = FakeMailContext.defaultContext(); + mailetConfig = new FakeMailetConfig("Test", mailetContext); + mail = FakeMail.builder().build(); } @Test - public void testAddressMapping() throws Exception { - Mail mail = createMail(new String[]{"test@localhost", "apache@localhost"}); - table.service(mail); - - assertEquals(3, mail.getRecipients().size()); - Iterator<MailAddress> it = mail.getRecipients().iterator(); - assertEquals("whatever@localhost", it.next().toString()); - assertEquals("blah@localhost", it.next().toString()); - assertEquals("apache@localhost", it.next().toString()); - + public void getMailetInfoShouldReturnCorrectInformation() throws Exception { + assertThat(mailet.getMailetInfo()).isEqualTo("RecipientRewriteTable Mailet"); } - /** - * @return - * @throws MessagingException - */ - private Mail createMail(String[] recipients) throws MessagingException { - return FakeMail.builder() - .recipients(FluentIterable.of(recipients) - .transform(new Function<String, MailAddress>() { - - @Override - public MailAddress apply(String recipient) { - try { - return new MailAddress(recipient); - } catch (AddressException e) { - throw Throwables.propagate(e); - } - } - }).toList()) - .mimeMessage(new MimeMessage(NO_SESSION)) - .build(); + @Test(expected = NullPointerException.class) + public void serviceShouldThrowExceptionWithNullMail() throws Exception { + mailet.service(null); } @Test - public void testMixedLocalAndRemoteRecipients() throws Exception { - RecordingMailContext context = new RecordingMailContext(); - RecipientRewriteTable mailet = createRecipientRewriteMailet( - rewriteTableMock(mapFrom("mixed@localhost").to("a@localhost", "[email protected]")), - context - ); - Mail mail = createMail(new String[]{"mixed@localhost"}); + public void serviceShouldDoNothingIfAbsentMessageInMail() throws Exception { mailet.service(mail); - //the mail must be send via the context to [email protected], the other - //recipient a@localhost must be in the recipient list of the message - //after processing. - assertEquals(context.getSendmails().size(), 1); - MimeMessage msg = context.getSendmails().get(0).getMessage(); - if (msg == null) { - msg = context.getSendmails().get(0).getMail().getMessage(); - } - Address[] mimeMessageRecipients = msg.getRecipients(Message.RecipientType.TO); - if (mimeMessageRecipients != null && mimeMessageRecipients.length == 1) { - assertEquals(msg.getRecipients(Message.RecipientType.TO)[0].toString(), "[email protected]"); - } else { - assertEquals(context.getSendmails().get(0).getRecipients().size(), 1); - MailAddress rec = context.getSendmails().get(0).getRecipients().iterator().next(); - assertEquals(rec.toInternetAddress().toString(), "[email protected]"); - } - - assertEquals(mail.getRecipients().size(), 1); - MailAddress localRec = mail.getRecipients().iterator().next(); - assertEquals(localRec.toInternetAddress().toString(), "a@localhost"); } + + @Test + public void serviceShouldWork() throws Exception { + mailet.init(mailetConfig); + mail = FakeMail.builder() + .mimeMessage(message) + .recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES) + .build(); + mailet.service(mail); + + assertThat(mail.getRecipients()).containsOnly(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
