001package org.andromda.utils.beans; 002 003import java.util.ArrayList; 004import java.util.Collection; 005import java.util.Collections; 006import java.util.List; 007 008import org.andromda.core.common.ExceptionUtils; 009import org.andromda.utils.beans.SortCriteria.Ordering; 010import org.andromda.utils.beans.comparators.BeanComparator; 011import org.apache.commons.collections.comparators.ComparatorChain; 012 013/** 014 * Provides bean sorting capabilities. 015 * 016 * <p> 017 * Sorts passed in Collections and returns 018 * sorted Lists. Performs sorting for any 019 * Class that has an associated Comparator implementation defined. If 020 * the Collection that is passed in, is not an instance of List, it will create 021 * a new ArrayList with the contents of the passed in Collection, before 022 * sorting occurs (since sorting can only be done on a java.util.List). 023 * </p> 024 * 025 * @author Chad Brandon 026 */ 027public class BeanSorter 028{ 029 /** 030 * Performs sorting of the collection by one property to 031 * sort with more than one property see {@link #sort(java.util.Collection, SortCriteria[])}. 032 * 033 * @see #sort(java.util.Collection, SortCriteria[]) 034 * 035 * @param <T> Collection type 036 * @param beans the Collection of PersistentObjects to sort 037 * @param sortBy the property to sort by (i.e. firstName, etc). Can 038 * be a nested property such as 'person.address.street'. 039 * @param ordering the ordering of the sorting (either {@link Ordering#ASCENDING} 040 * or {@link Ordering#DESCENDING}) 041 * @return the sorted List 042 */ 043 public static <T> List<T> sort( 044 final Collection<T> beans, 045 final String sortBy, 046 final Ordering ordering) 047 { 048 return sort( 049 beans, 050 new SortCriteria[] {new SortCriteria( 051 sortBy, 052 ordering)}); 053 } 054 055 /** 056 * Performs sorting of the collection by one property to 057 * sort with more than one property see {@link #sort(java.util.Collection, SortCriteria[])}. 058 * 059 * @see #sort(java.util.Collection, SortCriteria[]) 060 * 061 * @param <T> Collection type 062 * @param beans the Collection of PersistentObjects to sort 063 * @param sortBy the property to sort by (i.e. firstName, etc). Can 064 * be a nested property such as 'person.address.street'. 065 * @param nullsFirst a flag indicating whether or not null values should be sorted to the beginning 066 * or the ending of the list. 067 * @return the sorted List 068 */ 069 public static <T> List<T> sort( 070 final Collection<T> beans, 071 final String sortBy, 072 final boolean nullsFirst) 073 { 074 return sort( 075 beans, 076 new SortCriteria[] {new SortCriteria( 077 sortBy, 078 nullsFirst)}); 079 } 080 081 /** 082 * Performs sorting of the collection by one property to 083 * sort with more than one property see {@link #sort(java.util.Collection, SortCriteria[])}. 084 * 085 * @see #sort(java.util.Collection, SortCriteria[]) 086 * 087 * @param <T> Collection type 088 * @param beans the Collection of PersistentObjects to sort 089 * @param sortBy the property to sort by (i.e. firstName, etc). Can 090 * be a nested property such as 'person.address.street'. 091 * @param ordering the ordering of the sorting (either {@link Ordering#ASCENDING} 092 * or {@link Ordering#DESCENDING}) 093 * @param nullsFirst a flag indicating whether or not null values should be sorted to the beginning 094 * or the ending of the list. 095 * @return the sorted List 096 */ 097 public static <T> List<T> sort( 098 final Collection<T> beans, 099 final String sortBy, 100 final Ordering ordering, 101 final boolean nullsFirst) 102 { 103 return sort( 104 beans, 105 new SortCriteria[] {new SortCriteria( 106 sortBy, 107 ordering, 108 nullsFirst)}); 109 } 110 111 /** 112 * <p> 113 * Sorts the passed in Collection and returns 114 * a sorted List. Performs SQL like sorting for any 115 * Class that has an associated Comparator implementation defined. If 116 * the Collection that is passed in, is not an instance of List, it will create 117 * a new ArrayList with the contents of the passed in Collection, before 118 * sorting occurs. Since sorting can only be done on a java.util.List. If 119 * it is a list, then in-line sorting will occur of the list. 120 * </p> 121 * 122 * @param <T> Collection type 123 * @param beans the Collection of PersistentObjects to sort 124 * @param sortBy an array of SortCriteria. This array of SortCriteria 125 * specifies which attributes to sort by. 126 * Attributes to sort by, MUST be simple attributes 127 * (i.e. name, type, etc, they can not be complex objects, but the properties can be 128 * nested simple types within associated beans). 129 * 130 * @return List the sorted List 131 */ 132 public static <T> List<T> sort( 133 final Collection<T> beans, 134 final SortCriteria[] sortBy) 135 { 136 ExceptionUtils.checkNull( 137 "beans", 138 beans); 139 ExceptionUtils.checkNull( 140 "sortBy", 141 sortBy); 142 143 if (sortBy.length == 0) 144 { 145 throw new IllegalArgumentException("sortBy must contain at least one value by which to sort"); 146 } 147 148 List<T> sorted = null; 149 150 // IMPORTANT: do not replace this logic with new list creation, this allows for sorting of the passed 151 // in collection of beans (i.e. it allows this method to do "in-line" sorting), with the caller not having 152 // to get the result of this method to get the sorted result, only if the collection is not a List instance 153 // will it need to use the result of this method to get the sorted collection. 154 if (!(beans instanceof List)) 155 { 156 sorted = new ArrayList<T>(beans); 157 } 158 else 159 { 160 sorted = (List)beans; 161 } 162 163 int sortByNum = sortBy.length; 164 165 // - use the Comparator chain to provide SQL like sorting of properties 166 final ComparatorChain chain = new ComparatorChain(); 167 for (int ctr = 0; ctr < sortByNum; ctr++) 168 { 169 final SortCriteria orderBy = sortBy[ctr]; 170 chain.addComparator(new BeanComparator(orderBy)); 171 } 172 173 Collections.sort( 174 sorted, 175 chain); 176 177 return sorted; 178 } 179}