// // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // /****************************************************************************** * The MIT License * Copyright (c) 2003 Novell Inc. www.novell.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the Software), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *******************************************************************************/ // // Novell.Directory.Ldap.LdapCompareAttrNames.cs // // Author: // Sunil Kumar (Sunilk@novell.com) // // (C) 2003 Novell, Inc (http://www.novell.com) // using System; using Novell.Directory.Ldap.Utilclass; namespace Novell.Directory.Ldap { /// Compares Ldap entries based on attribute name. /// /// An object of this class defines ordering when sorting LdapEntries, /// usually from search results. When using this Comparator, LdapEntry objects /// are sorted by the attribute names(s) passed in on the /// constructor, in ascending or descending order. The object is typically /// supplied to an implementation of the collection interfaces such as /// java.util.TreeSet which performs sorting. /// /// Comparison is performed via locale-sensitive Java String comparison, /// which may not correspond to the Ldap ordering rules by which an Ldap server /// would sort them. /// /// public class LdapCompareAttrNames : System.Collections.IComparer { private void InitBlock() { // location = Locale.getDefault(); location=System.Globalization.CultureInfo.CurrentCulture; collator = System.Globalization.CultureInfo.CurrentCulture.CompareInfo; } /// Returns the locale to be used for sorting, if a locale has been /// specified. /// /// If locale is null, a basic String.compareTo method is used for /// collation. If non-null, a locale-specific collation is used. /// /// /// The locale if one has been specified /// /// Sets the locale to be used for sorting. /// /// /// The locale to be used for sorting. /// virtual public System.Globalization.CultureInfo Locale { get { //currently supports only English local. return location; } set { collator = value.CompareInfo; location = value; } } private System.String[] sortByNames; //names to to sort by. private bool[] sortAscending; //true if sorting ascending private System.Globalization.CultureInfo location; private System.Globalization.CompareInfo collator; /// Constructs an object that sorts results by a single attribute, in /// ascending order. /// /// /// Name of an attribute by which to sort. /// /// public LdapCompareAttrNames(System.String attrName) { InitBlock(); sortByNames = new System.String[1]; sortByNames[0] = attrName; sortAscending = new bool[1]; sortAscending[0] = true; } /// Constructs an object that sorts results by a single attribute, in /// either ascending or descending order. /// /// /// Name of an attribute to sort by. /// /// /// True specifies ascending order; false specifies /// descending order. /// public LdapCompareAttrNames(System.String attrName, bool ascendingFlag) { InitBlock(); sortByNames = new System.String[1]; sortByNames[0] = attrName; sortAscending = new bool[1]; sortAscending[0] = ascendingFlag; } /// Constructs an object that sorts by one or more attributes, in the /// order provided, in ascending order. /// /// Note: Novell eDirectory allows sorting by one attribute only. The /// direcctory server must also be configured to index the specified /// attribute. /// /// /// Array of names of attributes to sort by. /// /// public LdapCompareAttrNames(System.String[] attrNames) { InitBlock(); sortByNames = new System.String[attrNames.Length]; sortAscending = new bool[attrNames.Length]; for (int i = 0; i < attrNames.Length; i++) { sortByNames[i] = attrNames[i]; sortAscending[i] = true; } } /// Constructs an object that sorts by one or more attributes, in the /// order provided, in either ascending or descending order for each /// attribute. /// /// Note: Novell eDirectory supports only ascending sort order (A,B,C ...) /// and allows sorting only by one attribute. The directory server must be /// configured to index this attribute. /// /// /// Array of names of attributes to sort by. /// /// /// Array of flags, one for each attrName, where /// true specifies ascending order and false specifies /// descending order. An LdapException is thrown if /// the length of ascendingFlags is not greater than /// or equal to the length of attrNames. /// /// /// LdapException A general exception which includes an error /// message and an Ldap error code. /// /// public LdapCompareAttrNames(System.String[] attrNames, bool[] ascendingFlags) { InitBlock(); if (attrNames.Length != ascendingFlags.Length) { throw new LdapException(ExceptionMessages.UNEQUAL_LENGTHS, LdapException.INAPPROPRIATE_MATCHING, (System.String) null); //"Length of attribute Name array does not equal length of Flags array" } sortByNames = new System.String[attrNames.Length]; sortAscending = new bool[ascendingFlags.Length]; for (int i = 0; i < attrNames.Length; i++) { sortByNames[i] = attrNames[i]; sortAscending[i] = ascendingFlags[i]; } } /// Compares the the attributes of the first LdapEntry to the second. /// Only the values of the attributes named at the construction of this /// object will be compared. Multi-valued attributes compare on the first /// value only. /// /// /// Target entry for comparison. /// /// /// Entry to be compared to. /// /// /// Negative value if the first entry is less than the second and /// positive if the first is greater than the second. Zero is returned if all /// attributes to be compared are the same. /// public virtual int Compare(System.Object object1, System.Object object2) { LdapEntry entry1 = (LdapEntry) object1; LdapEntry entry2 = (LdapEntry) object2; LdapAttribute one, two; System.String[] first; //multivalued attributes are ignored. System.String[] second; //we just use the first element int compare, i = 0; if (collator == null) { //using default locale collator = System.Globalization.CultureInfo.CurrentCulture.CompareInfo; } do { //while first and second are equal one = entry1.getAttribute(sortByNames[i]); two = entry2.getAttribute(sortByNames[i]); if ((one != null) && (two != null)) { first = one.StringValueArray; second = two.StringValueArray; compare = collator.Compare(first[0], second[0]); } //We could also use the other multivalued attributes to break ties. //one of the entries was null else { if (one != null) compare = - 1; //one is greater than two else if (two != null) compare = 1; //one is lesser than two else compare = 0; //tie - break it with the next attribute name } i++; } while ((compare == 0) && (i < sortByNames.Length)); if (sortAscending[i - 1]) { // return the normal ascending comparison. return compare; } else { // negate the comparison for a descending comparison. return - compare; } } /// Determines if this comparator is equal to the comparator passed in. /// /// This will return true if the comparator is an instance of /// LdapCompareAttrNames and compares the same attributes names in the same /// order. /// /// /// true the comparators are equal /// public override bool Equals(System.Object comparator) { if (!(comparator is LdapCompareAttrNames)) { return false; } LdapCompareAttrNames comp = (LdapCompareAttrNames) comparator; // Test to see if the attribute to compare are the same length if ((comp.sortByNames.Length != this.sortByNames.Length) || (comp.sortAscending.Length != this.sortAscending.Length)) { return false; } // Test to see if the attribute names and sorting orders are the same. for (int i = 0; i < this.sortByNames.Length; i++) { if (comp.sortAscending[i] != this.sortAscending[i]) return false; if (!comp.sortByNames[i].ToUpper().Equals(this.sortByNames[i].ToUpper())) return false; } return true; } } }