001: /* ====================================================================
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 2001 The Apache Software Foundation. All rights
005: * reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The end-user documentation included with the redistribution,
020: * if any, must include the following acknowledgment:
021: * "This product includes software developed by the
022: * Apache Software Foundation (http://www.apache.org/)."
023: * Alternately, this acknowledgment may appear in the software itself,
024: * if and wherever such third-party acknowledgments normally appear.
025: *
026: * 4. The names "Apache" and "Apache Software Foundation" and
027: * "Apache Commons" must not be used to endorse or promote products
028: * derived from this software without prior written permission. For
029: * written permission, please contact apache@apache.org.
030: *
031: * 5. Products derived from this software may not be called "Apache",
032: * "Apache Turbine", nor may "Apache" appear in their name, without
033: * prior written permission of the Apache Software Foundation.
034: *
035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: *
049: * This software consists of voluntary contributions made by many
050: * individuals on behalf of the Apache Software Foundation. For more
051: * information on the Apache Software Foundation, please see
052: * <http://www.apache.org/>.
053: */
054: package com.jidesoft.comparator;
055:
056: import java.io.Serializable;
057: import java.util.Comparator;
058:
059: /**
060: * A Comparator that compares Comparable objects.
061: * Throws ClassCastExceptions if the objects are not
062: * Comparable, or if they are null.
063: * Throws ClassCastException if the compareTo of both
064: * objects do not provide an inverse result of each other
065: * as per the Comparable javadoc. This Comparator is useful, for example,
066: * for enforcing the natural order in custom implementations
067: * of SortedSet and SortedMap.
068: * <br>
069: * If both objects are null, they will be treated as equal. If one is null and the other
070: * is not, the null value will be treated as smaller then non-null value.
071: *
072: * @author bayard@generationjava.com
073: * @author JIDE Software
074: */
075: public class ComparableComparator implements Comparator, Serializable {
076:
077: private static final ComparableComparator instance = new ComparableComparator();
078:
079: /**
080: * Return a shared instance of a ComparableComparator. Developers are
081: * encouraged to use the comparator returned from this method instead of
082: * constructing a new instance to reduce allocation and GC overhead when
083: * multiple comparable comparators may be used in the same VM.
084: *
085: * @return an instance of ComparableComparator.
086: */
087: public static ComparableComparator getInstance() {
088: return instance;
089: }
090:
091: private static final long serialVersionUID = -291439688585137865L;
092:
093: /**
094: * Constructs a ComparableComparator.
095: */
096: public ComparableComparator() {
097: }
098:
099: public int compare(Object o1, Object o2) {
100: if (o1 == null && o2 == null) {
101: return 0;
102: } else if (o1 == null) {
103: return -1;
104: } else if (o2 == null) {
105: return 1;
106: }
107:
108: if (o1 instanceof Comparable) {
109: if (o2 instanceof Comparable) {
110: int result1 = 0;
111: int result2 = 0;
112: try {
113: result1 = ((Comparable) o1).compareTo(o2);
114: result2 = ((Comparable) o2).compareTo(o1);
115: } catch (ClassCastException e) {
116: return o1.getClass().getName().compareTo(
117: o2.getClass().getName()); // fall back to compare the string
118: }
119:
120: // enforce comparable contract
121: if (result1 == 0 && result2 == 0) {
122: return 0;
123: } else if (result1 < 0 && result2 > 0) { // to make sure the two results are consistent
124: return result1;
125: } else if (result1 > 0 && result2 < 0) { // to make sure the two results are consistent
126: return result1;
127: } else {
128: // results inconsistent
129: throw new ClassCastException(
130: "The two compareTo methods of o1 and o2 returned two inconsistent results. Please make sure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y.");
131: }
132: } else {
133: // o2 wasn't comparable
134: throw new ClassCastException(
135: "The second argument of this method was not a Comparable: "
136: + o2.getClass().getName());
137: }
138: } else if (o2 instanceof Comparable) {
139: // o1 wasn't comparable
140: throw new ClassCastException(
141: "The first argument of this method was not a Comparable: "
142: + o1.getClass().getName());
143: } else {
144: // neither were comparable
145: throw new ClassCastException(
146: "Both arguments of this method were not Comparables: "
147: + o1.getClass().getName() + " and "
148: + o2.getClass().getName());
149: }
150: }
151: }
|