#region License
/*
* Copyright 2002-2005 the original author or authors.
*
* 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.
*/
#endregion
#region Imports
using System;
using System.Collections;
using System.Globalization;
using Common.Logging;
using Spring.Core;
using Spring.Util;
#endregion
namespace Spring.Objects.Support{
/// <summary>
/// Performs a comparison of two objects, using the specified object property via
/// an <see cref="Spring.Objects.IObjectWrapper"/>.
/// </summary>
/// <author>Juergen Hoeller</author>
/// <author>Jean-Pierre Pawlak</author>
/// <author>Simon White (.NET)</author>
public class PropertyComparator : IComparer
{
private static readonly ILog logger
= LogManager.GetLogger(typeof (PropertyComparator));
private ISortDefinition sortDefinition;
private readonly IDictionary cachedObjectWrappers = new Hashtable();
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Objects.Support.PropertyComparator"/> class.
/// </summary>
/// <param name="definition">
/// The <see cref="Spring.Objects.Support.ISortDefinition"/> to use for any
/// sorting.
/// </param>
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="definition"/> is <cref lang="null"/>.
/// </exception>
public PropertyComparator(ISortDefinition definition)
{
AssertUtils.ArgumentNotNull(definition, "definition");
this.sortDefinition = definition;
}
/// <summary>
/// Gets the <see cref="Spring.Objects.Support.ISortDefinition"/> to
/// use for any sorting.
/// </summary>
/// <value>
/// The <see cref="Spring.Objects.Support.ISortDefinition"/> to use for
/// any sorting.
/// </value>
public ISortDefinition SortDefinition
{
get { return this.sortDefinition; }
}
/// <summary>
/// Compares two objects and returns a value indicating whether one is less
/// than, equal to or greater than the other.
/// </summary>
/// <param name="o1">The first object to compare.</param>
/// <param name="o2">The second object to compare.</param>
/// <returns><see cref="System.Collections.IComparer.Compare"/></returns>
public virtual int Compare(object o1, object o2)
{
object v1 = GetPropertyValue(o1);
object v2 = GetPropertyValue(o2);
if (this.sortDefinition.IgnoreCase
&& (v1 is string)
&& (v2 is string))
{
v1 = ((string) v1).ToLower(CultureInfo.CurrentCulture);
v2 = ((string) v2).ToLower(CultureInfo.CurrentCulture);
}
int result = 0;
try
{
if (v1 != null)
{
if (v2 != null)
{
result = ((IComparable) v1).CompareTo(v2);
}
else
{
result = -1;
}
}
else
{
if (v2 != null)
{
result = 1;
}
else
{
result = 0;
}
}
}
catch (Exception ex)
{
#region Instrumentation
if (logger.IsWarnEnabled)
{
logger.Warn("Could not sort objects [" + o1 + "] and [" + o2 + "]",
ex);
}
#endregion
return 0;
}
return (this.sortDefinition.Ascending ? result : -result);
}
/// <summary>
/// Get the <see cref="Spring.Objects.Support.ISortDefinition"/>'s property
/// value for the given object.
/// </summary>
/// <param name="obj">The object to get the property value for.</param>
/// <returns>The property value.</returns>
private object GetPropertyValue(object obj)
{
object propertyValue = null;
if (obj != null)
{
IObjectWrapper ow = (IObjectWrapper) this.cachedObjectWrappers[obj];
if (ow == null)
{
ow = new ObjectWrapper(obj);
this.cachedObjectWrappers.Add(obj, ow);
}
try
{
propertyValue = ow.GetPropertyValue(this.sortDefinition.Property);
}
catch (InvalidPropertyException)
{
// the property doesn't exist in the first place, so let exception through...
throw;
}
catch (ObjectsException ex)
{
// if a nested property cannot be read, simply return null...
if (logger.IsDebugEnabled)
{
logger.Debug("Could not access property - treating as null for sorting.", ex);
}
}
}
return propertyValue;
}
/// <summary>
/// Sort the given <see cref="System.Collections.IList"/> according to the
/// given sort definition.
/// </summary>
/// <param name="source">
/// The <see cref="System.Collections.IList"/> to be sorted.
/// </param>
/// <param name="sortDefinition">The parameters to sort by.</param>
/// <exception cref="Spring.Objects.ObjectsException">
/// In the case of a missing property name.
/// </exception>
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="sortDefinition"/> is <cref lang="null"/>.
/// </exception>
public static void Sort(IList source, ISortDefinition sortDefinition)
{
// ArrayList.Adapter(source).Sort(new PropertyComparator(sortDefinition));
ICollection coll = CollectionUtils.StableSort(source, new PropertyComparator(sortDefinition));
int index = 0;
IEnumerator it = coll.GetEnumerator();
while(it.MoveNext())
{
source[index] = it.Current;
index++;
}
}
}
}
|