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 <qngu...@linagora.com>
Authored: Wed Oct 5 11:15:34 2016 +0700
Committer: Quynh Nguyen <qngu...@linagora.com>
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", 
"b...@remote.com")),
-            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 b...@remote.com, 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(), 
"b...@remote.com");
-        } else {
-            assertEquals(context.getSendmails().get(0).getRecipients().size(), 
1);
-            MailAddress rec = 
context.getSendmails().get(0).getRecipients().iterator().next();
-            assertEquals(rec.toInternetAddress().toString(), 
"b...@remote.com");
-        }
-
-        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: server-dev-unsubscr...@james.apache.org
For additional commands, e-mail: server-dev-h...@james.apache.org

Reply via email to