001: /*
002: * Copyright 2002-2005 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.util.comparator;
018:
019: import java.io.Serializable;
020: import java.util.ArrayList;
021: import java.util.Comparator;
022: import java.util.Iterator;
023: import java.util.List;
024:
025: import org.springframework.util.Assert;
026:
027: /**
028: * A comparator that chains a sequence of one or more more Comparators.
029: *
030: * <p>A compound comparator calls each Comparator in sequence until a single
031: * Comparator returns a non-zero result, or the comparators are exhausted and
032: * zero is returned.
033: *
034: * <p>This facilitates in-memory sorting similar to multi-column sorting in SQL.
035: * The order of any single Comparator in the list can also be reversed.
036: *
037: * @author Keith Donald
038: * @author Juergen Hoeller
039: * @since 1.2.2
040: */
041: public class CompoundComparator implements Comparator, Serializable {
042:
043: private final List comparators;
044:
045: /**
046: * Construct a CompoundComparator with initially no Comparators. Clients
047: * must add at least one Comparator before calling the compare method or an
048: * IllegalStateException is thrown.
049: */
050: public CompoundComparator() {
051: this .comparators = new ArrayList();
052: }
053:
054: /**
055: * Construct a CompoundComparator from the Comparators in the provided array.
056: * <p>All Comparators will default to ascending sort order,
057: * unless they are InvertibleComparators.
058: * @param comparators the comparators to build into a compound comparator
059: * @see InvertibleComparator
060: */
061: public CompoundComparator(Comparator[] comparators) {
062: this .comparators = new ArrayList(comparators.length);
063: for (int i = 0; i < comparators.length; i++) {
064: addComparator(comparators[i]);
065: }
066: }
067:
068: /**
069: * Add a Comparator to the end of the chain.
070: * <p>The Comparator will default to ascending sort order,
071: * unless it is a InvertibleComparator.
072: * @param comparator the Comparator to add to the end of the chain
073: * @see InvertibleComparator
074: */
075: public void addComparator(Comparator comparator) {
076: if (comparator instanceof InvertibleComparator) {
077: this .comparators.add(comparator);
078: } else {
079: this .comparators.add(new InvertibleComparator(comparator));
080: }
081: }
082:
083: /**
084: * Add a Comparator to the end of the chain using the provided sort order.
085: * @param comparator the Comparator to add to the end of the chain
086: * @param ascending the sort order: ascending (true) or descending (false)
087: */
088: public void addComparator(Comparator comparator, boolean ascending) {
089: this .comparators.add(new InvertibleComparator(comparator,
090: ascending));
091: }
092:
093: /**
094: * Replace the Comparator at the given index.
095: * <p>The Comparator will default to ascending sort order,
096: * unless it is a InvertibleComparator.
097: * @param index the index of the Comparator to replace
098: * @param comparator the Comparator to place at the given index
099: * @see InvertibleComparator
100: */
101: public void setComparator(int index, Comparator comparator) {
102: if (comparator instanceof InvertibleComparator) {
103: this .comparators.set(index, comparator);
104: } else {
105: InvertibleComparator invComp = new InvertibleComparator(
106: comparator);
107: this .comparators.set(index, invComp);
108: }
109: }
110:
111: /**
112: * Replace the Comparator at the given index using the given sort order.
113: * @param index the index of the Comparator to replace
114: * @param comparator the Comparator to place at the given index
115: * @param ascending the sort order: ascending (true) or descending (false)
116: */
117: public void setComparator(int index, Comparator comparator,
118: boolean ascending) {
119: InvertibleComparator invComp = new InvertibleComparator(
120: comparator, ascending);
121: this .comparators.set(index, invComp);
122: }
123:
124: /**
125: * Invert the sort order of each sort definition contained by this compound
126: * comparator.
127: */
128: public void invertOrder() {
129: Iterator it = this .comparators.iterator();
130: while (it.hasNext()) {
131: ((InvertibleComparator) it.next()).invertOrder();
132: }
133: }
134:
135: /**
136: * Invert the sort order of the sort definition at the specified index.
137: * @param index the index of the comparator to invert
138: */
139: public void invertOrder(int index) {
140: getInvertibleComparator(index).invertOrder();
141: }
142:
143: /**
144: * Change the sort order at the given index to ascending.
145: * @param index the index of the comparator to change
146: */
147: public void setAscendingOrder(int index) {
148: getInvertibleComparator(index).setAscending(true);
149: }
150:
151: /**
152: * Change the sort order at the given index to descending sort.
153: * @param index the index of the comparator to change
154: */
155: public void setDescendingOrder(int index) {
156: getInvertibleComparator(index).setAscending(false);
157: }
158:
159: /**
160: * Return the InvertibleComparator for the given index, if any.
161: */
162: private InvertibleComparator getInvertibleComparator(int index) {
163: return (InvertibleComparator) this .comparators.get(index);
164: }
165:
166: /**
167: * Returns the number of aggregated comparators.
168: */
169: public int getComparatorCount() {
170: return comparators.size();
171: }
172:
173: public int compare(Object o1, Object o2) {
174: Assert
175: .state(this .comparators.size() > 0,
176: "No sort definitions have been added to this CompoundComparator to compare");
177: for (Iterator it = this .comparators.iterator(); it.hasNext();) {
178: InvertibleComparator def = (InvertibleComparator) it.next();
179: int result = def.compare(o1, o2);
180: if (result != 0) {
181: return result;
182: }
183: }
184: return 0;
185: }
186:
187: public boolean equals(Object obj) {
188: if (this == obj) {
189: return true;
190: }
191: if (!(obj instanceof CompoundComparator)) {
192: return false;
193: }
194: CompoundComparator other = (CompoundComparator) obj;
195: return this .comparators.equals(other.comparators);
196: }
197:
198: public int hashCode() {
199: return this .comparators.hashCode();
200: }
201:
202: public String toString() {
203: return "CompoundComparator: " + this.comparators;
204: }
205:
206: }
|