You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ni...@apache.org on 2014/10/20 05:55:42 UTC

[1/4] git commit: CAMEL-7873 Add capability to sort received messages

Repository: camel
Updated Branches:
  refs/heads/master f8c140f01 -> 5eed4d966


CAMEL-7873 Add capability to sort received messages

Add copyright headers


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/1149fae7
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/1149fae7
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/1149fae7

Branch: refs/heads/master
Commit: 1149fae798de25ec43b330d41b11db85273c3765
Parents: f8c140f
Author: Christian Amann <ch...@qaware.de>
Authored: Wed Sep 24 13:15:43 2014 +0200
Committer: Willem Jiang <wi...@gmail.com>
Committed: Mon Oct 20 11:34:06 2014 +0800

----------------------------------------------------------------------
 components/camel-mail/pom.xml                   |   5 +
 .../camel/component/mail/MailConsumer.java      |  86 +++++++--
 .../camel/component/mail/MailEndpoint.java      |  36 ++--
 .../apache/camel/component/mail/MailSorter.java | 174 +++++++++++++++++++
 .../camel/component/mail/MailSortTermTest.java  | 121 +++++++++++++
 .../camel/component/mail/MailSorterTest.java    | 154 ++++++++++++++++
 6 files changed, 552 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/1149fae7/components/camel-mail/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-mail/pom.xml b/components/camel-mail/pom.xml
index 50cc9fa..4888f4d 100644
--- a/components/camel-mail/pom.xml
+++ b/components/camel-mail/pom.xml
@@ -88,6 +88,11 @@
             <artifactId>slf4j-log4j12</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 </project>

http://git-wip-us.apache.org/repos/asf/camel/blob/1149fae7/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java
index 065a4ef..29835aa 100644
--- a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java
+++ b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java
@@ -27,7 +27,11 @@ import javax.mail.Header;
 import javax.mail.Message;
 import javax.mail.MessagingException;
 import javax.mail.Store;
+import javax.mail.search.SearchTerm;
 
