- /*
- * Copyright 2001-2004 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.commons.collections.comparators;
-
- import java.util.Comparator;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
-
- /**
- * A Comparator which imposes a specific order on a specific set of Objects.
- * Objects are presented to the FixedOrderComparator in a specified order and
- * subsequent calls to {@link #compare(Object, Object) compare} yield that order.
- * For example:
- * <pre>
- * String[] planets = {"Mercury", "Venus", "Earth", "Mars"};
- * FixedOrderComparator distanceFromSun = new FixedOrderComparator(planets);
- * Arrays.sort(planets); // Sort to alphabetical order
- * Arrays.sort(planets, distanceFromSun); // Back to original order
- * </pre>
- * <p>
- * Once <code>compare</code> has been called, the FixedOrderComparator is locked
- * and attempts to modify it yield an UnsupportedOperationException.
- * <p>
- * Instances of FixedOrderComparator are not synchronized. The class is not
- * thread-safe at construction time, but it is thread-safe to perform
- * multiple comparisons after all the setup operations are complete.
- *
- * @since Commons Collections 3.0
- * @version $Revision: 1.10 $ $Date: 2004/05/15 13:24:11 $
- *
- * @author David Leppik
- * @author Stephen Colebourne
- * @author Janek Bogucki
- */
- public class FixedOrderComparator implements Comparator {
-
- /**
- * Behavior when comparing unknown Objects:
- * unknown objects compare as before known Objects.
- */
- public static final int UNKNOWN_BEFORE = 0;
-
- /**
- * Behavior when comparing unknown Objects:
- * unknown objects compare as after known Objects.
- */
- public static final int UNKNOWN_AFTER = 1;
-
- /**
- * Behavior when comparing unknown Objects:
- * unknown objects cause a IllegalArgumentException to be thrown.
- * This is the default behavior.
- */
- public static final int UNKNOWN_THROW_EXCEPTION = 2;
-
- /** Internal map of object to position */
- private final Map map = new HashMap();
- /** Counter used in determining the position in the map */
- private int counter = 0;
- /** Is the comparator locked against further change */
- private boolean isLocked = false;
- /** The behaviour in the case of an unknown object */
- private int unknownObjectBehavior = UNKNOWN_THROW_EXCEPTION;
-
- // Constructors
- //-----------------------------------------------------------------------
- /**
- * Constructs an empty FixedOrderComparator.
- */
- public FixedOrderComparator() {
- super();
- }
-
- /**
- * Constructs a FixedOrderComparator which uses the order of the given array
- * to compare the objects.
- * <p>
- * The array is copied, so later changes will not affect the comparator.
- *
- * @param items the items that the comparator can compare in order
- * @throws IllegalArgumentException if the array is null
- */
- public FixedOrderComparator(Object[] items) {
- super();
- if (items == null) {
- throw new IllegalArgumentException("The list of items must not be null");
- }
- for (int i = 0; i < items.length; i++) {
- add(items[i]);
- }
- }
-
- /**
- * Constructs a FixedOrderComparator which uses the order of the given list
- * to compare the objects.
- * <p>
- * The list is copied, so later changes will not affect the comparator.
- *
- * @param items the items that the comparator can compare in order
- * @throws IllegalArgumentException if the list is null
- */
- public FixedOrderComparator(List items) {
- super();
- if (items == null) {
- throw new IllegalArgumentException("The list of items must not be null");
- }
- for (Iterator it = items.iterator(); it.hasNext();) {
- add(it.next());
- }
- }
-
- // Bean methods / state querying methods
- //-----------------------------------------------------------------------
- /**
- * Returns true if modifications cannot be made to the FixedOrderComparator.
- * FixedOrderComparators cannot be modified once they have performed a comparison.
- *
- * @return true if attempts to change the FixedOrderComparator yield an
- * UnsupportedOperationException, false if it can be changed.
- */
- public boolean isLocked() {
- return isLocked;
- }
-
- /**
- * Checks to see whether the comparator is now locked against further changes.
- *
- * @throws UnsupportedOperationException if the comparator is locked
- */
- protected void checkLocked() {
- if (isLocked()) {
- throw new UnsupportedOperationException("Cannot modify a FixedOrderComparator after a comparison");
- }
- }
-
- /**
- * Gets the behavior for comparing unknown objects.
- *
- * @return the flag for unknown behaviour - UNKNOWN_AFTER,
- * UNKNOWN_BEFORE or UNKNOWN_THROW_EXCEPTION
- */
- public int getUnknownObjectBehavior() {
- return unknownObjectBehavior;
- }
-
- /**
- * Sets the behavior for comparing unknown objects.
- *
- * @param unknownObjectBehavior the flag for unknown behaviour -
- * UNKNOWN_AFTER, UNKNOWN_BEFORE or UNKNOWN_THROW_EXCEPTION
- * @throws UnsupportedOperationException if a comparison has been performed
- * @throws IllegalArgumentException if the unknown flag is not valid
- */
- public void setUnknownObjectBehavior(int unknownObjectBehavior) {
- checkLocked();
- if (unknownObjectBehavior != UNKNOWN_AFTER
- && unknownObjectBehavior != UNKNOWN_BEFORE
- && unknownObjectBehavior != UNKNOWN_THROW_EXCEPTION) {
- throw new IllegalArgumentException("Unrecognised value for unknown behaviour flag");
- }
- this.unknownObjectBehavior = unknownObjectBehavior;
- }
-
- // Methods for adding items
- //-----------------------------------------------------------------------
- /**
- * Adds an item, which compares as after all items known to the Comparator.
- * If the item is already known to the Comparator, its old position is
- * replaced with the new position.
- *
- * @param obj the item to be added to the Comparator.
- * @return true if obj has been added for the first time, false if
- * it was already known to the Comparator.
- * @throws UnsupportedOperationException if a comparison has already been made
- */
- public boolean add(Object obj) {
- checkLocked();
- Object position = map.put(obj, new Integer(counter++));
- return (position == null);
- }
-
- /**
- * Adds a new item, which compares as equal to the given existing item.
- *
- * @param existingObj an item already in the Comparator's set of
- * known objects
- * @param newObj an item to be added to the Comparator's set of
- * known objects
- * @return true if newObj has been added for the first time, false if
- * it was already known to the Comparator.
- * @throws IllegalArgumentException if existingObject is not in the
- * Comparator's set of known objects.
- * @throws UnsupportedOperationException if a comparison has already been made
- */
- public boolean addAsEqual(Object existingObj, Object newObj) {
- checkLocked();
- Integer position = (Integer) map.get(existingObj);
- if (position == null) {
- throw new IllegalArgumentException(existingObj + " not known to " + this);
- }
- Object result = map.put(newObj, position);
- return (result == null);
- }
-
- // Comparator methods
- //-----------------------------------------------------------------------
- /**
- * Compares two objects according to the order of this Comparator.
- * <p>
- * It is important to note that this class will throw an IllegalArgumentException
- * in the case of an unrecognised object. This is not specified in the
- * Comparator interface, but is the most appropriate exception.
- *
- * @param obj1 the first object to compare
- * @param obj2 the second object to compare
- * @return negative if obj1 is less, positive if greater, zero if equal
- * @throws IllegalArgumentException if obj1 or obj2 are not known
- * to this Comparator and an alternative behavior has not been set
- * via {@link #setUnknownObjectBehavior(int)}.
- */
- public int compare(Object obj1, Object obj2) {
- isLocked = true;
- Integer position1 = (Integer) map.get(obj1);
- Integer position2 = (Integer) map.get(obj2);
- if (position1 == null || position2 == null) {
- switch (unknownObjectBehavior) {
- case UNKNOWN_BEFORE :
- if (position1 == null) {
- return (position2 == null) ? 0 : -1;
- } else {
- return 1;
- }
- case UNKNOWN_AFTER :
- if (position1 == null) {
- return (position2 == null) ? 0 : 1;
- } else {
- return -1;
- }
- case UNKNOWN_THROW_EXCEPTION :
- Object unknownObj = (position1 == null) ? obj1 : obj2;
- throw new IllegalArgumentException("Attempting to compare unknown object " + unknownObj);
- default :
- throw new UnsupportedOperationException("Unknown unknownObjectBehavior: " + unknownObjectBehavior);
- }
- } else {
- return position1.compareTo(position2);
- }
- }
-
- }