ShortNameComparator.java

  1. package emissary.util;

  2. import emissary.core.Family;
  3. import emissary.core.IBaseDataObject;

  4. import org.apache.commons.lang3.Validate;

  5. import java.io.Serializable;
  6. import java.util.Comparator;

  7. /**
  8.  * Allow a Collection or Array of IBaseDataObject to be sorted by shortName such that all attachments come in order and
  9.  * all parents are immediately followed by their children and all siblings are in numerical (i.e. not string) order.
  10.  */
  11. public class ShortNameComparator implements Comparator<IBaseDataObject>, Serializable {

  12.     // Serializable
  13.     static final long serialVersionUID = -7621558910791975422L;

  14.     @Override
  15.     public int compare(IBaseDataObject obj1, IBaseDataObject obj2) {
  16.         Validate.isTrue(obj1 != null, "Required: obj1 != null");
  17.         Validate.isTrue(obj2 != null, "Required: obj2 != true");

  18.         String s1 = obj1.shortName();
  19.         String s2 = obj2.shortName();
  20.         int index1 = s1.indexOf(Family.SEP);
  21.         int index2 = s2.indexOf(Family.SEP);

  22.         // Loop through each level in obj1's shortName.
  23.         while (index1 != -1) {
  24.             // If obj1's shortName has more levels than obj2's shortName then obj1 > obj2.
  25.             if (index2 == -1) {
  26.                 return 1;
  27.             }

  28.             // Get start character of level.
  29.             index1 += Family.SEP.length();
  30.             index2 += Family.SEP.length();

  31.             // Get character length of level.
  32.             final int nextIndex1 = s1.indexOf(Family.SEP, index1);
  33.             final int nextIndex2 = s2.indexOf(Family.SEP, index2);
  34.             final int length1 = ((nextIndex1 < 0) ? s1.length() : nextIndex1) - index1;
  35.             final int length2 = ((nextIndex2 < 0) ? s2.length() : nextIndex2) - index2;

  36.             // If the obj1's level and obj2's level are the same, then go to the next level.
  37.             if (length1 == length2 && s1.regionMatches(index1, s2, index2, length1)) {
  38.                 index1 = nextIndex1;
  39.                 index2 = nextIndex2;

  40.                 continue;
  41.             }

  42.             // Otherwise, try comparing the levels as integers.
  43.             try {
  44.                 int int1 = Integer.parseInt(s1, index1, index1 + length1, 10);
  45.                 int int2 = Integer.parseInt(s2, index2, index2 + length2, 10);

  46.                 return int1 - int2;
  47.             } catch (NumberFormatException e) {
  48.                 // Otherwise, compare the levels as strings.
  49.                 final String substring1 = s1.substring(index1, index1 + length1);
  50.                 final String substring2 = s2.substring(index2, index2 + length2);

  51.                 return substring1.compareTo(substring2);
  52.             }
  53.         }

  54.         // If obj1's shortName has fewer levels than obj2's shortName then obj1 < obj2.
  55.         if (index2 != -1) {
  56.             return -1;
  57.         }

  58.         // Otherwise, obj1 and obj2 compare as equivalent
  59.         return 0;
  60.     }
  61. }