001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.types; 028 029 030 031 import org.opends.server.api.OrderingMatchingRule; 032 033 import static org.opends.server.loggers.debug.DebugLogger.*; 034 import org.opends.server.loggers.debug.DebugTracer; 035 036 037 038 /** 039 * This class defines a data structure that may be used as a sort key. 040 * It includes an attribute type and a boolean value that indicates 041 * whether the sort should be ascending or descending. It may also 042 * contain a specific ordering matching rule that should be used for 043 * the sorting process, although if none is provided it will use the 044 * default ordering matching rule for the attribute type. 045 */ 046 @org.opends.server.types.PublicAPI( 047 stability=org.opends.server.types.StabilityLevel.VOLATILE, 048 mayInstantiate=true, 049 mayExtend=false, 050 mayInvoke=true) 051 public final class SortKey 052 { 053 /** 054 * The tracer object for the debug logger. 055 */ 056 private static final DebugTracer TRACER = getTracer(); 057 058 // The attribute type for this sort key. 059 private AttributeType attributeType; 060 061 // The indication of whether the sort should be ascending. 062 private boolean ascending; 063 064 // The ordering matching rule to use with this sort key. 065 private OrderingMatchingRule orderingRule; 066 067 068 069 /** 070 * Creates a new sort key with the provided information. 071 * 072 * @param attributeType The attribute type for this sort key. 073 * @param ascending Indicates whether the sort should be in 074 * ascending order rather than descending. 075 */ 076 public SortKey(AttributeType attributeType, boolean ascending) 077 { 078 this.attributeType = attributeType; 079 this.ascending = ascending; 080 081 orderingRule = null; 082 } 083 084 085 086 /** 087 * Creates a new sort key with the provided information. 088 * 089 * @param attributeType The attribute type for this sort key. 090 * @param ascending Indicates whether the sort should be in 091 * ascending order rather than descending. 092 * @param orderingRule The ordering matching rule to use with 093 * this sort key. 094 */ 095 public SortKey(AttributeType attributeType, boolean ascending, 096 OrderingMatchingRule orderingRule) 097 { 098 this.attributeType = attributeType; 099 this.ascending = ascending; 100 this.orderingRule = orderingRule; 101 } 102 103 104 105 /** 106 * Retrieves the attribute type for this sort key. 107 * 108 * @return The attribute type for this sort key. 109 */ 110 public AttributeType getAttributeType() 111 { 112 return attributeType; 113 } 114 115 116 117 /** 118 * Indicates whether the specified attribute should be sorted in 119 * ascending order. 120 * 121 * @return {@code true} if the attribute should be sorted in 122 * ascending order, or {@code false} if it should be sorted 123 * in descending order. 124 */ 125 public boolean ascending() 126 { 127 return ascending; 128 } 129 130 131 132 /** 133 * Retrieves the ordering matching rule to use with this sort key. 134 * 135 * @return The ordering matching rule to use with this sort key. 136 */ 137 public OrderingMatchingRule getOrderingRule() 138 { 139 return orderingRule; 140 } 141 142 143 144 /** 145 * Compares the provided values using this sort key. 146 * 147 * @param value1 The first value to be compared. 148 * @param value2 The second value to be compared. 149 * 150 * @return A negative value if the first value should come before 151 * the second in a sorted list, a positive value if the 152 * first value should come after the second in a sorted 153 * list, or zero if there is no relative difference between 154 * the values. 155 */ 156 public int compareValues(AttributeValue value1, 157 AttributeValue value2) 158 { 159 // A null value will always come after a non-null value. 160 if (value1 == null) 161 { 162 if (value2 == null) 163 { 164 return 0; 165 } 166 else 167 { 168 return 1; 169 } 170 } 171 else if (value2 == null) 172 { 173 return -1; 174 } 175 176 177 // Use the ordering matching rule if one is provided. Otherwise, 178 // fall back on the default ordering rule for the attribute type. 179 if (orderingRule == null) 180 { 181 try 182 { 183 OrderingMatchingRule rule = 184 attributeType.getOrderingMatchingRule(); 185 if (rule == null) 186 { 187 return 0; 188 } 189 190 if (ascending) 191 { 192 return rule.compareValues(value1.getNormalizedValue(), 193 value2.getNormalizedValue()); 194 } 195 else 196 { 197 return rule.compareValues(value2.getNormalizedValue(), 198 value1.getNormalizedValue()); 199 } 200 } 201 catch (Exception e) 202 { 203 if (debugEnabled()) 204 { 205 TRACER.debugCaught(DebugLogLevel.ERROR, e); 206 } 207 208 return 0; 209 } 210 } 211 else 212 { 213 try 214 { 215 if (ascending) 216 { 217 return orderingRule.compareValues( 218 orderingRule.normalizeValue(value1.getValue()), 219 orderingRule.normalizeValue(value2.getValue())); 220 } 221 else 222 { 223 return orderingRule.compareValues( 224 orderingRule.normalizeValue(value2.getValue()), 225 orderingRule.normalizeValue(value1.getValue())); 226 } 227 } 228 catch (Exception e) 229 { 230 if (debugEnabled()) 231 { 232 TRACER.debugCaught(DebugLogLevel.ERROR, e); 233 } 234 235 return 0; 236 } 237 } 238 } 239 240 241 242 /** 243 * Retrieves a string representation of this sort key. 244 * 245 * @return A string representation of this sort key. 246 */ 247 public String toString() 248 { 249 StringBuilder buffer = new StringBuilder(); 250 toString(buffer); 251 return buffer.toString(); 252 } 253 254 255 256 /** 257 * Appends a string representation of this sort key to the 258 * provided buffer. 259 * 260 * @param buffer The buffer to which the information should be 261 * appended. 262 */ 263 public void toString(StringBuilder buffer) 264 { 265 buffer.append("SortKey("); 266 if (ascending) 267 { 268 buffer.append("+"); 269 } 270 else 271 { 272 buffer.append("-"); 273 } 274 buffer.append(attributeType.getNameOrOID()); 275 276 if (orderingRule != null) 277 { 278 buffer.append(":"); 279 buffer.append(orderingRule.getNameOrOID()); 280 } 281 282 buffer.append(")"); 283 } 284 285 /** 286 * Retrieves the hash code for this sort key. 287 * 288 * @return The hash code for this sort key. 289 */ 290 public int hashCode() 291 { 292 int hashCode = 0; 293 294 if(ascending) 295 { 296 hashCode += 1; 297 } 298 299 hashCode += attributeType.hashCode(); 300 301 if(orderingRule != null) 302 { 303 hashCode += orderingRule.hashCode(); 304 } 305 306 return hashCode; 307 } 308 309 /** 310 * Indicates whether this sort key is equal to the provided 311 * object. 312 * 313 * @param o The object for which to make the determination. 314 * 315 * @return <CODE>true</CODE> if the provide object is equal to this 316 * sort key, or <CODE>false</CODE> if it is not. 317 */ 318 public boolean equals(Object o) 319 { 320 if(o == null) 321 { 322 return false; 323 } 324 325 if (o == this) 326 { 327 return true; 328 } 329 330 if (! (o instanceof SortKey)) 331 { 332 return false; 333 } 334 335 SortKey s = (SortKey) o; 336 337 if(ascending != s.ascending) 338 { 339 return false; 340 } 341 342 if(!attributeType.equals(s.attributeType)) 343 { 344 return false; 345 } 346 347 if(orderingRule != null) 348 { 349 if(s.orderingRule != null) 350 { 351 if(!orderingRule.equals(s.orderingRule)) 352 { 353 return false; 354 } 355 } 356 else if(!orderingRule.equals( 357 s.attributeType.getOrderingMatchingRule())) 358 { 359 return false; 360 } 361 } 362 else if(s.orderingRule != null) 363 { 364 if(!attributeType.getOrderingMatchingRule().equals( 365 s.orderingRule)) 366 { 367 return false; 368 } 369 } 370 371 return true; 372 } 373 } 374