/*
* ItemComparator.java
*
* Version: $Revision: 3761 $
*
* Date: $Date: 2009-05-07 04:18:02 +0000 (Thu, 07 May 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.dspace.sort.OrderFormat;
/**
* Compare two Items by their DCValues.
*
* The DCValues to be compared are specified by the element, qualifier and
* language parameters to the constructor. If the Item has more than one
* matching DCValue, then the max parameter to the constructor specifies whether
* the maximum or minimum lexicographic value will be used.
*
* @author Peter Breton
* @version $Revision: 3761 $
*/
public class ItemComparator implements Comparator
{
/** Dublin Core element */
private String element;
/** Dublin Core qualifier */
private String qualifier;
/** Language */
private String language;
/** Whether maximum or minimum value will be used */
private boolean max;
/**
* Constructor.
*
* @param element
* The Dublin Core element
* @param qualifier
* The Dublin Core qualifier
* @param language
* The language for the DCValues
* @param max
* If true, and there is more than one DCValue for element,
* qualifier and language, then use the maximum value
* lexicographically; otherwise use the minimum value.
*/
public ItemComparator(String element, String qualifier, String language,
boolean max)
{
this.element = element;
this.qualifier = qualifier;
this.language = language;
this.max = max;
}
/**
* Compare two Items by checking their DCValues for element, qualifier, and
* language.
*
* <p>
* Return >= 1 if the first is lexicographically greater than the second; <=
* -1 if the second is lexicographically greater than the first, and 0
* otherwise.
* </p>
*
* @param first
* The first object to compare. Must be an object of type
* org.dspace.content.Item.
* @param second
* The second object to compare. Must be an object of type
* org.dspace.content.Item.
* @return >= 1 if the first is lexicographically greater than the second; <=
* -1 if the second is lexicographically greater than the first, and
* 0 otherwise.
*/
public int compare(Object first, Object second)
{
if ((!(first instanceof Item)) || (!(second instanceof Item)))
{
throw new IllegalArgumentException("Arguments must be Items");
}
// Retrieve a chosen value from the array for comparison
String firstValue = getValue((Item) first);
String secondValue = getValue((Item) second);
if ((firstValue == null) && (secondValue == null))
{
return 0;
}
if ((firstValue != null) && (secondValue == null))
{
return 1;
}
if ((firstValue == null) && (secondValue != null))
{
return -1;
}
// See the javadoc for java.lang.String for an explanation
// of the return value.
return firstValue.compareTo(secondValue);
}
/**
* Return true if the object is equal to this one, false otherwise. Another
* object is equal to this one if it is also an ItemComparator, and has the
* same values for element, qualifier, language, and max.
*
* @param obj
* The object to compare to.
* @return True if the other object is equal to this one, false otherwise.
*/
public boolean equals(Object obj)
{
if (!(obj instanceof ItemComparator))
{
return false;
}
ItemComparator other = (ItemComparator) obj;
return _equals(element, other.element)
&& _equals(qualifier, other.qualifier)
&& _equals(language, other.language) && (max == other.max);
}
/**
* Return true if the first string is equal to the second. Either or both
* may be null.
*/
private boolean _equals(String first, String second)
{
if ((first == null) && (second == null))
{
return true;
}
if ((first != null) && (second == null))
{
return false;
}
if ((first == null) && (second != null))
{
return false;
}
return first.equals(second);
}
/**
* Choose the canonical value from an item for comparison. If there are no
* values, null is returned. If there is exactly one value, then it is
* returned. Otherwise, either the maximum or minimum lexicographical value
* is returned; the parameter to the constructor says which.
*
* @param item
* The item to check
* @return The chosen value, or null
*/
private String getValue(Item item)
{
// The overall array and each element are guaranteed non-null
DCValue[] dcvalues = item.getDC(element, qualifier, language);
if (dcvalues.length == 0)
{
return null;
}
if (dcvalues.length == 1)
{
return normalizeTitle(dcvalues[0]);
}
// We want to sort using Strings, but also keep track of
// which DCValue the value came from.
Map values = new HashMap();
for (int i = 0; i < dcvalues.length; i++)
{
String value = dcvalues[i].value;
if (value != null)
{
values.put(value, new Integer(i));
}
}
if (values.size() == 0)
{
return null;
}
Set valueSet = values.keySet();
String chosen = max ? (String) Collections.max(valueSet)
: (String) Collections.min(valueSet);
int index = ((Integer) values.get(chosen)).intValue();
return normalizeTitle(dcvalues[index]);
}
/**
* Normalize the title of a DCValue.
*/
private String normalizeTitle(DCValue value)
{
if (!"title".equals(element))
{
return value.value;
}
return OrderFormat.makeSortString(value.value, value.language, OrderFormat.TITLE);
}
}