/** * 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 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 com.sun.mail.imap.SortTerm; /** * 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 descending 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 descending final List<SortTermWithDescending> sortTermsWithDescending = new ArrayList<SortTermWithDescending>(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; } } }