package cyrille.util;
import java.util.Comparator;
import java.util.StringTokenizer;
import org.apache.commons.beanutils.PropertyUtils;
/**
* @author <a href="mailto:cleclerc@pobox.com">Cyrille Le Clerc</a>
*
*/
public class BeanComparator implements Comparator {
private final static int SORT_FIELDS = 0;
private final static int PROPERTIES_NAMES = 1;
private final static int ASCENDINGS = 2;
/**
* Array of col1 : String sortField e.g. "size.sortKey" col2 : String[] sortFieldGetters e.g.
* {"size", "sortKey"} col4 : Boolean flag indicating whether the sort is ascending or not
*/
private Object[][] sortFields = null;
/**
* BoComparator constructor comment.
*
* @param newSortField
* String : name of the bean attribute to sort on (i.e. getXXX must exist), can be
* separated by point, getBo() implied
* @param newAscending
* boolean : sort ascending or not
*/
public BeanComparator(String newSortField, boolean newAscending) {
this(new String[] { newSortField }, new boolean[] { newAscending });
}
/**
* BoComparator constructor comment.
*
* @param newSortField
* String[] : name of the bean attribute to sort on (i.e. getXXX must exist), can be
* separated by point, getBo() implied
* @param newAscending
* boolean[] : sort ascending or not
* @throws IllegalArgumentException :
*/
public BeanComparator(String[] newSortField, boolean[] newAscending) {
super();
if (newSortField == null) {
throw new IllegalArgumentException("arguments can NOT be bull sortField=" + newSortField);
}
if (newSortField.length != newAscending.length) {
throw new IllegalStateException("newSortField and newAscending arrays have different sizes");
}
this.sortFields = new Object[newSortField.length][4];
for (int i = 0; i < newSortField.length; i++) {
this.sortFields[i][SORT_FIELDS] = newSortField[i];
this.sortFields[i][ASCENDINGS] = Boolean.valueOf(newAscending[i]);
StringTokenizer sortFieldsTk = new StringTokenizer(newSortField[i], ".");
String[] gettersNames = new String[sortFieldsTk.countTokens()];
this.sortFields[i][PROPERTIES_NAMES] = gettersNames;
int j = 0;
while (sortFieldsTk.hasMoreElements()) {
String sortField = (String) sortFieldsTk.nextElement();
gettersNames[j] = sortField;
j++;
}
}
}
/**
* @return a negative integer, zero, or a positive integer as the first argument is less than,
* equal to, or greater than the second.
* @throws ClassCastException
* if the arguments' types prevent them from being compared by this Comparator.
*/
public int compare(Object o1, Object o2) {
// System.out.println("Compare");
// System.out.println("\t'" + o1 + "'");
// System.out.println("\t'" + o2 + "'");
int result = 0;
try {
int sortFieldsCounter = 0;
while (result == 0 && sortFieldsCounter < this.sortFields.length) {
Object currentO1 = o1;
Object currentO2 = o2;
String[] propertiesNames = (String[]) this.sortFields[sortFieldsCounter][PROPERTIES_NAMES];
boolean ascending = ((Boolean) this.sortFields[sortFieldsCounter][ASCENDINGS]).booleanValue();
int i = 0;
while (currentO1 != null && currentO2 != null && i < propertiesNames.length) {
currentO1 = PropertyUtils.getProperty(currentO1, propertiesNames[i]);
currentO2 = PropertyUtils.getProperty(currentO2, propertiesNames[i]);
i++;
}
if (currentO1 == null) {
if (currentO2 == null) {
result = 0;
} else {
result = +1;
}
} else {
if (currentO2 == null) {
// result = -1;
result = -1;
} else {
if (!(currentO1 instanceof Comparable)) {
throw new RuntimeException("Not comparable for getter " + currentO1.toString());
}
result = ((Comparable) currentO1).compareTo(currentO2);
}
}
result = (ascending == true ? result : -result);
// System.out.println("\t\t on '" + sortField + "' = '" + result + "'");
sortFieldsCounter++;
}
return result;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}