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 {@code Double}s 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 a {@code Double} 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 doubles returned from those methods
013     * 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}.  You may place instances of this
017     * class in a {@link CompoundComparator}.</p>
018     * <p>
019     * <b><u>Example</u></b><br/>
020     * Let there be a class, <tt>Pants</tt>, that has the following
021     * attributes, each of which is a <tt>double</tt>: 
022     * <tt>waist, inseam, price</tt>, and a <tt>String</tt> attribute:
023     * <tt>style</tt>.  Furthermore, assume the normal convention
024     * for the getters (e.g., <tt>getPrice()</tt>).  You could sort a collection of
025     * pants by waist, then price, then style, then inseam, without writing any new
026     * classes by doing this:</p>
027     * <pre>
028     *   ReflectiveDoubleSortKey&lt;Pants&gt; waistKey =
029     *     new ReflectiveDoubleSortKey&lt;Pants&gt;("getWaist");
030     *     
031     *   ReflectiveDoubleSortKey&lt;Pants&gt; lengthKey =
032     *     new ReflectiveDoubleSortKey&lt;Pants&gt;("getInseam");
033     *     
034     *   ReflectiveDoubleSortKey&lt;Pants&gt; costKey =
035     *     new ReflectiveDoubleSortKey&lt;Pants&gt;("getPrice");
036     *     
037     *   ReflectiveStringSortKey&lt;Pants&gt; styleKey =
038     *     new ReflectiveStringSortKey&lt;Pants&gt;("getStyle");
039     *     
040     *   CompoundComparator&lt;Pants&gt; comparator =
041     *     new CompoundComparator&lt;Pants&gt;(waistKey, priceKey, styleKey, lengthKey);
042     *     
043     *   Collections.sort(pantsCatalog, 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-04
055     */
056    public final class ReflectiveDoubleSortKey<T>
057      extends DoubleSortKey
058      implements Comparator<T>
059    {
060      private ReflectiveSortHelper<Double, T> helper;
061      
062      /**
063       * Creates a new instance that will base its comparison on the {@code Double}
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 a
068       *                   {@code Double} (or {@code double}).  If there is any
069       *                   trouble creating or calling the method with this name,
070       *                   it will be treated as if it returns a {@code Double}
071       *                   of {@link Double#NaN}.
072       */
073      public ReflectiveDoubleSortKey(String methodName)
074      {
075        helper = new ReflectiveSortHelper<Double, T>(methodName, Double.NaN);
076      }
077      
078      /**
079       * Sets the name of the method used for making comparisons.
080       * 
081       * @param newMethodName the name of a public, no argument, method that belongs
082       *                      to objects of type {@code T} and that returns a
083       *                      {@code Double} (or {@code double}).  If there is any
084       *                      trouble creating or calling the method with this name,
085       *                      it will be treated as if it returns a {@code Double}
086       *                      of {@link Double#NaN}.
087       */
088      public void setMethodName(String newMethodName)
089      {
090        helper.setMethodName(newMethodName);
091      }
092      
093      /* (non-Javadoc)
094       * @see Comparator#compare(Object, Object)
095       */
096      public int compare(T o1, T o2)
097      {
098        return compareObjects(helper.getValue(o1), helper.getValue(o2));
099      }
100    }