001 package edu.nrao.sss.sort; 002 003 /** 004 * A single sorting key. 005 * <p> 006 * <b>Version Info:</b> 007 * <table style="margin-left:2em"> 008 * <tr><td>$Revision: 593 $</td></tr> 009 * <tr><td>$Date: 2007-05-07 15:54:14 -0600 (Mon, 07 May 2007) $</td></tr> 010 * <tr><td>$Author: dharland $</td></tr> 011 * </table></p> 012 * 013 * @author David M. Harland 014 * @since 2007-05-03 015 */ 016 public abstract class SortKey<T> 017 implements Orderable 018 { 019 private SortOrder order; 020 021 /** Helps create a new key with a natural order. */ 022 protected SortKey() 023 { 024 order = SortOrder.NATURAL; 025 } 026 027 /* (non-Javadoc) 028 * @see Orderable#setOrder(SortOrder) 029 */ 030 public void setOrder(SortOrder newOrder) 031 { 032 if (newOrder == SortOrder.CUSTOM) 033 throw new IllegalArgumentException("This sort key (" + 034 this.getClass().getName() + 035 ") does not allow SortOrder.CUSTOM."); 036 037 order = (newOrder == null) ? SortOrder.NATURAL : newOrder; 038 } 039 040 /* (non-Javadoc) 041 * @see Orderable#getOrder() 042 */ 043 public SortOrder getOrder() { return order; } 044 045 /** 046 * Returns a number less than zero, zero, or greater than zero 047 * as <tt>o1</tt> is before, coincident with, or after <tt>o2</tt> 048 * when sorted in this key's current order. 049 */ 050 protected int compareObjects(T o1, T o2) 051 { 052 //Quick exit if objects are equal 053 if (objectsAreEqual(o1, o2)) 054 return 0; 055 056 //Quick exit if exactly one object is null 057 int nullOrder = nullOrdering(o1, o2); 058 if (nullOrder != 0) 059 return nullOrder; 060 061 return compareObjects(o1, o2, order); 062 } 063 064 /** 065 * Returns a number less than zero, zero, or greater than zero 066 * as <tt>o1</tt> is before, coincident with, or after <tt>o2</tt> 067 * when sorted in according to t he given sort order. 068 * <p/> 069 * This method is called by compareObjects(T o1, T o2). 070 */ 071 protected int compareObjects(T o1, T o2, SortOrder ordering) 072 { 073 switch (ordering) 074 { 075 case AS_IS: return 0; 076 077 case NATURAL: return compareNatural(o1, o2); 078 079 case ASCENDING: return compareAscending(o1, o2); 080 081 case DESCENDING: return -compareAscending(o1, o2); 082 083 default: 084 throw new IllegalStateException( 085 "Unrecognized or disallowed SortOrder "+ 086 ordering + " found in comparObjects(...)"); 087 } 088 } 089 090 /** 091 * Returns a number less than zero, zero, or greater than zero 092 * as <tt>o1</tt> is before, coincident with, or after <tt>o2</tt> 093 * when sorted in natural order. 094 */ 095 protected abstract int compareNatural(T o1, T o2); 096 097 /** 098 * Returns a number less than zero, zero, or greater than zero 099 * as <tt>o1</tt> is before, coincident with, or after <tt>o2</tt> 100 * when sorted in ascending order. 101 */ 102 protected abstract int compareAscending(T o1, T o2); 103 104 /** 105 * Returns <i>true</i> if the two objects are equal. 106 * This method is used by {@link #compareObjects(Object, Object)}. 107 */ 108 protected boolean objectsAreEqual(Object o1, Object o2) 109 { 110 //Quick return if same instance (incl both == null) 111 if (o1 == o2) 112 return true; 113 114 //Quick return if equal 115 if ((o1 != null) && o1.equals(o2)) 116 return true; 117 118 return false; 119 } 120 121 /** 122 * Handles comparisons when exactly one of the two objects is null. 123 * For ascending and natural sorts, null objects are placed at the 124 * end of the line. For descending sorts they are placed at the beginning. 125 * This method is used by {@link #compareObjects(Object, Object)}. 126 */ 127 protected int nullOrdering(T o1, T o2) 128 { 129 //TODO: There's an implicit assumption here that NATURAL == ASCENDING 130 // Trouble? 131 if ((o1 == null) && (o2 != null)) 132 return (order == SortOrder.DESCENDING) ? -1 : +1; 133 134 if ((o1 != null) && (o2 == null)) 135 return (order == SortOrder.DESCENDING) ? +1 : -1; 136 137 return 0; 138 } 139 }