+import com.sun.mail.imap.IMAPFolder;
+import com.sun.mail.imap.IMAPStore;
+import com.sun.mail.imap.SortTerm;
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.impl.ScheduledBatchPollingConsumer;
@@ -51,6 +55,11 @@ public class MailConsumer extends ScheduledBatchPollingConsumer {
     private Folder folder;
     private Store store;
 
+    /**
+     * Is true if server is an IMAP server and supports IMAP SORT extension.
+     */
+    private boolean serverCanSort;
+
     public MailConsumer(MailEndpoint endpoint, Processor processor, JavaMailSender sender) {
         super(endpoint, processor);
         this.sender = sender;
@@ -103,18 +112,7 @@ public class MailConsumer extends ScheduledBatchPollingConsumer {
         try {
             int count = folder.getMessageCount();
             if (count > 0) {
-                Message[] messages;
-
-                if (getEndpoint().getSearchTerm() != null) {
-                    // use custom search term
-                    messages = folder.search(getEndpoint().getSearchTerm());
-                } else if (getEndpoint().getConfiguration().isUnseen()) {
-                    // only unseen messages
-                    messages = folder.search(new SearchTermBuilder().unseen().build());
-                } else {
-                    // get all messages
-                    messages = folder.getMessages();
-                }
+                Message[] messages = retrieveMessages();
 
                 polledMessages = processBatch(CastUtils.cast(createExchanges(messages)));
             } else if (count == -1) {
@@ -229,6 +227,51 @@ public class MailConsumer extends ScheduledBatchPollingConsumer {
         }
     }
 
+    /**
+     * @return Messages from input folder according to the search and sort criteria stored in the endpoint
+     * @throws MessagingException If message retrieval fails
+     */
+    private Message[] retrieveMessages() throws MessagingException {
+        Message[] messages;
+        final SortTerm[] sortTerm = getEndpoint().getSortTerm();
+        final SearchTerm searchTerm = computeSearchTerm();
+        if (sortTerm != null && serverCanSort) {
+            final IMAPFolder imapFolder = (IMAPFolder) folder;
+            if (searchTerm != null) {
+                // Sort and search using server capability
+                messages = imapFolder.getSortedMessages(sortTerm, searchTerm);
+            } else {
+                // Only sort using server capability
+                messages = imapFolder.getSortedMessages(sortTerm);
+            }
+        } else {
+            if (searchTerm != null) {
+                // Only search
+                messages = folder.search(searchTerm);
+            } else {
+                // No search
+                messages = folder.getMessages();
+            }
+            // Now we can sort (emulate email sort but restrict sort terms)
+            if (sortTerm != null) {
+                MailSorter.sortMessages(messages, sortTerm);
+            }
+        }
+        return messages;
+    }
+
+    /**
+     * @return Search term from endpoint (including "seen" check) or null if there is no search term
+     */
+    private SearchTerm computeSearchTerm() {
+        if (getEndpoint().getSearchTerm() != null) {
+            return getEndpoint().getSearchTerm();
+        } else if (getEndpoint().getConfiguration().isUnseen()) {
+            return new SearchTermBuilder().unseen().build();
+        }
+        return null;
+    }
+
     protected Queue<Exchange> createExchanges(Message[] messages) throws MessagingException {
         Queue<Exchange> answer = new LinkedList<Exchange>();
 
@@ -423,6 +466,8 @@ public class MailConsumer extends ScheduledBatchPollingConsumer {
             }
             store = sender.getSession().getStore(config.getProtocol());
             store.connect(config.getHost(), config.getPort(), config.getUsername(), config.getPassword());
+
+            serverCanSort = hasSortCapability(store);
         }
 
         if (folder == null) {
@@ -436,6 +481,23 @@ public class MailConsumer extends ScheduledBatchPollingConsumer {
         }
     }
 
+    /**
+     * Check whether the email store has the sort capability or not.
+     *
+     * @param store Email store
+     * @return true if the store is an IMAP store and it has the store capability
+     * @throws MessagingException In case capability check fails
+     */
+    private static boolean hasSortCapability(Store store) throws MessagingException {
+        if (store instanceof IMAPStore) {
+            IMAPStore imapStore = (IMAPStore) store;
+            if (imapStore.hasCapability("SORT*")) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public MailEndpoint getEndpoint() {
         return (MailEndpoint) super.getEndpoint();

http://git-wip-us.apache.org/repos/asf/camel/blob/1149fae7/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
index e1345ac..a875612 100644
--- a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
+++ b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
@@ -16,14 +16,8 @@
  */
 package org.apache.camel.component.mail;
 
-import javax.mail.Message;
-import javax.mail.search.SearchTerm;
-
-import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
-import org.apache.camel.Processor;
-import org.apache.camel.Producer;
+import com.sun.mail.imap.SortTerm;
+import org.apache.camel.*;
 import org.apache.camel.impl.DefaultExchange;
 import org.apache.camel.impl.DefaultHeaderFilterStrategy;
 import org.apache.camel.impl.ScheduledPollEndpoint;
@@ -31,10 +25,11 @@ import org.apache.camel.spi.HeaderFilterStrategy;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 
+import javax.mail.Message;
+import javax.mail.search.SearchTerm;
+
 /**
  * Endpoint for Camel Mail.
- *
- * @version 
  */
 @UriEndpoint(scheme = "mail", consumerClass = MailConsumer.class)
 public class MailEndpoint extends ScheduledPollEndpoint {
@@ -46,6 +41,7 @@ public class MailEndpoint extends ScheduledPollEndpoint {
     @UriParam
     private int maxMessagesPerPoll;
     private SearchTerm searchTerm;
+    private SortTerm[] sortTerm;
 
     public MailEndpoint() {
     }
@@ -84,7 +80,7 @@ public class MailEndpoint extends ScheduledPollEndpoint {
     public Consumer createConsumer(Processor processor) throws Exception {
         if (configuration.getProtocol().startsWith("smtp")) {
             throw new IllegalArgumentException("Protocol " + configuration.getProtocol()
-                + " cannot be used for a MailConsumer. Please use another protocol such as pop3 or imap.");
+                    + " cannot be used for a MailConsumer. Please use another protocol such as pop3 or imap.");
         }
 
         // must use java mail sender impl as we need to get hold of a mail session
@@ -111,7 +107,7 @@ public class MailEndpoint extends ScheduledPollEndpoint {
     public boolean isSingleton() {
         return false;
     }
-    
+
     @Override
     public Exchange createExchange(ExchangePattern pattern) {
         return createExchange(pattern, null);
@@ -185,4 +181,20 @@ public class MailEndpoint extends ScheduledPollEndpoint {
         this.searchTerm = searchTerm;
     }
 
+    /**
+     * @return Sorting order for messages. Only natively supported for IMAP. Emulated to some degree when using POP3
+     * or when IMAP server does not have the SORT capability.
+     * @see com.sun.mail.imap.SortTerm
+     */
+    public SortTerm[] getSortTerm() {
+        return sortTerm == null ? null : sortTerm.clone();
+    }
+
+    /**
+     * @param sortTerm {@link #getSortTerm()}
+     */
+    public void setSortTerm(SortTerm[] sortTerm) {
+        this.sortTerm = (sortTerm == null ? null : sortTerm.clone());
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/1149fae7/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailSorter.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailSorter.java b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailSorter.java
new file mode 100644
index 0000000..cdfb22c
--- /dev/null
+++ b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailSorter.java
@@ -0,0 +1,174 @@
+/**
+ * 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.camel.component.mail;
+
+import com.sun.mail.imap.SortTerm;
+
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.internet.InternetAddress;
+import java.util.*;
+
+/**
+ * Utility class for sorting of mail messages
+ */
+public final class MailSorter {
+    /**
+     * No instances
+     */
+    private MailSorter() {
+    }
+
+    /**
+     * Sort the messages. This emulates sorting the messages on the server if the server doesn't have the sorting
+     * capability. See RFC 5256
+     * Does not support complex sorting like in the RFC (with Base Subject or other similar stuff), just simple
+     * comparisons.
+     *
+     * @param messages Messages to sort. Are sorted in place
+     * @param sortTerm Sort term
+     */
+    public static void sortMessages(Message[] messages, final SortTerm[] sortTerm) {
+        final List<SortTermWithDescending> sortTermsWithDescending = getSortTermsWithDescending(sortTerm);
+        sortMessages(messages, sortTermsWithDescending);
+    }
+
+    /**
+     * Compute the potentially descendingd sort terms from the input list
+     *
+     * @param sortTerm Input list
+     * @return Sort terms list including if the respective sort should be sorted in descending order
+     */
+    private static List<SortTermWithDescending> getSortTermsWithDescending(SortTerm[] sortTerm) {
+        // List of reversable sort terms. If the boolean is true the respective sort term is descendingd
+        final List<SortTermWithDescending> sortTermsWithDescending = new ArrayList<>(sortTerm.length);
+        // Descending next item in input because the last item was a "descending"
+        boolean descendingNext = false;
+        for (SortTerm term : sortTerm) {
+            if (term.equals(SortTerm.REVERSE)) {
+                if (descendingNext) {
+                    throw new IllegalArgumentException("Double reverse in sort term is not allowed");
+                }
+                descendingNext = true;
+            } else {
+                sortTermsWithDescending.add(new SortTermWithDescending(term, descendingNext));
+                descendingNext = false;
+            }
+        }
+        return sortTermsWithDescending;
+    }
+
+    /**
+     * Sort messages using the list of properties
+     *
+     * @param messages             Messages to sort. Are sorted in place
+     * @param sortTermsWithDescending Sort terms list including if the respective sort should be sorted in descending order
+     */
+    private static void sortMessages(Message[] messages, final List<SortTermWithDescending> sortTermsWithDescending) {
+        Arrays.sort(messages, new Comparator<Message>() {
+            @Override
+            public int compare(Message m1, Message m2) {
+                try {
+                    for (SortTermWithDescending reversableTerm : sortTermsWithDescending) {
+                        int comparison = compareMessageProperty(m1, m2, reversableTerm.getTerm());
+                        // Descending
+                        if (reversableTerm.isDescending()) {
+                            comparison = -comparison;
+                        }
+                        // Abort on first non-equal
+                        if (comparison != 0) {
+                            return comparison;
+                        }
+                    }
+                    // Equal
+                    return 0;
+                } catch (MessagingException e) {
+                    throw new IllegalArgumentException(e);
+                }
+            }
+        });
+    }
+
+    /**
+     * Compare the value of the property of the two messages.
+     *
+     * @param msg1     Message 1
+     * @param msg2     Message 2
+     * @param property Property to compare
+     * @return msg1.property.compareTo(msg2.property)
+     * @throws javax.mail.MessagingException If message data could not be read.
+     */
+    private static int compareMessageProperty(Message msg1, Message msg2, SortTerm property) throws MessagingException {
+        if (property.equals(SortTerm.TO)) {
+            InternetAddress addr1 = (InternetAddress) msg1.getRecipients(Message.RecipientType.TO)[0];
+            InternetAddress addr2 = (InternetAddress) msg2.getRecipients(Message.RecipientType.TO)[0];
+            return addr1.getAddress().compareTo(addr2.getAddress());
+        } else if (property.equals(SortTerm.CC)) {
+            InternetAddress addr1 = (InternetAddress) msg1.getRecipients(Message.RecipientType.CC)[0];
+            InternetAddress addr2 = (InternetAddress) msg2.getRecipients(Message.RecipientType.CC)[0];
+            return addr1.getAddress().compareTo(addr2.getAddress());
+        } else if (property.equals(SortTerm.FROM)) {
+            InternetAddress addr1 = (InternetAddress) msg1.getFrom()[0];
+            InternetAddress addr2 = (InternetAddress) msg2.getFrom()[0];
+            return addr1.getAddress().compareTo(addr2.getAddress());
+        } else if (property.equals(SortTerm.ARRIVAL)) {
+            Date arr1 = msg1.getReceivedDate();
+            Date arr2 = msg2.getReceivedDate();
+            return arr1.compareTo(arr2);
+        } else if (property.equals(SortTerm.DATE)) {
+            Date sent1 = msg1.getSentDate();
+            Date sent2 = msg2.getSentDate();
+            return sent1.compareTo(sent2);
+        } else if (property.equals(SortTerm.SIZE)) {
+            int size1 = msg1.getSize();
+            int size2 = msg2.getSize();
+            return Integer.compare(size1, size2);
+        } else if (property.equals(SortTerm.SUBJECT)) {
+            String sub1 = msg1.getSubject();
+            String sub2 = msg2.getSubject();
+            return sub1.compareTo(sub2);
+        }
+        throw new IllegalArgumentException(String.format("Unknown sort term: %s", property.toString()));
+    }
+
+    /**
+     * A sort term with a bit indicating if sorting should be descending for this term
+     */
+    private static final class SortTermWithDescending {
+        private SortTerm term;
+        private boolean descending;
+
+        private SortTermWithDescending(SortTerm term, boolean descending) {
+            this.term = term;
+            this.descending = descending;
+        }
+
+        /**
+         * @return Actual search term
+         */
+        public SortTerm getTerm() {
+            return term;
+        }
+
+        /**
+         * @return true if sorting should be descending, false if it should be ascending
+         */
+        public boolean isDescending() {
+            return descending;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/1149fae7/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSortTermTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSortTermTest.java b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSortTermTest.java
new file mode 100644
index 0000000..40fb2f5
--- /dev/null
+++ b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSortTermTest.java
@@ -0,0 +1,121 @@
+/**
+ * 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.camel.component.mail;
+
+import com.sun.mail.imap.SortTerm;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+import org.jvnet.mock_javamail.Mailbox;
+
+import javax.mail.Folder;
+import javax.mail.Message;
+import javax.mail.Store;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+import javax.mail.search.SearchTerm;
+
+import java.util.Date;
+
+import static org.apache.camel.component.mail.SearchTermBuilder.Op;
+
+/**
+ * This is a test that checks integration of the sort term in camel. The actual sorting logic is tested in the
+ * SortUtilTest.
+ */
+public class MailSortTermTest extends CamelTestSupport {
+
+    @Override
+    public void setUp() throws Exception {
+        prepareMailbox();
+        super.setUp();
+    }
+
+    @Override
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry jndi = super.createRegistry();
+        jndi.bind("sortAscendingDate", new SortTerm[]{SortTerm.DATE});
+        jndi.bind("sortDescendingDate", new SortTerm[]{SortTerm.REVERSE, SortTerm.DATE});
+        jndi.bind("searchTerm", new SearchTermBuilder().subject("Camel").build());
+        return jndi;
+    }
+
+    @Test
+    public void testSortTerm() throws Exception {
+        Mailbox mailbox = Mailbox.get("bill@localhost");
+        assertEquals(3, mailbox.size());
+
+        // This one has search term *not* set
+        MockEndpoint mockAsc = getMockEndpoint("mock:resultAscending");
+        mockAsc.expectedBodiesReceived("Earlier date", "Later date");
+
+        // This one has search term set
+        MockEndpoint mockDesc = getMockEndpoint("mock:resultDescending");
+        mockDesc.expectedBodiesReceived("Even later date", "Later date", "Earlier date");
+
+        // This one has search term set
+        MockEndpoint mockDescImap = getMockEndpoint("mock:resultDescendingImap");
+        mockDescImap.expectedBodiesReceived("Even later date", "Later date", "Earlier date");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    private void prepareMailbox() throws Exception {
+        // connect to mailbox
+        Mailbox.clearAll();
+        JavaMailSender sender = new DefaultJavaMailSender();
+        Store store = sender.getSession().getStore("pop3");
+        store.connect("localhost", 25, "bill", "secret");
+        Folder folder = store.getFolder("INBOX");
+        folder.open(Folder.READ_WRITE);
+        folder.expunge();
+
+        // inserts 3 messages, one with earlier, one with later sent date and one with invalid subject (not returned in search)
+        Message[] messages = new Message[3];
+        messages[0] = new MimeMessage(sender.getSession());
+        messages[0].setText("Earlier date");
+        messages[0].setSentDate(new Date(10000));
+        messages[0].setSubject("Camel");
+
+        messages[1] = new MimeMessage(sender.getSession());
+        messages[1].setText("Later date");
+        messages[1].setSentDate(new Date(20000));
+        messages[1].setSubject("Camel");
+
+        messages[2] = new MimeMessage(sender.getSession());
+        messages[2].setText("Even later date");
+        messages[2].setSentDate(new Date(30000));
+        messages[2].setSubject("Invalid");
+
+        folder.appendMessages(messages);
+        folder.close(true);
+    }
+
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        // Two tests also in conjunction with search since mail consumer does sort and search together
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                from("pop3://bill@localhost?password=secret&searchTerm=#searchTerm&sortTerm=#sortAscendingDate").to("mock:resultAscending");
+                from("pop3://bill@localhost?password=secret&sortTerm=#sortDescendingDate").to("mock:resultDescending");
+                from("imap://bill@localhost?password=secret&sortTerm=#sortDescendingDate").to("mock:resultDescendingImap");
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/1149fae7/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSorterTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSorterTest.java b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSorterTest.java
new file mode 100644
index 0000000..a2a0b52
--- /dev/null
+++ b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSorterTest.java
@@ -0,0 +1,154 @@
+/**
+ * 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.camel.component.mail;
+
+import com.sun.mail.imap.SortTerm;
+import org.apache.camel.component.mail.MailSorter;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import javax.mail.Address;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.internet.InternetAddress;
+import java.util.Date;
+
+import static org.mockito.Mockito.when;
+
+
+/**
+ * Tests mail sort util
+ */
+public class MailSorterTest extends CamelTestSupport {
+    private final static Message[] messages = new Message[3];
+    private final static Message tieBreaker;
+
+    /**
+     * All possible sort terms
+     */
+    private final static SortTerm[] possibleTerms = new SortTerm[]{
+            SortTerm.ARRIVAL,
+            SortTerm.CC,
+            SortTerm.DATE,
+            SortTerm.FROM,
+            SortTerm.SIZE,
+            SortTerm.TO,
+            SortTerm.SUBJECT
+    };
+
+    static {
+        try {
+            messages[0] = createMessage("to1", "cc1", "from1", new Date(1), new Date(1001), 1, "subject1");
+            messages[1] = createMessage("to2", "cc2", "from2", new Date(2), new Date(1002), 2, "subject2");
+            messages[2] = createMessage("to3", "cc3", "from3", new Date(3), new Date(1003), 3, "subject3");
+            // Message that creates a tie on all fields except for one
+            tieBreaker = createMessage("to3", "cc3", "from3", new Date(3), new Date(1003), 3, "subject0TieBreaker");
+        } catch (MessagingException e) {
+            // Rethrow as unchecked. Can not occur anyways
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Create a new message with the specified data
+     */
+    private static Message createMessage(String to, String cc, String from, Date received, Date sent, int size, String subject)
+            throws MessagingException {
+        final Message msg = Mockito.mock(Message.class);
+        when(msg.getFrom()).thenReturn(new Address[]{new InternetAddress(from)});
+        when(msg.getRecipients(Message.RecipientType.TO)).thenReturn(new Address[]{new InternetAddress(to)});
+        when(msg.getRecipients(Message.RecipientType.CC)).thenReturn(new Address[]{new InternetAddress(cc)});
+        when(msg.getSentDate()).thenReturn(sent);
+        when(msg.getReceivedDate()).thenReturn(received);
+        when(msg.getSize()).thenReturn(size);
+        when(msg.getSubject()).thenReturn(subject);
+        return msg;
+    }
+
+    @Test
+    public void testSortMessages() throws Exception {
+        Message[] expected = new Message[]{messages[0], messages[1], messages[2]};
+
+        // Sort using all the terms. Message order should be the same no matter what term is used
+        for (SortTerm term : possibleTerms) {
+            Message[] actual = messages.clone();
+            MailSorter.sortMessages(actual, new SortTerm[]{term});
+            try {
+                assertArrayEquals(actual, expected);
+            } catch (Exception ex) {
+                throw new Exception("Term: " + term.toString(), ex);
+            }
+        }
+    }
+
+    @Test
+    public void testSortMessagesReverse() throws Exception {
+        Message[] expected = new Message[]{messages[2], messages[1], messages[0]};
+
+        // Sort using all the terms. Message order should be the same no matter what term is used
+        for (SortTerm term : possibleTerms) {
+            Message[] actual = messages.clone();
+            MailSorter.sortMessages(actual, new SortTerm[]{SortTerm.REVERSE, term});
+            try {
+                assertArrayEquals(actual, expected);
+            } catch (AssertionError ex) {
+                throw new AssertionError("Term: " + term.toString(), ex);
+            }
+        }
+    }
+
+    @Test
+    public void testSortMessagesMulti() throws Exception {
+        Message[] expected = new Message[]{messages[0], messages[1], messages[2]};
+
+        // Sort using all the terms. Message order should be the same no matter what term is used. The second term
+        // should be ignored since it is already the decider.
+        for (SortTerm term1 : possibleTerms) {
+            for (SortTerm term2 : possibleTerms) {
+                Message[] actual = messages.clone();
+                MailSorter.sortMessages(actual, new SortTerm[]{term1, SortTerm.REVERSE, term2});
+                try {
+                    assertArrayEquals(actual, expected);
+                } catch (AssertionError ex) {
+                    throw new AssertionError(String.format("Terms: %s, %s", term1.toString(), term2.toString()), ex);
+                }
+            }
+
+        }
+    }
+
+    @Test
+    public void testSortMessagesWithTie() throws Exception {
+        Message[] given = new Message[]{messages[2], tieBreaker};
+
+        // Sort according to the whole list. Only the last element breaks the tie
+        Message[] actual1 = given.clone();
+        MailSorter.sortMessages(actual1, possibleTerms);
+        assertArrayEquals(actual1, new Message[]{tieBreaker, messages[2]});
+
+        // now reverse the last element (the tie breaker)
+        SortTerm[] reversed = new SortTerm[possibleTerms.length + 1];
+        System.arraycopy(possibleTerms, 0, reversed, 0, possibleTerms.length - 1);
+        reversed[reversed.length - 2] = SortTerm.REVERSE;
+        reversed[reversed.length - 1] = possibleTerms[possibleTerms.length - 1];
+        // And check again
+        Message[] actual2 = given.clone();
+        MailSorter.sortMessages(actual2, reversed);
+        assertArrayEquals(actual2, new Message[]{messages[2], tieBreaker});
+    }
+}
\ No newline at end of file


[3/4] git commit: CAMEL-7872 Fixed the CS errors

Posted by ni...@apache.org.
CAMEL-7872 Fixed the CS errors


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/07850131
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/07850131
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/07850131

Branch: refs/heads/master
Commit: 07850131677117ac831cc7146c4c838f1ed5dccb
Parents: e1a04be
Author: Willem Jiang <wi...@gmail.com>
Authored: Mon Oct 20 11:17:38 2014 +0800
Committer: Willem Jiang <wi...@gmail.com>
Committed: Mon Oct 20 11:34:19 2014 +0800

----------------------------------------------------------------------
 .../camel/component/mail/MailPostProcessActionTest.java | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/07850131/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailPostProcessActionTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailPostProcessActionTest.java b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailPostProcessActionTest.java
index 97c1aa4..c9a1655 100644
--- a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailPostProcessActionTest.java
+++ b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailPostProcessActionTest.java
@@ -16,6 +16,11 @@
  */
 package org.apache.camel.component.mail;
 
+import javax.mail.Folder;
+import javax.mail.Message;
+import javax.mail.Store;
+import javax.mail.internet.MimeMessage;
+
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.impl.JndiRegistry;
@@ -25,11 +30,6 @@ import org.jvnet.mock_javamail.Mailbox;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.mail.Folder;
-import javax.mail.Message;
-import javax.mail.Store;
-import javax.mail.internet.MimeMessage;
-
 /**
  * Tests if post process action is called if it is set
  */
@@ -67,7 +67,7 @@ public class MailPostProcessActionTest extends CamelTestSupport {
     private void waitForActionCalled() throws InterruptedException {
         // Wait for a maximum of 500 ms for the action to be called
         for (int i = 0; i < 50; i++) {
-            if(action.hasBeenCalled()) {
+            if (action.hasBeenCalled()) {
                 break;
             }
             LOG.debug("Sleeping for 10 millis to wait for action call");


[4/4] git commit: CAMEL-7873 Fixed the CS errors

Posted by ni...@apache.org.
CAMEL-7873 Fixed the CS errors


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/5eed4d96
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/5eed4d96
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/5eed4d96

Branch: refs/heads/master
Commit: 5eed4d9668ab055749b9f0305b019b779a236a5c
Parents: 0785013
Author: Willem Jiang <wi...@gmail.com>
Authored: Mon Oct 20 11:51:22 2014 +0800
Committer: Willem Jiang <wi...@gmail.com>
Committed: Mon Oct 20 11:51:22 2014 +0800

----------------------------------------------------------------------
 .../camel/component/mail/MailEndpoint.java      | 15 ++--
 .../apache/camel/component/mail/MailSorter.java |  9 ++-
 .../camel/component/mail/MailSortTermTest.java  | 19 +++--
 .../camel/component/mail/MailSorterTest.java    | 75 ++++++++++----------
 4 files changed, 61 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/5eed4d96/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
index 1a6b34f..63531aa 100644
--- a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
+++ b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
@@ -16,8 +16,16 @@
  */
 package org.apache.camel.component.mail;
 
+import javax.mail.Message;
+import javax.mail.search.SearchTerm;
+
 import com.sun.mail.imap.SortTerm;
-import org.apache.camel.*;
+
+import org.apache.camel.Consumer;
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
 import org.apache.camel.impl.DefaultExchange;
 import org.apache.camel.impl.DefaultHeaderFilterStrategy;
 import org.apache.camel.impl.ScheduledPollEndpoint;
@@ -25,9 +33,6 @@ import org.apache.camel.spi.HeaderFilterStrategy;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 
-import javax.mail.Message;
-import javax.mail.search.SearchTerm;
-
 /**
  * Endpoint for Camel Mail.
  */
@@ -196,7 +201,7 @@ public class MailEndpoint extends ScheduledPollEndpoint {
      * @param sortTerm {@link #getSortTerm()}
      */
     public void setSortTerm(SortTerm[] sortTerm) {
-        this.sortTerm = (sortTerm == null ? null : sortTerm.clone());
+        this.sortTerm = sortTerm == null ? null : sortTerm.clone();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/camel/blob/5eed4d96/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailSorter.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailSorter.java b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailSorter.java
index cdfb22c..e5c91c3 100644
--- a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailSorter.java
+++ b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailSorter.java
@@ -16,12 +16,17 @@
  */
 package org.apache.camel.component.mail;
 
-import com.sun.mail.imap.SortTerm;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
 
 import javax.mail.Message;
 import javax.mail.MessagingException;
 import javax.mail.internet.InternetAddress;
-import java.util.*;
+
+import com.sun.mail.imap.SortTerm;
 
 /**
  * Utility class for sorting of mail messages

http://git-wip-us.apache.org/repos/asf/camel/blob/5eed4d96/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSortTermTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSortTermTest.java b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSortTermTest.java
index 40fb2f5..70154e4 100644
--- a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSortTermTest.java
+++ b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSortTermTest.java
@@ -16,24 +16,21 @@
  */
 package org.apache.camel.component.mail;
 
-import com.sun.mail.imap.SortTerm;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.impl.JndiRegistry;
-import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Test;
-import org.jvnet.mock_javamail.Mailbox;
+import java.util.Date;
 
 import javax.mail.Folder;
 import javax.mail.Message;
 import javax.mail.Store;
-import javax.mail.internet.InternetAddress;
 import javax.mail.internet.MimeMessage;
-import javax.mail.search.SearchTerm;
 
-import java.util.Date;
+import com.sun.mail.imap.SortTerm;
 
-import static org.apache.camel.component.mail.SearchTermBuilder.Op;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+import org.jvnet.mock_javamail.Mailbox;
 
 /**
  * This is a test that checks integration of the sort term in camel. The actual sorting logic is tested in the

http://git-wip-us.apache.org/repos/asf/camel/blob/5eed4d96/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSorterTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSorterTest.java b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSorterTest.java
index a2a0b52..7e47b81 100644
--- a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSorterTest.java
+++ b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailSorterTest.java
@@ -16,17 +16,17 @@
  */
 package org.apache.camel.component.mail;
 
-import com.sun.mail.imap.SortTerm;
-import org.apache.camel.component.mail.MailSorter;
-import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Test;
-import org.mockito.Mockito;
+import java.util.Date;
 
 import javax.mail.Address;
 import javax.mail.Message;
 import javax.mail.MessagingException;
 import javax.mail.internet.InternetAddress;
-import java.util.Date;
+
+import com.sun.mail.imap.SortTerm;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+import org.mockito.Mockito;
 
 import static org.mockito.Mockito.when;
 
@@ -35,29 +35,26 @@ import static org.mockito.Mockito.when;
  * Tests mail sort util
  */
 public class MailSorterTest extends CamelTestSupport {
-    private final static Message[] messages = new Message[3];
-    private final static Message tieBreaker;
+    private static final Message[] MESSAGES = new Message[3];
+    private static final Message TIE_BREAKER;
 
     /**
      * All possible sort terms
      */
-    private final static SortTerm[] possibleTerms = new SortTerm[]{
-            SortTerm.ARRIVAL,
-            SortTerm.CC,
-            SortTerm.DATE,
-            SortTerm.FROM,
-            SortTerm.SIZE,
-            SortTerm.TO,
-            SortTerm.SUBJECT
-    };
+    private static final SortTerm[] POSSIBLE_TERMS = 
+        new SortTerm[] {
+            SortTerm.ARRIVAL, SortTerm.CC,
+            SortTerm.DATE, SortTerm.FROM,
+            SortTerm.SIZE, SortTerm.TO,
+            SortTerm.SUBJECT};
 
     static {
         try {
-            messages[0] = createMessage("to1", "cc1", "from1", new Date(1), new Date(1001), 1, "subject1");
-            messages[1] = createMessage("to2", "cc2", "from2", new Date(2), new Date(1002), 2, "subject2");
-            messages[2] = createMessage("to3", "cc3", "from3", new Date(3), new Date(1003), 3, "subject3");
+            MESSAGES[0] = createMessage("to1", "cc1", "from1", new Date(1), new Date(1001), 1, "subject1");
+            MESSAGES[1] = createMessage("to2", "cc2", "from2", new Date(2), new Date(1002), 2, "subject2");
+            MESSAGES[2] = createMessage("to3", "cc3", "from3", new Date(3), new Date(1003), 3, "subject3");
             // Message that creates a tie on all fields except for one
-            tieBreaker = createMessage("to3", "cc3", "from3", new Date(3), new Date(1003), 3, "subject0TieBreaker");
+            TIE_BREAKER = createMessage("to3", "cc3", "from3", new Date(3), new Date(1003), 3, "subject0TieBreaker");
         } catch (MessagingException e) {
             // Rethrow as unchecked. Can not occur anyways
             throw new IllegalStateException(e);
@@ -68,7 +65,7 @@ public class MailSorterTest extends CamelTestSupport {
      * Create a new message with the specified data
      */
     private static Message createMessage(String to, String cc, String from, Date received, Date sent, int size, String subject)
-            throws MessagingException {
+        throws MessagingException {
         final Message msg = Mockito.mock(Message.class);
         when(msg.getFrom()).thenReturn(new Address[]{new InternetAddress(from)});
         when(msg.getRecipients(Message.RecipientType.TO)).thenReturn(new Address[]{new InternetAddress(to)});
@@ -82,11 +79,11 @@ public class MailSorterTest extends CamelTestSupport {
 
     @Test
     public void testSortMessages() throws Exception {
-        Message[] expected = new Message[]{messages[0], messages[1], messages[2]};
+        Message[] expected = new Message[]{MESSAGES[0], MESSAGES[1], MESSAGES[2]};
 
         // Sort using all the terms. Message order should be the same no matter what term is used
-        for (SortTerm term : possibleTerms) {
-            Message[] actual = messages.clone();
+        for (SortTerm term : POSSIBLE_TERMS) {
+            Message[] actual = MESSAGES.clone();
             MailSorter.sortMessages(actual, new SortTerm[]{term});
             try {
                 assertArrayEquals(actual, expected);
@@ -98,11 +95,11 @@ public class MailSorterTest extends CamelTestSupport {
 
     @Test
     public void testSortMessagesReverse() throws Exception {
-        Message[] expected = new Message[]{messages[2], messages[1], messages[0]};
+        Message[] expected = new Message[]{MESSAGES[2], MESSAGES[1], MESSAGES[0]};
 
         // Sort using all the terms. Message order should be the same no matter what term is used
-        for (SortTerm term : possibleTerms) {
-            Message[] actual = messages.clone();
+        for (SortTerm term : POSSIBLE_TERMS) {
+            Message[] actual = MESSAGES.clone();
             MailSorter.sortMessages(actual, new SortTerm[]{SortTerm.REVERSE, term});
             try {
                 assertArrayEquals(actual, expected);
@@ -114,13 +111,13 @@ public class MailSorterTest extends CamelTestSupport {
 
     @Test
     public void testSortMessagesMulti() throws Exception {
-        Message[] expected = new Message[]{messages[0], messages[1], messages[2]};
+        Message[] expected = new Message[]{MESSAGES[0], MESSAGES[1], MESSAGES[2]};
 
         // Sort using all the terms. Message order should be the same no matter what term is used. The second term
         // should be ignored since it is already the decider.
-        for (SortTerm term1 : possibleTerms) {
-            for (SortTerm term2 : possibleTerms) {
-                Message[] actual = messages.clone();
+        for (SortTerm term1 : POSSIBLE_TERMS) {
+            for (SortTerm term2 : POSSIBLE_TERMS) {
+                Message[] actual = MESSAGES.clone();
                 MailSorter.sortMessages(actual, new SortTerm[]{term1, SortTerm.REVERSE, term2});
                 try {
                     assertArrayEquals(actual, expected);
@@ -134,21 +131,21 @@ public class MailSorterTest extends CamelTestSupport {
 
     @Test
     public void testSortMessagesWithTie() throws Exception {
-        Message[] given = new Message[]{messages[2], tieBreaker};
+        Message[] given = new Message[]{MESSAGES[2], TIE_BREAKER};
 
         // Sort according to the whole list. Only the last element breaks the tie
         Message[] actual1 = given.clone();
-        MailSorter.sortMessages(actual1, possibleTerms);
-        assertArrayEquals(actual1, new Message[]{tieBreaker, messages[2]});
+        MailSorter.sortMessages(actual1, POSSIBLE_TERMS);
+        assertArrayEquals(actual1, new Message[]{TIE_BREAKER, MESSAGES[2]});
 
         // now reverse the last element (the tie breaker)
-        SortTerm[] reversed = new SortTerm[possibleTerms.length + 1];
-        System.arraycopy(possibleTerms, 0, reversed, 0, possibleTerms.length - 1);
+        SortTerm[] reversed = new SortTerm[POSSIBLE_TERMS.length + 1];
+        System.arraycopy(POSSIBLE_TERMS, 0, reversed, 0, POSSIBLE_TERMS.length - 1);
         reversed[reversed.length - 2] = SortTerm.REVERSE;
-        reversed[reversed.length - 1] = possibleTerms[possibleTerms.length - 1];
+        reversed[reversed.length - 1] = POSSIBLE_TERMS[POSSIBLE_TERMS.length - 1];
         // And check again
         Message[] actual2 = given.clone();
         MailSorter.sortMessages(actual2, reversed);
-        assertArrayEquals(actual2, new Message[]{messages[2], tieBreaker});
+        assertArrayEquals(actual2, new Message[]{MESSAGES[2], TIE_BREAKER});
     }
 }
\ No newline at end of file


[2/4] git commit: CAMEL-7872 Post processing action for input mail box Add a possibility to register a post processing action for input mail box. This can be used for example to clean up the mail box after messages have been retrieved.

Posted by ni...@apache.org.
CAMEL-7872 Post processing action for input mail box
 Add a possibility to register a post processing action for input mail box.
 This can be used for example to clean up the mail box after messages have been retrieved.

Add copyright headers


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e1a04be0
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e1a04be0
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e1a04be0

Branch: refs/heads/master
Commit: e1a04be088809faec94886e680ed6b7cc4a75650
Parents: 1149fae
Author: Christian Amann <ch...@qaware.de>
Authored: Wed Sep 24 14:00:02 2014 +0200
Committer: Willem Jiang <wi...@gmail.com>
Committed: Mon Oct 20 11:34:18 2014 +0800

----------------------------------------------------------------------
 .../mail/MailBoxPostProcessAction.java          |  32 +++++
 .../camel/component/mail/MailConsumer.java      |   5 +
 .../camel/component/mail/MailEndpoint.java      |  16 +++
 .../mail/MailPostProcessActionTest.java         | 127 +++++++++++++++++++
 4 files changed, 180 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/e1a04be0/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBoxPostProcessAction.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBoxPostProcessAction.java b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBoxPostProcessAction.java
new file mode 100644
index 0000000..ea42b09
--- /dev/null
+++ b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBoxPostProcessAction.java
@@ -0,0 +1,32 @@
+/**
+ * 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.camel.component.mail;
+
+import javax.mail.Folder;
+
+/**
+ * Is used for doing post processing tasks on the mailbox once the normal processing ended. This includes for example
+ * cleaning up old emails.
+ */
+public interface MailBoxPostProcessAction {
+    /**
+     * Process the given mail folder
+     *
+     * @param folder Folder to process
+     */
+    void process(Folder folder) throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e1a04be0/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java
index 29835aa..2015cca 100644
--- a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java
+++ b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java
@@ -115,6 +115,11 @@ public class MailConsumer extends ScheduledBatchPollingConsumer {
                 Message[] messages = retrieveMessages();
 
                 polledMessages = processBatch(CastUtils.cast(createExchanges(messages)));
+
+                final MailBoxPostProcessAction postProcessor = getEndpoint().getPostProcessAction();
+                if (postProcessor != null) {
+                    postProcessor.process(folder);
+                }
             } else if (count == -1) {
                 throw new MessagingException("Folder: " + folder.getFullName() + " is closed");
             }

http://git-wip-us.apache.org/repos/asf/camel/blob/e1a04be0/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
index a875612..1a6b34f 100644
--- a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
+++ b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
@@ -43,6 +43,8 @@ public class MailEndpoint extends ScheduledPollEndpoint {
     private SearchTerm searchTerm;
     private SortTerm[] sortTerm;
 
+    private MailBoxPostProcessAction postProcessAction;
+
     public MailEndpoint() {
     }
 
@@ -197,4 +199,18 @@ public class MailEndpoint extends ScheduledPollEndpoint {
         this.sortTerm = (sortTerm == null ? null : sortTerm.clone());
     }
 
+    /**
+     * @return Post processor that can e.g. delete old email. Gets called once the messages have been polled and
+     * processed.
+     */
+    public MailBoxPostProcessAction getPostProcessAction() {
+        return postProcessAction;
+    }
+
+    /**
+     * @param postProcessAction {@link #getPostProcessAction()}
+     */
+    public void setPostProcessAction(MailBoxPostProcessAction postProcessAction) {
+        this.postProcessAction = postProcessAction;
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e1a04be0/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailPostProcessActionTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailPostProcessActionTest.java b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailPostProcessActionTest.java
new file mode 100644
index 0000000..97c1aa4
--- /dev/null
+++ b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailPostProcessActionTest.java
@@ -0,0 +1,127 @@
+/**
+ * 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.camel.component.mail;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+import org.jvnet.mock_javamail.Mailbox;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.mail.Folder;
+import javax.mail.Message;
+import javax.mail.Store;
+import javax.mail.internet.MimeMessage;
+
+/**
+ * Tests if post process action is called if it is set
+ */
+public class MailPostProcessActionTest extends CamelTestSupport {
+    private static final Logger LOG = LoggerFactory.getLogger(MailPostProcessActionTest.class);
+
+    private TestPostProcessAction action;
+
+    @Override
+    public void setUp() throws Exception {
+        prepareMailbox();
+        action = new TestPostProcessAction();
+        super.setUp();
+    }
+
+    @Override
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry jndi = super.createRegistry();
+        jndi.bind("postProcessAction", action);
+        return jndi;
+    }
+
+    @Test
+    public void testActionCalled() throws Exception {
+        Mailbox mailbox = Mailbox.get("bill@localhost");
+        assertEquals(1, mailbox.size());
+
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceivedInAnyOrder("TestText");
+
+        assertMockEndpointsSatisfied();
+        waitForActionCalled();
+    }
+
+    private void waitForActionCalled() throws InterruptedException {
+        // Wait for a maximum of 500 ms for the action to be called
+        for (int i = 0; i < 50; i++) {
+            if(action.hasBeenCalled()) {
+                break;
+            }
+            LOG.debug("Sleeping for 10 millis to wait for action call");
+            Thread.sleep(10);
+        }
+        assertEquals(true, action.hasBeenCalled());
+    }
+
+    private void prepareMailbox() throws Exception {
+        // connect to mailbox
+        Mailbox.clearAll();
+        JavaMailSender sender = new DefaultJavaMailSender();
+        Store store = sender.getSession().getStore("pop3");
+        store.connect("localhost", 25, "bill", "secret");
+        Folder folder = store.getFolder("INBOX");
+        folder.open(Folder.READ_WRITE);
+        folder.expunge();
+
+        // inserts 1 new message
+        Message[] messages = new Message[1];
+        messages[0] = new MimeMessage(sender.getSession());
+        messages[0].setSubject("TestSubject");
+        messages[0].setText("TestText");
+
+        folder.appendMessages(messages);
+        folder.close(true);
+    }
+
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                from("pop3://bill@localhost?password=secret&postProcessAction=#postProcessAction").to("mock:result");
+            }
+        };
+    }
+
+    private class TestPostProcessAction implements MailBoxPostProcessAction {
+        private boolean called;
+
+        @Override
+        public void process(Folder folder) throws Exception {
+            // Assert that we are looking at the correct folder with our message
+            final Message[] messages = folder.getMessages();
+            assertEquals(1, messages.length);
+            assertEquals("TestSubject", messages[0].getSubject());
+            // And mark ourselves as "called"
+            called = true;
+        }
+
+        /**
+         * @return true if the action has been called
+         */
+        public boolean hasBeenCalled() {
+            return called;
+        }
+    }
+}