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