FileDocCategorySizeDatePackage
ReflexiveComparator.javaAPI DocExample6565Sun Dec 14 22:47:40 GMT 2003oreilly.hcj.reflection

ReflexiveComparator.java

/*
 *     file: ReflexiveComparator.java
 *  package: oreilly.hcj.reflection
 *
 * This software is granted under the terms of the Common Public License,
 * CPL, which may be found at the following URL:
 * http://www-124.ibm.com/developerworks/oss/CPLv1.0.htm
 *
 * Copyright(c) 2003-2005 by the authors indicated in the @author tags.
 * All Rights are Reserved by the various authors.
 *
########## DO NOT EDIT ABOVE THIS LINE ########## */

package oreilly.hcj.reflection;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.Comparator;

/**  
 * Creates a comparator that sorts the target objects based upon the value  of a specific
 * property. <b>Note: this comparator imposes orderings that are inconsistent with
 * equals. This is because the comparator is set up reflexively and may not match the
 * comparisons in the equals method.</b>
 *
 * @author $author$
 * @version $Revision: 1.9 $
 */
public class ReflexiveComparator implements Comparator {
	/** Holds error message for non comparable sortProperty. */
	private static final String ERR_COMPARABLE =
		"The sortProperty doesn't implement java.lang.Comparable";  //$NON-NLS-1$

	/** Holds value of property dataType. */
	private Class dataType;

	/** Holds value of property sortProperty. */
	private PropertyDescriptor sortProperty;

	/** Holds value of property ascending. */
	private boolean ascending;

	/** 
	 * Creates a new instance of ReflexiveComparator.
	 *
	 * @param dataType Class which this comparator will be sorting.
	 * @param sortProperty The property descriptor of the class to use to sort.
	 * @param ascending Whether to sort in ascending order (default) or not. Pass false
	 *        to sort in descending order.
	 *
	 * @throws IllegalArgumentException DOCUMENT ME!
	 */
	public ReflexiveComparator(final Class dataType,
	                           final PropertyDescriptor sortProperty,
	                           final boolean ascending) {
		this.dataType = dataType;
		this.sortProperty = sortProperty;
		this.ascending = ascending;

		if (!(sortProperty.getPropertyType().isPrimitive())) {
			if (!(Comparable.class.isAssignableFrom(this.sortProperty.getPropertyType()))) {
				throw new IllegalArgumentException(ERR_COMPARABLE);
			}
		}
	}

	//	/** 
	//	 * Creates a new instance of ReflexiveComparator.
	//	 *
	//	 * @param dataType Class which this comparator will be sorting.
	//	 * @param sortProperty The name of the property of the class to use to sort. This
	//	 *        property must implement the interface{@link java.lang.Comparable
	//	 *        java.lang.Comparable}.
	//	 * @param ascending Whether to sort in ascending order (default) or not. Pass false
	//	 *        to sort in descending order.
	//	 */
	//	public ReflexiveComparator(final Class dataType, final String sortProperty,
	//	                           final boolean ascending) {
	//		this(dataType, PropertyDescriptorMap.getDescriptor(dataType, sortProperty),
	//		     ascending);
	//	}

	/** 
	 * Setter for property ascending.
	 *
	 * @param ascending New value of property ascending.
	 */
	public void setAscending(final boolean ascending) {
		this.ascending = ascending;
	}

	/** 
	 * Getter for property ascending.
	 *
	 * @return Value of property ascending.
	 */
	public boolean isAscending() {
		return this.ascending;
	}

	/** 
	 * Setter for property tgtClass.
	 *
	 * @param dataType New value of property tgtClass.
	 */
	public void setDataType(Class dataType) {
		this.dataType = dataType;
	}

	/** 
	 * Getter for property tgtClass.
	 *
	 * @return Value of property tgtClass.
	 */
	public Class getDataType() {
		return this.dataType;
	}

	/** 
	 * Setter for property sortProperty.
	 *
	 * @param sortProperty New value of property sortProperty.
	 */
	public void setSortProperty(PropertyDescriptor sortProperty) {
		this.sortProperty = sortProperty;
	}

	/** 
	 * Getter for property sortProperty.
	 *
	 * @return Value of property sortProperty.
	 */
	public PropertyDescriptor getSortProperty() {
		return this.sortProperty;
	}

	/** 
	 * Compares its two arguments for order. Sorts according to the following design.
	 * Note that if the ascending property is false, the values for +1 or -1 will be
	 * reversed.
	 * 
	 * <ul>
	 * <li>
	 * Giving null for the first argument will always give a -1 reply.
	 * </li>
	 * <li>
	 * Giving null for the second argument will always give a +1 reply.
	 * </li>
	 * <li>
	 * Giving null for the both arguments will always give a 0 reply.
	 * </li>
	 * <li>
	 * Objects whose sortProperty contains null will give a -1 reply relative to objects
	 * with a non-null sortProperty.
	 * </li>
	 * <li>
	 * If both objects' sort property are not null, The values of the sort properties
	 * will be compared.
	 * </li>
	 * </ul>
	 * 
	 *
	 * @param x Object to compare.
	 * @param y Second object to compare.
	 *
	 * @return A value of +1, -1 or 0 depending on the compare.
	 */
	public int compare(final Object x, final Object y) {
		if (ascending) {
			return compareHelper(x, y);
		} else {
			return (0 - compareHelper(x, y));
		}
	}

	/** 
	 * Perform the raw compare.
	 *
	 * @param x Object to compare.
	 * @param y Second object to compare.
	 *
	 * @return The result of the comparison
	 *
	 * @throws RuntimeException If there is an exception during ocmparison.
	 *
	 * @see Method {@link mirror.utilties.ReflexiveComparator.compare(Object, Object)}
	 */
	private int compareHelper(final Object x, final Object y) {
		try {
			if ((x != null) && (y == null)) {
				return -1;
			} else if ((x == null) && (y != null)) {
				return -1;
			} else if ((x == null) && (y == null)) {
				return 0;
			}

			Object xVal = this.sortProperty.getReadMethod()
				                           .invoke(x, null);
			Object yVal = this.sortProperty.getReadMethod()
				                           .invoke(y, null);

			if ((xVal != null) && (yVal == null)) {
				return -1;
			} else if ((xVal == null) && (yVal != null)) {
				return -1;
			} else if ((xVal == null) && (yVal == null)) {
				return 0;
			}

			return ((Comparable)xVal).compareTo(yVal);
		} catch (final InvocationTargetException ex) {
			throw new RuntimeException(ex);
		} catch (final IllegalAccessException ex) {
			throw new RuntimeException(ex);
		}
	}
}

/* ########## End of File ########## */