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 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.schema; 028 import org.opends.messages.Message; 029 030 031 032 import org.opends.server.admin.std.server.OrderingMatchingRuleCfg; 033 import org.opends.server.api.OrderingMatchingRule; 034 import org.opends.server.config.ConfigException; 035 import org.opends.server.core.DirectoryServer; 036 import org.opends.server.protocols.asn1.ASN1OctetString; 037 import org.opends.server.types.ByteString; 038 import org.opends.server.types.DirectoryException; 039 import org.opends.server.types.InitializationException; 040 import org.opends.server.types.ResultCode; 041 042 import static org.opends.server.loggers.ErrorLogger.*; 043 import static org.opends.messages.SchemaMessages.*; 044 import static org.opends.server.schema.SchemaConstants.*; 045 046 047 /** 048 * This class defines the integerOrderingMatch matching rule defined in X.520 049 * and referenced in RFC 4519. 050 */ 051 public class IntegerOrderingMatchingRule 052 extends OrderingMatchingRule 053 { 054 /** 055 * The serial version identifier required to satisfy the compiler because this 056 * class implements the <CODE>java.io.Serializable</CODE> interface. This 057 * value was generated using the <CODE>serialver</CODE> command-line utility 058 * included with the Java SDK. 059 */ 060 private static final long serialVersionUID = 6654300545706161754L; 061 062 063 064 /** 065 * Creates a new instance of this integerOrderingMatch matching rule. 066 */ 067 public IntegerOrderingMatchingRule() 068 { 069 super(); 070 } 071 072 073 074 /** 075 * {@inheritDoc} 076 */ 077 public void initializeMatchingRule(OrderingMatchingRuleCfg configuration) 078 throws ConfigException, InitializationException 079 { 080 // No initialization is required. 081 } 082 083 084 085 /** 086 * Retrieves the common name for this matching rule. 087 * 088 * @return The common name for this matching rule, or <CODE>null</CODE> if 089 * it does not have a name. 090 */ 091 public String getName() 092 { 093 return OMR_INTEGER_NAME; 094 } 095 096 097 098 /** 099 * Retrieves the OID for this matching rule. 100 * 101 * @return The OID for this matching rule. 102 */ 103 public String getOID() 104 { 105 return OMR_INTEGER_OID; 106 } 107 108 109 110 /** 111 * Retrieves the description for this matching rule. 112 * 113 * @return The description for this matching rule, or <CODE>null</CODE> if 114 * there is none. 115 */ 116 public String getDescription() 117 { 118 // There is no standard description for this matching rule. 119 return null; 120 } 121 122 123 124 /** 125 * Retrieves the OID of the syntax with which this matching rule is 126 * associated. 127 * 128 * @return The OID of the syntax with which this matching rule is associated. 129 */ 130 public String getSyntaxOID() 131 { 132 return SYNTAX_INTEGER_OID; 133 } 134 135 136 137 /** 138 * Retrieves the normalized form of the provided value, which is best suited 139 * for efficiently performing matching operations on that value. 140 * 141 * @param value The value to be normalized. 142 * 143 * @return The normalized version of the provided value. 144 * 145 * @throws DirectoryException If the provided value is invalid according to 146 * the associated attribute syntax. 147 */ 148 public ByteString normalizeValue(ByteString value) 149 throws DirectoryException 150 { 151 byte[] valueBytes = value.value(); 152 153 int length = valueBytes.length; 154 StringBuilder buffer = new StringBuilder(length); 155 156 boolean logged = false; 157 for (int i=0; i < length; i++) 158 { 159 switch (valueBytes[i]) 160 { 161 case '0': 162 switch (buffer.length()) 163 { 164 case 0: 165 // This is only OK if the value is zero 166 if (i == (length-1)) 167 { 168 buffer.append("0"); 169 } 170 else 171 { 172 173 Message message = WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO.get( 174 value.stringValue()); 175 176 switch (DirectoryServer.getSyntaxEnforcementPolicy()) 177 { 178 case REJECT: 179 throw new DirectoryException( 180 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 181 case WARN: 182 if (! logged) 183 { 184 logged = true; 185 logError(message); 186 } 187 break; 188 } 189 } 190 break; 191 case 1: 192 // This is OK as long as the first character isn't a dash. 193 if (buffer.charAt(0) == '-') 194 { 195 196 Message message = WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO.get( 197 value.stringValue()); 198 199 switch (DirectoryServer.getSyntaxEnforcementPolicy()) 200 { 201 case REJECT: 202 throw new DirectoryException( 203 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 204 case WARN: 205 if (! logged) 206 { 207 logged = true; 208 logError( 209 message); 210 } 211 break; 212 } 213 } 214 else 215 { 216 buffer.append("0"); 217 } 218 break; 219 default: 220 // This is always fine. 221 buffer.append("0"); 222 break; 223 } 224 break; 225 case '1': 226 buffer.append('1'); 227 break; 228 case '2': 229 buffer.append('2'); 230 break; 231 case '3': 232 buffer.append('3'); 233 break; 234 case '4': 235 buffer.append('4'); 236 break; 237 case '5': 238 buffer.append('5'); 239 break; 240 case '6': 241 buffer.append('6'); 242 break; 243 case '7': 244 buffer.append('7'); 245 break; 246 case '8': 247 buffer.append('8'); 248 break; 249 case '9': 250 buffer.append('9'); 251 break; 252 case '-': 253 // This is only OK if the buffer is empty. 254 if (buffer.length() == 0) 255 { 256 buffer.append("-"); 257 } 258 else 259 { 260 Message message = WARN_ATTR_SYNTAX_INTEGER_MISPLACED_DASH.get( 261 value.stringValue()); 262 263 switch (DirectoryServer.getSyntaxEnforcementPolicy()) 264 { 265 case REJECT: 266 throw new DirectoryException( 267 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 268 case WARN: 269 if (! logged) 270 { 271 logged = true; 272 logError( 273 message); 274 } 275 break; 276 } 277 } 278 break; 279 default: 280 Message message = WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER.get( 281 value.stringValue(), 282 ((char) valueBytes[i]), i); 283 switch (DirectoryServer.getSyntaxEnforcementPolicy()) 284 { 285 case REJECT: 286 throw new DirectoryException( 287 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); 288 case WARN: 289 if (! logged) 290 { 291 logged = true; 292 logError( 293 message); 294 } 295 break; 296 } 297 } 298 } 299 300 if (buffer.length() == 0) 301 { 302 Message message = WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE.get( 303 value.stringValue()); 304 305 switch (DirectoryServer.getSyntaxEnforcementPolicy()) 306 { 307 case REJECT: 308 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 309 message); 310 311 case WARN: 312 if (! logged) 313 { 314 logged = true; 315 logError( 316 message); 317 } 318 319 buffer.append("0"); 320 break; 321 322 default: 323 buffer.append("0"); 324 break; 325 } 326 } 327 else if ((buffer.length() == 1) && (buffer.charAt(0) == '-')) 328 { 329 Message message = WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE.get( 330 value.stringValue()); 331 332 switch (DirectoryServer.getSyntaxEnforcementPolicy()) 333 { 334 case REJECT: 335 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 336 message); 337 338 case WARN: 339 if (! logged) 340 { 341 logged = true; 342 logError( 343 message); 344 } 345 346 buffer.setCharAt(0, '0'); 347 break; 348 349 default: 350 buffer.setCharAt(0, '0'); 351 break; 352 } 353 } 354 355 return new ASN1OctetString(buffer.toString()); 356 } 357 358 359 360 /** 361 * Compares the first value to the second and returns a value that indicates 362 * their relative order. 363 * 364 * @param value1 The normalized form of the first value to compare. 365 * @param value2 The normalized form of the second value to compare. 366 * 367 * @return A negative integer if <CODE>value1</CODE> should come before 368 * <CODE>value2</CODE> in ascending order, a positive integer if 369 * <CODE>value1</CODE> should come after <CODE>value2</CODE> in 370 * ascending order, or zero if there is no difference between the 371 * values with regard to ordering. 372 */ 373 public int compareValues(ByteString value1, ByteString value2) 374 { 375 return compare(value1.value(), value2.value()); 376 } 377 378 379 380 /** 381 * Compares the contents of the provided byte arrays to determine their 382 * relative order. 383 * 384 * @param b1 The first byte array to use in the comparison. 385 * @param b2 The second byte array to use in the comparison. 386 * 387 * @return A negative integer if <CODE>b1</CODE> should come before 388 * <CODE>b2</CODE> in ascending order, a positive integer if 389 * <CODE>b1</CODE> should come after <CODE>b2</CODE> in ascending 390 * order, or zero if there is no difference between the values with 391 * regard to ordering. 392 */ 393 public int compare(byte[] b1, byte[] b2) 394 { 395 int b1Length = b1.length; 396 int b2Length = b2.length; 397 398 399 // A length of zero should be considered a value of zero. 400 if (b1Length == 0) 401 { 402 if (b2Length == 0) 403 { 404 return 0; 405 } 406 else if (b2[0] == '-') 407 { 408 return 1; 409 } 410 else 411 { 412 return -1; 413 } 414 } 415 else if (b2Length == 0) 416 { 417 if (b1[0] == '-') 418 { 419 return -1; 420 } 421 else 422 { 423 return 1; 424 } 425 } 426 427 428 // Starting with a dash should be an indicator of a negative value. 429 if (b1[0] == '-') 430 { 431 if (b2[0] == '-') 432 { 433 if (b1Length > b2Length) 434 { 435 return -1; 436 } 437 else if (b2Length > b1Length) 438 { 439 return 1; 440 } 441 else 442 { 443 for (int i=1; i < b1Length; i++) 444 { 445 if (b1[i] > b2[i]) 446 { 447 return -1; 448 } 449 else if (b1[i] < b2[i]) 450 { 451 return 1; 452 } 453 } 454 455 return 0; 456 } 457 } 458 else 459 { 460 return -1; 461 } 462 } 463 else if (b2[0] == '-') 464 { 465 return 1; 466 } 467 468 469 // They are both positive, so see which one's bigger. 470 if (b1Length > b2Length) 471 { 472 return 1; 473 } 474 else if (b2Length > b1Length) 475 { 476 return -1; 477 } 478 else 479 { 480 for (int i=0; i < b1Length; i++) 481 { 482 if (b1[i] > b2[i]) 483 { 484 return 1; 485 } 486 else if (b1[i] < b2[i]) 487 { 488 return -1; 489 } 490 } 491 492 return 0; 493 } 494 } 495 } 496