001    package edu.nrao.sss.sort;
002    
003    import java.util.Comparator;
004    
005    /**
006     * A {@link SortKey sort key} and {@link Comparator comparator} that works with
007     * the enumeration elements returned by a method that is found reflectively.
008     * <p>
009     * Clients of this class must provide the name of a public, no argument, method
010     * that returns an {@code Enum} and that is present in classes of the
011     * parameterized type {@code T}.  The method created from that name is called
012     * on the objects to be compared, and the enumeration elements returned from
013     * those methods are what is actually compared.</p>
014     * <p>
015     * Because this class is a {@link SortKey}, you may configure its instances with
016     * a particular {@code SortOrder}.  Because it is also an {@link EnumSortKey}, 
017     * you may specify a custom ordering.  You may place instances of this
018     * class in a {@link CompoundComparator}.</p>
019     * <p>
020     * <b><u>Example</u></b><br/>
021     * Let there be a class, <tt>Person</tt>, that has the following
022     * attributes, each of which is an enumeration: 
023     * <tt>gender</tt> and <tt>handedness</tt>.
024     * Furthermore, assume the normal convention
025     * for the getters (e.g., <tt>getGender()</tt>).
026     * If you are studying the distribution of handedness by age and gender,
027     * you might want to sort a collection of people by age, gender, and
028     * handedness.  You could do this without writing any new
029     * classes by doing as follows:</p>
030     * <pre>
031     *   ReflectiveIntSortKey&lt;Person&gt; ageKey =
032     *     new ReflectiveIntSortKey&lt;Person&gt;("getAge");
033     *     
034     *   ReflectiveEnumSortKey&lt;Person,Gender&gt; sexKey =
035     *     new ReflectiveEnumSortKey&lt;Person,Gender&gt;("getGender");
036     *     
037     *   ReflectiveEnumSortKey&lt;Person,Handedness&gt; handKey =
038     *     new ReflectiveEnumSortKey&lt;Person,Handedness&gt;("getHandedness");
039     *     
040     *   CompoundComparator&lt;Person&gt; comparator =
041     *     new CompoundComparator&lt;Person&gt;(ageKey, sexKey, handKey);
042     *     
043     *   Collections.sort(population, comparator);
044     * </pre>
045     * <p>
046     * <b>Version Info:</b>
047     * <table style="margin-left:2em">
048     *   <tr><td>$Revision: 593 $</td></tr>
049     *   <tr><td>$Date: 2007-05-07 15:54:14 -0600 (Mon, 07 May 2007) $</td></tr>
050     *   <tr><td>$Author: dharland $</td></tr>
051     * </table></p>
052     * 
053     * @author David M. Harland
054     * @since 2007-05-07
055     */
056    public final class ReflectiveEnumSortKey<T, E extends Enum<E>>
057      extends EnumSortKey<E>
058      implements Comparator<T>
059    {
060      private ReflectiveSortHelper<E, T> helper;
061      
062      /**
063       * Creates a new instance that will base its comparison on the {@code Integer}
064       * returned by the method with the given name.
065       *  
066       * @param methodName the name of a public, no argument, method that belongs
067       *                   to objects of type {@code T} and that returns an
068       *                   {@link Enum}).  If there is any
069       *                   trouble creating or calling the method with this name,
070       *                   it will be treated as if it returns <i>null</i>.
071       */
072      public ReflectiveEnumSortKey(String methodName)
073      {
074        helper = new ReflectiveSortHelper<E, T>(methodName, (E)null);
075      }
076      
077      /**
078       * Sets the name of the method used for making comparisons.
079       * 
080       * @param newMethodName the name of a public, no argument, method that belongs
081       *                      to objects of type {@code T} and that returns an
082       *                      {@code Integer} (or {@code in}).  If there is any
083       *                      trouble creating or calling the method with this name,
084       *                      it will be treated as if it returns a {@code Integer}
085       *                      of {@link Integer#MIN_VALUE}.
086       */
087      public void setMethodName(String newMethodName)
088      {
089        helper.setMethodName(newMethodName);
090      }
091      
092      /* (non-Javadoc)
093       * @see Comparator#compare(Object, Object)
094       */
095      public int compare(T o1, T o2)
096      {
097        return compareObjects(helper.getValue(o1), helper.getValue(o2));
098      }
099    }