New test.
[mono.git] / mcs / class / Novell.Directory.Ldap / Novell.Directory.Ldap / LdapCompareAttrNames.cs
1 /******************************************************************************
2 * The MIT License
3 * Copyright (c) 2003 Novell Inc.  www.novell.com
4
5 * Permission is hereby granted, free of charge, to any person obtaining  a copy
6 * of this software and associated documentation files (the Software), to deal
7 * in the Software without restriction, including  without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
9 * copies of the Software, and to  permit persons to whom the Software is 
10 * furnished to do so, subject to the following conditions:
11
12 * The above copyright notice and this permission notice shall be included in 
13 * all copies or substantial portions of the Software.
14
15 * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *******************************************************************************/
23 //
24 // Novell.Directory.Ldap.LdapCompareAttrNames.cs
25 //
26 // Author:
27 //   Sunil Kumar (Sunilk@novell.com)
28 //
29 // (C) 2003 Novell, Inc (http://www.novell.com)
30 //
31
32 using System;
33 using Novell.Directory.Ldap.Utilclass;
34
35 namespace Novell.Directory.Ldap
36 {
37         
38         
39         /// <summary>  Compares Ldap entries based on attribute name.
40         /// 
41         /// An object of this class defines ordering when sorting LdapEntries,
42         /// usually from search results.  When using this Comparator, LdapEntry objects
43         /// are sorted by the attribute names(s) passed in on the
44         /// constructor, in ascending or descending order.  The object is typically
45         /// supplied to an implementation of the collection interfaces such as
46         /// java.util.TreeSet which performs sorting. 
47         /// 
48         /// Comparison is performed via locale-sensitive Java String comparison,
49         /// which may not correspond to the Ldap ordering rules by which an Ldap server
50         /// would sort them.
51         /// 
52         /// </summary>
53         public class LdapCompareAttrNames : System.Collections.IComparer
54         {
55                 private void  InitBlock()
56                 {
57 //                      location = Locale.getDefault();
58                         location=System.Globalization.CultureInfo.CurrentCulture;
59                         collator = System.Globalization.CultureInfo.CurrentCulture.CompareInfo;
60                 }
61                 /// <summary> Returns the locale to be used for sorting, if a locale has been
62                 /// specified.
63                 /// 
64                 /// If locale is null, a basic String.compareTo method is used for
65                 /// collation.  If non-null, a locale-specific collation is used. 
66                 /// 
67                 /// </summary>
68                 /// <returns> The locale if one has been specified
69                 /// </returns>
70                 /// <summary> Sets the locale to be used for sorting.
71                 /// 
72                 /// </summary>
73                 /// <param name="locale">  The locale to be used for sorting.
74                 /// </param>
75                 virtual public System.Globalization.CultureInfo Locale
76                 {
77                         get
78                         {
79                                 //currently supports only English local.
80                                 return location;
81                         }
82                         
83                         set
84                         {
85                                 collator = value.CompareInfo;
86                                 location = value;
87                         }
88                         
89                 }
90                 private System.String[] sortByNames; //names to to sort by.
91                 private bool[] sortAscending; //true if sorting ascending
92                 private System.Globalization.CultureInfo location;
93                 private System.Globalization.CompareInfo collator;
94                 
95                 /// <summary> Constructs an object that sorts results by a single attribute, in
96                 /// ascending order.
97                 /// 
98                 /// </summary>
99                 /// <param name="attrName">      Name of an attribute by which to sort.
100                 /// 
101                 /// </param>
102                 public LdapCompareAttrNames(System.String attrName)
103                 {
104                         InitBlock();
105                         sortByNames = new System.String[1];
106                         sortByNames[0] = attrName;
107                         sortAscending = new bool[1];
108                         sortAscending[0] = true;
109                 }
110                 
111                 /// <summary> Constructs an object that sorts results by a single attribute, in
112                 /// either ascending or descending order.
113                 /// 
114                 /// </summary>
115                 /// <param name="attrName">      Name of an attribute to sort by.
116                 /// 
117                 /// </param>
118                 /// <param name="ascendingFlag"> True specifies ascending order; false specifies
119                 /// descending order.
120                 /// </param>
121                 public LdapCompareAttrNames(System.String attrName, bool ascendingFlag)
122                 {
123                         InitBlock();
124                         sortByNames = new System.String[1];
125                         sortByNames[0] = attrName;
126                         sortAscending = new bool[1];
127                         sortAscending[0] = ascendingFlag;
128                 }
129                 
130                 
131                 /// <summary> Constructs an object that sorts by one or more attributes, in the
132                 /// order provided, in ascending order.
133                 /// 
134                 /// Note: Novell eDirectory allows sorting by one attribute only. The
135                 /// direcctory server must also be configured to index the specified
136                 /// attribute.
137                 /// 
138                 /// </summary>
139                 /// <param name="attrNames">     Array of names of attributes to sort by.
140                 /// 
141                 /// </param>
142                 public LdapCompareAttrNames(System.String[] attrNames)
143                 {
144                         InitBlock();
145                         sortByNames = new System.String[attrNames.Length];
146                         sortAscending = new bool[attrNames.Length];
147                         for (int i = 0; i < attrNames.Length; i++)
148                         {
149                                 sortByNames[i] = attrNames[i];
150                                 sortAscending[i] = true;
151                         }
152                 }
153                 
154                 /// <summary> Constructs an object that sorts by one or more attributes, in the
155                 /// order provided, in either ascending or descending order for each
156                 /// attribute.
157                 /// 
158                 /// Note: Novell eDirectory supports only ascending sort order (A,B,C ...)
159                 /// and allows sorting only by one attribute. The directory server must be
160                 /// configured to index this attribute.
161                 /// 
162                 /// </summary>
163                 /// <param name="attrNames">     Array of names of attributes to sort by.
164                 /// 
165                 /// </param>
166                 /// <param name="ascendingFlags"> Array of flags, one for each attrName, where
167                 /// true specifies ascending order and false specifies
168                 /// descending order. An LdapException is thrown if
169                 /// the length of ascendingFlags is not greater than
170                 /// or equal to the length of attrNames.
171                 /// 
172                 /// </param>
173                 /// <exception> LdapException A general exception which includes an error
174                 /// message and an Ldap error code.
175                 /// 
176                 /// </exception>
177                 public LdapCompareAttrNames(System.String[] attrNames, bool[] ascendingFlags)
178                 {
179                         InitBlock();
180                         if (attrNames.Length != ascendingFlags.Length)
181                         {
182                                 throw new LdapException(ExceptionMessages.UNEQUAL_LENGTHS, LdapException.INAPPROPRIATE_MATCHING, (System.String) null);
183                                 //"Length of attribute Name array does not equal length of Flags array"
184                         }
185                         sortByNames = new System.String[attrNames.Length];
186                         sortAscending = new bool[ascendingFlags.Length];
187                         for (int i = 0; i < attrNames.Length; i++)
188                         {
189                                 sortByNames[i] = attrNames[i];
190                                 sortAscending[i] = ascendingFlags[i];
191                         }
192                 }
193                 
194                 /// <summary> Compares the the attributes of the first LdapEntry to the second.
195                 /// Only the values of the attributes named at the construction of this
196                 /// object will be compared.  Multi-valued attributes compare on the first
197                 /// value only.  
198                 /// 
199                 /// </summary>
200                 /// <param name="object1">        Target entry for comparison.
201                 /// 
202                 /// </param>
203                 /// <param name="object2">        Entry to be compared to.
204                 /// 
205                 /// </param>
206                 /// <returns>     Negative value if the first entry is less than the second and
207                 /// positive if the first is greater than the second.  Zero is returned if all
208                 /// attributes to be compared are the same.
209                 /// </returns>
210                 public virtual int Compare(System.Object object1, System.Object object2)
211                 {
212                         LdapEntry entry1 = (LdapEntry) object1;
213                         LdapEntry entry2 = (LdapEntry) object2;
214                         LdapAttribute one, two;
215                         System.String[] first; //multivalued attributes are ignored.
216                         System.String[] second; //we just use the first element
217                         int compare, i = 0;
218                         if (collator == null)
219                         {
220                                 //using default locale
221                                 collator = System.Globalization.CultureInfo.CurrentCulture.CompareInfo;
222                         }
223                         
224                         do 
225                         {
226                                 //while first and second are equal
227                                 one = entry1.getAttribute(sortByNames[i]);
228                                 two = entry2.getAttribute(sortByNames[i]);
229                                 if ((one != null) && (two != null))
230                                 {
231                                         first = one.StringValueArray;
232                                         second = two.StringValueArray;
233                                         compare = collator.Compare(first[0], second[0]);
234                                 }
235                                 //We could also use the other multivalued attributes to break ties.
236                                 //one of the entries was null
237                                 else
238                                 {
239                                         if (one != null)
240                                                 compare = - 1;
241                                         //one is greater than two
242                                         else if (two != null)
243                                                 compare = 1;
244                                         //one is lesser than two
245                                         else
246                                                 compare = 0; //tie - break it with the next attribute name
247                                 }
248                                 
249                                 i++;
250                         }
251                         while ((compare == 0) && (i < sortByNames.Length));
252                         
253                         if (sortAscending[i - 1])
254                         {
255                                 // return the normal ascending comparison.
256                                 return compare;
257                         }
258                         else
259                         {
260                                 // negate the comparison for a descending comparison.
261                                 return - compare;
262                         }
263                 }
264                 
265                 /// <summary> Determines if this comparator is equal to the comparator passed in.
266                 /// 
267                 ///  This will return true if the comparator is an instance of
268                 /// LdapCompareAttrNames and compares the same attributes names in the same
269                 /// order.
270                 /// 
271                 /// </summary>
272                 /// <returns> true the comparators are equal
273                 /// </returns>
274                 public override bool Equals(System.Object comparator)
275                 {
276                         if (!(comparator is LdapCompareAttrNames))
277                         {
278                                 return false;
279                         }
280                         LdapCompareAttrNames comp = (LdapCompareAttrNames) comparator;
281                         
282                         // Test to see if the attribute to compare are the same length
283                         if ((comp.sortByNames.Length != this.sortByNames.Length) || (comp.sortAscending.Length != this.sortAscending.Length))
284                         {
285                                 return false;
286                         }
287                         
288                         // Test to see if the attribute names and sorting orders are the same.
289                         for (int i = 0; i < this.sortByNames.Length; i++)
290                         {
291                                 if (comp.sortAscending[i] != this.sortAscending[i])
292                                         return false;
293                                 if (!comp.sortByNames[i].ToUpper().Equals(this.sortByNames[i].ToUpper()))
294                                         return false;
295                         }
296                         return true;
297                 }
298         }
299 }