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