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
029
030
031 import java.text.SimpleDateFormat;
032 import java.util.Date;
033 import java.util.TimeZone;
034
035 import org.opends.messages.Message;
036 import org.opends.messages.MessageBuilder;
037 import org.opends.server.admin.std.server.AttributeSyntaxCfg;
038 import org.opends.server.api.ApproximateMatchingRule;
039 import org.opends.server.api.AttributeSyntax;
040 import org.opends.server.api.EqualityMatchingRule;
041 import org.opends.server.api.OrderingMatchingRule;
042 import org.opends.server.api.SubstringMatchingRule;
043 import org.opends.server.config.ConfigException;
044 import org.opends.server.core.DirectoryServer;
045 import org.opends.server.loggers.debug.DebugTracer;
046 import org.opends.server.protocols.asn1.ASN1OctetString;
047 import org.opends.server.types.AttributeValue;
048 import org.opends.server.types.ByteString;
049 import org.opends.server.types.DebugLogLevel;
050 import org.opends.server.types.DirectoryException;
051 import org.opends.server.types.ResultCode;
052
053 import static org.opends.messages.SchemaMessages.*;
054 import static org.opends.server.loggers.debug.DebugLogger.*;
055 import static org.opends.server.loggers.ErrorLogger.*;
056 import static org.opends.server.schema.SchemaConstants.*;
057 import static org.opends.server.util.ServerConstants.*;
058
059
060
061 /**
062 * This class implements the UTC time attribute syntax. This is very similar to
063 * the generalized time syntax (and actually has been deprecated in favor of
064 * that), but requires that the minute be provided and does not allow for
065 * sub-second times. All matching will be performed using the generalized time
066 * matching rules, and equality, ordering, and substring matching will be
067 * allowed.
068 */
069 public class UTCTimeSyntax
070 extends AttributeSyntax<AttributeSyntaxCfg>
071 {
072 /**
073 * The tracer object for the debug logger.
074 */
075 private static final DebugTracer TRACER = getTracer();
076
077
078
079 /**
080 * The lock that will be used to provide threadsafe access to the date
081 * formatter.
082 */
083 private static Object dateFormatLock;
084
085
086
087 /**
088 * The date formatter that will be used to convert dates into UTC time values.
089 * Note that all interaction with it must be synchronized.
090 */
091 private static SimpleDateFormat dateFormat;
092
093
094
095 // The default equality matching rule for this syntax.
096 private EqualityMatchingRule defaultEqualityMatchingRule;
097
098 // The default ordering matching rule for this syntax.
099 private OrderingMatchingRule defaultOrderingMatchingRule;
100
101 // The default substring matching rule for this syntax.
102 private SubstringMatchingRule defaultSubstringMatchingRule;
103
104
105
106 /*
107 * Create the date formatter that will be used to construct and parse
108 * normalized UTC time values.
109 */
110 static
111 {
112 dateFormat = new SimpleDateFormat(DATE_FORMAT_UTC_TIME);
113 dateFormat.setLenient(false);
114 dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
115
116 dateFormatLock = new Object();
117 }
118
119
120
121 /**
122 * Creates a new instance of this syntax. Note that the only thing that
123 * should be done here is to invoke the default constructor for the
124 * superclass. All initialization should be performed in the
125 * <CODE>initializeSyntax</CODE> method.
126 */
127 public UTCTimeSyntax()
128 {
129 super();
130 }
131
132
133
134 /**
135 * {@inheritDoc}
136 */
137 public void initializeSyntax(AttributeSyntaxCfg configuration)
138 throws ConfigException
139 {
140 defaultEqualityMatchingRule =
141 DirectoryServer.getEqualityMatchingRule(EMR_GENERALIZED_TIME_OID);
142 if (defaultEqualityMatchingRule == null)
143 {
144 logError(ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE.get(
145 EMR_GENERALIZED_TIME_OID, SYNTAX_UTC_TIME_NAME));
146 }
147
148 defaultOrderingMatchingRule =
149 DirectoryServer.getOrderingMatchingRule(OMR_GENERALIZED_TIME_OID);
150 if (defaultOrderingMatchingRule == null)
151 {
152 logError(ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE.get(
153 OMR_GENERALIZED_TIME_OID, SYNTAX_UTC_TIME_NAME));
154 }
155
156 defaultSubstringMatchingRule =
157 DirectoryServer.getSubstringMatchingRule(SMR_CASE_IGNORE_OID);
158 if (defaultSubstringMatchingRule == null)
159 {
160 logError(ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE.get(
161 SMR_CASE_IGNORE_OID, SYNTAX_UTC_TIME_NAME));
162 }
163 }
164
165
166
167 /**
168 * Retrieves the common name for this attribute syntax.
169 *
170 * @return The common name for this attribute syntax.
171 */
172 public String getSyntaxName()
173 {
174 return SYNTAX_UTC_TIME_NAME;
175 }
176
177
178
179 /**
180 * Retrieves the OID for this attribute syntax.
181 *
182 * @return The OID for this attribute syntax.
183 */
184 public String getOID()
185 {
186 return SYNTAX_UTC_TIME_OID;
187 }
188
189
190
191 /**
192 * Retrieves a description for this attribute syntax.
193 *
194 * @return A description for this attribute syntax.
195 */
196 public String getDescription()
197 {
198 return SYNTAX_UTC_TIME_DESCRIPTION;
199 }
200
201
202
203 /**
204 * Retrieves the default equality matching rule that will be used for
205 * attributes with this syntax.
206 *
207 * @return The default equality matching rule that will be used for
208 * attributes with this syntax, or <CODE>null</CODE> if equality
209 * matches will not be allowed for this type by default.
210 */
211 public EqualityMatchingRule getEqualityMatchingRule()
212 {
213 return defaultEqualityMatchingRule;
214 }
215
216
217
218 /**
219 * Retrieves the default ordering matching rule that will be used for
220 * attributes with this syntax.
221 *
222 * @return The default ordering matching rule that will be used for
223 * attributes with this syntax, or <CODE>null</CODE> if ordering
224 * matches will not be allowed for this type by default.
225 */
226 public OrderingMatchingRule getOrderingMatchingRule()
227 {
228 return defaultOrderingMatchingRule;
229 }
230
231
232
233 /**
234 * Retrieves the default substring matching rule that will be used for
235 * attributes with this syntax.
236 *
237 * @return The default substring matching rule that will be used for
238 * attributes with this syntax, or <CODE>null</CODE> if substring
239 * matches will not be allowed for this type by default.
240 */
241 public SubstringMatchingRule getSubstringMatchingRule()
242 {
243 return defaultSubstringMatchingRule;
244 }
245
246
247
248 /**
249 * Retrieves the default approximate matching rule that will be used for
250 * attributes with this syntax.
251 *
252 * @return The default approximate matching rule that will be used for
253 * attributes with this syntax, or <CODE>null</CODE> if approximate
254 * matches will not be allowed for this type by default.
255 */
256 public ApproximateMatchingRule getApproximateMatchingRule()
257 {
258 // Approximate matching will not be allowed by default.
259 return null;
260 }
261
262
263
264 /**
265 * Indicates whether the provided value is acceptable for use in an attribute
266 * with this syntax. If it is not, then the reason may be appended to the
267 * provided buffer.
268 *
269 * @param value The value for which to make the determination.
270 * @param invalidReason The buffer to which the invalid reason should be
271 * appended.
272 *
273 * @return <CODE>true</CODE> if the provided value is acceptable for use with
274 * this syntax, or <CODE>false</CODE> if not.
275 */
276 public boolean valueIsAcceptable(ByteString value,
277 MessageBuilder invalidReason)
278 {
279 // Get the value as a string and verify that it is at least long enough for
280 // "YYYYMMDDhhmmZ", which is the shortest allowed value.
281 String valueString = value.stringValue().toUpperCase();
282 int length = valueString.length();
283 if (length < 11)
284 {
285 Message message = ERR_ATTR_SYNTAX_UTC_TIME_TOO_SHORT.get(valueString);
286 invalidReason.append(message);
287 return false;
288 }
289
290
291 // The first two characters are the year, and they must be numeric digits
292 // between 0 and 9.
293 for (int i=0; i < 2; i++)
294 {
295 switch (valueString.charAt(i))
296 {
297 case '0':
298 case '1':
299 case '2':
300 case '3':
301 case '4':
302 case '5':
303 case '6':
304 case '7':
305 case '8':
306 case '9':
307 // These are all fine.
308 break;
309 default:
310 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_YEAR.get(
311 valueString, String.valueOf(valueString.charAt(i)));
312 invalidReason.append(message);
313 return false;
314 }
315 }
316
317
318 // The next two characters are the month, and they must form the string
319 // representation of an integer between 01 and 12.
320 char m1 = valueString.charAt(2);
321 char m2 = valueString.charAt(3);
322 switch (m1)
323 {
324 case '0':
325 // m2 must be a digit between 1 and 9.
326 switch (m2)
327 {
328 case '1':
329 case '2':
330 case '3':
331 case '4':
332 case '5':
333 case '6':
334 case '7':
335 case '8':
336 case '9':
337 // These are all fine.
338 break;
339 default:
340 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH.get(
341 valueString, valueString.substring(2, 4));
342 invalidReason.append(message);
343 return false;
344 }
345 break;
346 case '1':
347 // m2 must be a digit between 0 and 2.
348 switch (m2)
349 {
350 case '0':
351 case '1':
352 case '2':
353 // These are all fine.
354 break;
355 default:
356 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH.get(
357 valueString, valueString.substring(2, 4));
358 invalidReason.append(message);
359 return false;
360 }
361 break;
362 default:
363 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH.get(
364 valueString, valueString.substring(2, 4));
365 invalidReason.append(message);
366 return false;
367 }
368
369
370 // The next two characters should be the day of the month, and they must
371 // form the string representation of an integer between 01 and 31.
372 // This doesn't do any validation against the year or month, so it will
373 // allow dates like April 31, or February 29 in a non-leap year, but we'll
374 // let those slide.
375 char d1 = valueString.charAt(4);
376 char d2 = valueString.charAt(5);
377 switch (d1)
378 {
379 case '0':
380 // d2 must be a digit between 1 and 9.
381 switch (d2)
382 {
383 case '1':
384 case '2':
385 case '3':
386 case '4':
387 case '5':
388 case '6':
389 case '7':
390 case '8':
391 case '9':
392 // These are all fine.
393 break;
394 default:
395 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY.get(
396 valueString, valueString.substring(4, 6));
397 invalidReason.append(message);
398 return false;
399 }
400 break;
401 case '1':
402 // Treated the same as '2'.
403 case '2':
404 // d2 must be a digit between 0 and 9.
405 switch (d2)
406 {
407 case '0':
408 case '1':
409 case '2':
410 case '3':
411 case '4':
412 case '5':
413 case '6':
414 case '7':
415 case '8':
416 case '9':
417 // These are all fine.
418 break;
419 default:
420 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY.get(
421 valueString, valueString.substring(4, 6));
422 invalidReason.append(message);
423 return false;
424 }
425 break;
426 case '3':
427 // d2 must be either 0 or 1.
428 switch (d2)
429 {
430 case '0':
431 case '1':
432 // These are all fine.
433 break;
434 default:
435 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY.get(
436 valueString, valueString.substring(4, 6));
437 invalidReason.append(message);
438 return false;
439 }
440 break;
441 default:
442 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY.get(valueString,
443 valueString.substring(4, 6));
444 invalidReason.append(message);
445 return false;
446 }
447
448
449 // The next two characters must be the hour, and they must form the string
450 // representation of an integer between 00 and 23.
451 char h1 = valueString.charAt(6);
452 char h2 = valueString.charAt(7);
453 switch (h1)
454 {
455 case '0':
456 // This is treated the same as '1'.
457 case '1':
458 switch (h2)
459 {
460 case '0':
461 case '1':
462 case '2':
463 case '3':
464 case '4':
465 case '5':
466 case '6':
467 case '7':
468 case '8':
469 case '9':
470 // These are all fine.
471 break;
472 default:
473 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR.get(
474 valueString, valueString.substring(6, 8));
475 invalidReason.append(message);
476 return false;
477 }
478 break;
479 case '2':
480 // This must be a digit between 0 and 3.
481 switch (h2)
482 {
483 case '0':
484 case '1':
485 case '2':
486 case '3':
487 // These are all fine.
488 break;
489 default:
490 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR.get(
491 valueString, valueString.substring(6, 8));
492 invalidReason.append(message);
493 return false;
494 }
495 break;
496 default:
497 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR.get(valueString,
498 valueString.substring(6, 8));
499 invalidReason.append(message);
500 return false;
501 }
502
503
504 // Next, there should be two digits comprising an integer between 00 and 59
505 // for the minute.
506 m1 = valueString.charAt(8);
507 switch (m1)
508 {
509 case '0':
510 case '1':
511 case '2':
512 case '3':
513 case '4':
514 case '5':
515 // There must be at least two more characters, and the next one must
516 // be a digit between 0 and 9.
517 if (length < 11)
518 {
519 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR.get(
520 valueString, String.valueOf(m1), 8);
521 invalidReason.append(message);
522 return false;
523 }
524
525 switch (valueString.charAt(9))
526 {
527 case '0':
528 case '1':
529 case '2':
530 case '3':
531 case '4':
532 case '5':
533 case '6':
534 case '7':
535 case '8':
536 case '9':
537 // These are all fine.
538 break;
539 default:
540 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MINUTE.get(
541 valueString, valueString.substring(8, 10));
542 invalidReason.append(message);
543 return false;
544 }
545
546 break;
547
548 default:
549 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR.get(
550 valueString, String.valueOf(m1), 8);
551 invalidReason.append(message);
552 return false;
553 }
554
555
556 // Next, there should be either two digits comprising an integer between 00
557 // and 60 (for the second, including a possible leap second), a letter 'Z'
558 // (for the UTC specifier), or a plus or minus sign followed by four digits
559 // (for the UTC offset).
560 char s1 = valueString.charAt(10);
561 switch (s1)
562 {
563 case '0':
564 case '1':
565 case '2':
566 case '3':
567 case '4':
568 case '5':
569 // There must be at least two more characters, and the next one must
570 // be a digit between 0 and 9.
571 if (length < 13)
572 {
573 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR.get(
574 valueString, String.valueOf(s1), 10);
575 invalidReason.append(message);
576 return false;
577 }
578
579 switch (valueString.charAt(11))
580 {
581 case '0':
582 case '1':
583 case '2':
584 case '3':
585 case '4':
586 case '5':
587 case '6':
588 case '7':
589 case '8':
590 case '9':
591 // These are all fine.
592 break;
593 default:
594 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_SECOND.get(
595 valueString, valueString.substring(10, 12));
596 invalidReason.append(message);
597 return false;
598 }
599
600 break;
601 case '6':
602 // There must be at least two more characters and the next one must be
603 // a 0.
604 if (length < 13)
605 {
606
607 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR.get(
608 valueString, String.valueOf(s1), 10);
609 invalidReason.append(message);
610 return false;
611 }
612
613 if (valueString.charAt(11) != '0')
614 {
615 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_SECOND.get(
616 valueString, valueString.substring(10, 12));
617 invalidReason.append(message);
618 return false;
619 }
620
621 break;
622 case 'Z':
623 // This is fine only if we are at the end of the value.
624 if (length == 11)
625 {
626 return true;
627 }
628 else
629 {
630 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR.get(
631 valueString, String.valueOf(s1), 10);
632 invalidReason.append(message);
633 return false;
634 }
635
636 case '+':
637 case '-':
638 // These are fine only if there are exactly four more digits that
639 // specify a valid offset.
640 if (length == 15)
641 {
642 return hasValidOffset(valueString, 11, invalidReason);
643 }
644 else
645 {
646 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR.get(
647 valueString, String.valueOf(s1), 10);
648 invalidReason.append(message);
649 return false;
650 }
651
652 default:
653 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR.get(
654 valueString, String.valueOf(s1), 10);
655 invalidReason.append(message);
656 return false;
657 }
658
659
660 // The last element should be either a letter 'Z' (for the UTC specifier),
661 // or a plus or minus sign followed by four digits (for the UTC offset).
662 switch (valueString.charAt(12))
663 {
664 case 'Z':
665 // This is fine only if we are at the end of the value.
666 if (length == 13)
667 {
668 return true;
669 }
670 else
671 {
672 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR.get(
673 valueString, String.valueOf(valueString.charAt(12)), 12);
674 invalidReason.append(message);
675 return false;
676 }
677
678 case '+':
679 case '-':
680 // These are fine only if there are four or two more digits that
681 // specify a valid offset.
682 if ((length == 17) || (length == 15))
683 {
684 return hasValidOffset(valueString, 13, invalidReason);
685 }
686 else
687 {
688 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR.get(
689 valueString, String.valueOf(valueString.charAt(12)), 12);
690 invalidReason.append(message);
691 return false;
692 }
693
694 default:
695 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR.get(
696 valueString, String.valueOf(valueString.charAt(12)), 12);
697 invalidReason.append(message);
698 return false;
699 }
700 }
701
702
703
704 /**
705 * Indicates whether the provided string contains a valid set of two or four
706 * UTC offset digits. The provided string must have either two or four
707 * characters from the provided start position to the end of the value.
708 *
709 * @param value The whole value, including the offset.
710 * @param startPos The position of the first character that is
711 * contained in the offset.
712 * @param invalidReason The buffer to which the invalid reason may be
713 * appended if the string does not contain a valid set
714 * of UTC offset digits.
715 *
716 * @return <CODE>true</CODE> if the provided offset string is valid, or
717 * <CODE>false</CODE> if it is not.
718 */
719 private boolean hasValidOffset(String value, int startPos,
720 MessageBuilder invalidReason)
721 {
722 int offsetLength = value.length() - startPos;
723 if (offsetLength < 2)
724 {
725 Message message = ERR_ATTR_SYNTAX_UTC_TIME_TOO_SHORT.get(value);
726 invalidReason.append(message);
727 return false;
728 }
729
730 // The first two characters must be an integer between 00 and 23.
731 switch (value.charAt(startPos))
732 {
733 case '0':
734 case '1':
735 switch (value.charAt(startPos+1))
736 {
737 case '0':
738 case '1':
739 case '2':
740 case '3':
741 case '4':
742 case '5':
743 case '6':
744 case '7':
745 case '8':
746 case '9':
747 // These are all fine.
748 break;
749 default:
750 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET.get(value,
751 value.substring(startPos,
752 startPos+offsetLength));
753 invalidReason.append(message);
754 return false;
755 }
756 break;
757 case '2':
758 switch (value.charAt(startPos+1))
759 {
760 case '0':
761 case '1':
762 case '2':
763 case '3':
764 // These are all fine.
765 break;
766 default:
767 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET.get(value,
768 value.substring(startPos,
769 startPos+offsetLength));
770 invalidReason.append(message);
771 return false;
772 }
773 break;
774 default:
775 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET.get(value,
776 value.substring(startPos,
777 startPos+offsetLength));
778 invalidReason.append(message);
779 return false;
780 }
781
782
783 // If there are two more characters, then they must be an integer between
784 // 00 and 59.
785 if (offsetLength == 4)
786 {
787 switch (value.charAt(startPos+2))
788 {
789 case '0':
790 case '1':
791 case '2':
792 case '3':
793 case '4':
794 case '5':
795 switch (value.charAt(startPos+3))
796 {
797 case '0':
798 case '1':
799 case '2':
800 case '3':
801 case '4':
802 case '5':
803 case '6':
804 case '7':
805 case '8':
806 case '9':
807 // These are all fine.
808 break;
809 default:
810 Message message =
811 ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET.get(
812 value,value.substring(startPos,
813 startPos+offsetLength));
814 invalidReason.append(message);
815 return false;
816 }
817 break;
818 default:
819 Message message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET.get(value,
820 value.substring(startPos,
821 startPos+offsetLength));
822 invalidReason.append(message);
823 return false;
824 }
825 }
826
827 return true;
828 }
829
830
831
832 /**
833 * Retrieves an attribute value containing a UTC time representation of the
834 * provided date.
835 *
836 * @param d The date for which to retrieve the UTC time value.
837 *
838 * @return The attribute value created from the date.
839 */
840 public static AttributeValue createUTCTimeValue(Date d)
841 {
842 String valueString;
843
844 synchronized (dateFormatLock)
845 {
846 valueString = dateFormat.format(d);
847 }
848
849 return new AttributeValue(new ASN1OctetString(valueString),
850 new ASN1OctetString(valueString));
851 }
852
853
854
855 /**
856 * Decodes the provided normalized value as a UTC time value and
857 * retrieves a Java <CODE>Date</CODE> object containing its representation.
858 *
859 * @param normalizedValue The normalized UTC time value to decode to a
860 * Java <CODE>Date</CODE>.
861 *
862 * @return The Java <CODE>Date</CODE> created from the provided UTC time
863 * value.
864 *
865 * @throws DirectoryException If the provided value cannot be parsed as a
866 * valid UTC time string.
867 */
868 public static Date decodeUTCTimeValue(ByteString normalizedValue)
869 throws DirectoryException
870 {
871 String valueString = normalizedValue.stringValue();
872 try
873 {
874 synchronized (dateFormatLock)
875 {
876 return dateFormat.parse(valueString);
877 }
878 }
879 catch (Exception e)
880 {
881 if (debugEnabled())
882 {
883 TRACER.debugCaught(DebugLogLevel.ERROR, e);
884 }
885
886 Message message = ERR_ATTR_SYNTAX_UTC_TIME_CANNOT_PARSE.get(
887 valueString, String.valueOf(e));
888 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
889 message, e);
890 }
891 }
892 }
893