package com.spun.util; import java.io.Serializable; import java.util.Comparator; import java.util.Date; public class MethodSorter<T> implements java.util.Comparator<T>, Serializable { public static enum SortOrder { Ascending, Decending; public boolean toBoolean() { return this == Ascending; } public static SortOrder isAscending(boolean ascending) { return ascending ? Ascending : Decending; } } private Comparator<Object> comparator; private MethodExecutionPath path; /************************************************************************/ public MethodSorter(MethodExecutionPath path, SortOrder sortOrder) { SortOrder s = sortOrder; this.path = path; this.comparator = getComparatorForType(path.getReturnType(), s.toBoolean()); } /************************************************************************/ public MethodSorter(Class<? extends T> classType, String methodName, boolean ascending) { this(new MethodExecutionPath(classType, methodName), SortOrder.isAscending(ascending)); } /************************************************************************/ public MethodSorter(Class<? extends T> classType, String[] methodNames, boolean ascending) { this(new MethodExecutionPath(classType, methodNames), SortOrder.isAscending(ascending)); } /************************************************************************/ public Class getClassType() { return path.getClassType(); } /************************************************************************/ private static Comparator<Object> getComparatorForType(Class type, boolean ascending) { if (String.class.isAssignableFrom(type)) { return new StringComparator(ascending); } else if (Double.TYPE.isAssignableFrom(type)) { return new NumberComparator(ascending); } else if (Integer.TYPE.isAssignableFrom(type) || Integer.class.isAssignableFrom(type)) { return new NumberComparator(ascending); } else if (Date.class.isAssignableFrom(type)) { return new DateComparator(ascending); } else if (Character.TYPE.isAssignableFrom(type)) { return new CharacterComparator(ascending); } else if (type.isArray()) { return new ArraySizeComparator(ascending); } else { throw new Error("Cannot handle class of type " + type.getName()); } } /************************************************************************/ private Object extractValue(T object) { Object o = path.extractValue(object); return (MethodExecutionPath.NULL_ENCOUNTERED_ON_PATH == o) ? null : o; } /************************************************************************/ public int compare(T o1, T o2) { return comparator.compare(extractValue(o1), extractValue(o2)); } private static int compareNull(Object o1, Object o2) { if (o1 == o2) { return 0; } return (o1 == null) ? -1 : 1; } /************************************************************************/ /************************************************************************/ /* INNNER CLASSES */ /************************************************************************/ public static class NumberComparator implements Comparator<Object>, Serializable { private boolean ascending; /************************************************************************/ public NumberComparator(boolean ascending) { this.ascending = ascending; } /************************************************************************/ public int compare(Object o1, Object o2) throws java.lang.ClassCastException { int value = 0; if (o1 == null || o2 == null) { value = compareNull(o1, o2); } else { value = Double.compare(((Number) o1).doubleValue(), ((Number) o2).doubleValue()); } return ascending ? value : -value; } } /***********************************************************************/ public static class DateComparator implements Comparator<Object>, Serializable { private boolean ascending; /************************************************************************/ public DateComparator(boolean ascending) { this.ascending = ascending; } /************************************************************************/ public int compare(Object o1, Object o2) { if (o1 == null || o2 == null) { return compareNull(o1, o2); } Date date1 = (Date) o1; Date date2 = (Date) o2; return date1.compareTo(date2) * (ascending ? 1 : -1); } } /***********************************************************************/ public static class ArraySizeComparator implements Comparator<Object> { private boolean ascending; /************************************************************************/ public ArraySizeComparator(boolean ascending) { this.ascending = ascending; } /************************************************************************/ public int compare(Object o1, Object o2) { Object[] array1 = (Object[]) o1; Object[] array2 = (Object[]) o2; return Double.compare(array1.length, array2.length) * (ascending ? 1 : -1); } } /***********************************************************************/ public static class CharacterComparator implements Comparator<Object>, Serializable { private boolean ascending; /************************************************************************/ public CharacterComparator(boolean ascending) { this.ascending = ascending; } /************************************************************************/ public int compare(Object o1, Object o2) { Character c1 = (Character) o1; Character c2 = (Character) o2; return c1.compareTo(c2) * (ascending ? 1 : -1); } } /***********************************************************************/ public static class StringComparator implements Comparator<Object>, Serializable { private boolean ascending; /************************************************************************/ public StringComparator(boolean ascending) { this.ascending = ascending; } /************************************************************************/ public int compare(Object o1, Object o2) { return StringComparator.compare((String) o1, (String) o2, ascending); } /************************************************************************/ public static int compare(String o1, String o2, boolean ascending) { int value = 0; if (o1 == null || o2 == null) { value = compareNull(o1, o2); } else { value = o1.compareTo(o2); } return ascending ? value : -value; } } /************************************************************************/ /************************************************************************/ }