From 03818b13c1f667d1c092c04004c248993dcdca9c Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Wed, 18 Apr 2007 22:54:37 +0000
Subject: [PATCH] Re-implement the way that the server handles the generalized time syntax to make it more standards compliant and fix problems reported with its behavior.
---
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRuleTest.java | 33
opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java | 707 -----------
opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeSyntax.java | 1956 +++++++++++++++++++++------------
opendj-sdk/opends/src/server/org/opends/server/messages/SchemaMessages.java | 58 +
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRuleTest.java | 8
opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRule.java | 667 -----------
6 files changed, 1,373 insertions(+), 2,056 deletions(-)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/SchemaMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/SchemaMessages.java
index 308a94b..942ee92 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/SchemaMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/SchemaMessages.java
@@ -3074,6 +3074,48 @@
/**
+ * The message ID for the message that will be used if a generalized time
+ * value contains an illegal character in the fraction component. This takes
+ * two arguments, which are the value string and the illegal character.
+ */
+ public static final int
+ MSGID_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR =
+ CATEGORY_MASK_SCHEMA | SEVERITY_MASK_SEVERE_WARNING | 275;
+
+
+
+ /**
+ * The message ID for the message that will be used if a generalized time
+ * value contains an empty fractional component. This takes a single
+ * argument, which is the value string.
+ */
+ public static final int MSGID_ATTR_SYNTAX_GENERALIZED_TIME_EMPTY_FRACTION =
+ CATEGORY_MASK_SCHEMA | SEVERITY_MASK_SEVERE_WARNING | 276;
+
+
+
+ /**
+ * The message ID for the message that will be used if a generalized time
+ * value does not contain any time zone information. This takes a single
+ * argument, which is the value string.
+ */
+ public static final int MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NO_TIME_ZONE_INFO =
+ CATEGORY_MASK_SCHEMA | SEVERITY_MASK_SEVERE_WARNING | 277;
+
+
+
+ /**
+ * The message ID for the message that will be used if a generalized time
+ * value represents an invalid date or time (e.g., September 31). This takes
+ * two arguments, which are the value string and a string representation of
+ * the exception that was caught.
+ */
+ public static final int MSGID_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME =
+ CATEGORY_MASK_SCHEMA | SEVERITY_MASK_SEVERE_WARNING | 278;
+
+
+
+ /**
* Associates a set of generic messages with the message IDs defined in this
* class.
*/
@@ -3181,6 +3223,22 @@
registerMessage(MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE,
"An unexpected error occurred while trying to normalize " +
"value %s as a generalized time value: %s.");
+ registerMessage(MSGID_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR,
+ "The provided value %s is not a valid generalized time " +
+ "value because it contains illegal character %s in the " +
+ "fraction component.");
+ registerMessage(MSGID_ATTR_SYNTAX_GENERALIZED_TIME_EMPTY_FRACTION,
+ "The provided value %s is not a valid generalized time " +
+ "value because it does not contain at least one digit " +
+ "after the period to use as the fractional component.");
+ registerMessage(MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NO_TIME_ZONE_INFO,
+ "The provided value %s is not a valid generalized time " +
+ "value because it does not end with 'Z' or a time zone " +
+ "offset.");
+ registerMessage(MSGID_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME,
+ "The provided value %s is not a valid generalized time " +
+ "value because it represents an invalid time (e.g., a " +
+ "date that does not exist): %s.");
registerMessage(MSGID_ATTR_SYNTAX_DN_INVALID,
diff --git a/opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRule.java b/opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRule.java
index 6fbb6f8..be01196 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRule.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRule.java
@@ -29,9 +29,6 @@
import java.text.SimpleDateFormat;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.concurrent.locks.ReentrantLock;
@@ -40,13 +37,11 @@
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AcceptRejectWarn;
import org.opends.server.types.ByteString;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.ErrorLogCategory;
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
@@ -67,9 +62,6 @@
public class GeneralizedTimeEqualityMatchingRule
extends EqualityMatchingRule
{
-
-
-
/**
* The lock that will be used to provide threadsafe access to the date
* formatter.
@@ -209,651 +201,30 @@
public ByteString normalizeValue(ByteString value)
throws DirectoryException
{
- String valueString = value.stringValue().toUpperCase();
- int length = valueString.length();
-
-
- //Make sure that it has at least eleven characters and parse the first ten
- // as the year, month, day, and hour.
- if (length < 11)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT;
- String message = getMessage(msgID, valueString);
-
- switch (DirectoryServer.getSyntaxEnforcementPolicy())
- {
- case REJECT:
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- case WARN:
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.SEVERE_WARNING,
- message, msgID);
- return new ASN1OctetString(valueString);
- default:
- return new ASN1OctetString(valueString);
- }
- }
-
-
- // The year, month, day, and hour must always be specified.
- int year;
- int month;
- int day;
- int hour;
try
{
- year = Integer.parseInt(valueString.substring(0, 4));
- month = Integer.parseInt(valueString.substring(4, 6));
- day = Integer.parseInt(valueString.substring(6, 8));
- hour = Integer.parseInt(valueString.substring(8, 10));
+ long timestamp = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(value);
+ return new ASN1OctetString(GeneralizedTimeSyntax.format(timestamp));
}
- catch (Exception e)
+ catch (DirectoryException de)
{
if (debugEnabled())
{
- debugCaught(DebugLogLevel.ERROR, e);
+ debugCaught(DebugLogLevel.ERROR, de);
}
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE;
- String message = getMessage(msgID, valueString,
- String.valueOf(e));
-
switch (DirectoryServer.getSyntaxEnforcementPolicy())
{
case REJECT:
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
+ throw de;
+
case WARN:
logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.SEVERE_WARNING,
- message, msgID);
- return new ASN1OctetString(valueString);
+ de.getErrorMessage(), de.getErrorMessageID());
+ return new ASN1OctetString(value.value());
+
default:
- return new ASN1OctetString(valueString);
- }
- }
-
-
- // The minute may come next, but if not then it should indicate that we've
- // hit the end of the value.
- int minute;
- if (isDigit(valueString.charAt(10)))
- {
- try
- {
- minute = Integer.parseInt(valueString.substring(10, 12));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE;
- String message = getMessage(msgID, valueString,
- String.valueOf(e));
-
- switch (DirectoryServer.getSyntaxEnforcementPolicy())
- {
- case REJECT:
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- case WARN:
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.SEVERE_WARNING,
- message, msgID);
- return new ASN1OctetString(valueString);
- default:
- return new ASN1OctetString(valueString);
- }
- }
- }
- else
- {
- return processValueEnd(valueString, 10, year, month, day, hour, 0, 0, 0);
- }
-
-
- // The second should come next, but if not then it should indicate that
- // we've hit the end of the value.
- int second;
- if (length < 13)
- {
- // Technically, this is invalid. If we're enforcing strict syntax
- // adherence, then throw an exception. Otherwise, just assume that it's
- // a time with a second of zero and parse it in the local time zone.
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT;
- String message = getMessage(msgID, valueString);
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- GregorianCalendar calendar =
- new GregorianCalendar(year, (month-1), day, hour, minute, 0);
- calendar.setTimeZone(utcTimeZone);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- String message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
- }
- }
- }
- else
- {
- if (isDigit(valueString.charAt(12)))
- {
- try
- {
- second = Integer.parseInt(valueString.substring(12, 14));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE;
- String message = getMessage(msgID, valueString,
- String.valueOf(e));
-
- switch (DirectoryServer.getSyntaxEnforcementPolicy())
- {
- case REJECT:
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- case WARN:
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.SEVERE_WARNING,
- message, msgID);
- return new ASN1OctetString(valueString);
- default:
- return new ASN1OctetString(valueString);
- }
- }
- }
- else
- {
- return processValueEnd(valueString, 12, year, month, day, hour, minute,
- 0, 0);
- }
- }
-
-
- // If the next character is a period, then it will start the sub-second
- // portion of the value. Otherwise, it should indicate that we've hit the
- // end of the value.
- if (length < 15)
- {
- // Technically, this is invalid. If we're enforcing strict syntax
- // adherence, then throw an exception. Otherwise, just assume that it's
- // a time with a second of zero and parse it in the local time zone.
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT;
- String message = getMessage(msgID, valueString);
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- GregorianCalendar calendar =
- new GregorianCalendar(year, (month-1), day, hour, minute, second);
- calendar.setTimeZone(utcTimeZone);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- String message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
- }
- }
- }
- else
- {
- if (valueString.charAt(14) == '.')
- {
- // There should be some number of digits following the decimal point to
- // indicate the sub-second value. We'll read all of them now, but may
- // throw some away later.
- char c;
- int pos = 15;
- StringBuilder buffer = new StringBuilder(3);
- for ( ; pos < length; pos++)
- {
- if (isDigit(c = valueString.charAt(pos)))
- {
- buffer.append(c);
- }
- else
- {
- break;
- }
- }
-
- int millisecond;
- switch (buffer.length())
- {
- case 0:
- millisecond = 0;
- break;
- case 1:
- millisecond = (100 * Integer.parseInt(buffer.toString()));
- break;
- case 2:
- millisecond = (10 * Integer.parseInt(buffer.toString()));
- break;
- case 3:
- millisecond = Integer.parseInt(buffer.toString());
- break;
- default:
- // We only want three digits for the millisecond, but if the fourth
- // digit is greater than or equal to five, then we may need to round
- // up.
- millisecond = Integer.parseInt(buffer.toString().substring(0, 3));
- switch (buffer.charAt(3))
- {
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- millisecond++;
- break;
- }
- break;
- }
-
- return processValueEnd(valueString, pos, year, month, day, hour, minute,
- second, millisecond);
- }
- else
- {
- return processValueEnd(valueString, 14, year, month, day, hour, minute,
- second, 0);
- }
- }
- }
-
-
-
- /**
- * Processes the specified portion of the value as the end of the generalized
- * time specification. If the character at the specified location is a 'Z',
- * then it will be assumed that the value is already in UTC. If it is a '+'
- * or '-', then it will be assumed that the remainder is an offset from UTC.
- * Otherwise, it will be an error.
- *
- * @param valueString The value being parsed as a generalized time string.
- * @param endPos The position at which the end of the value begins.
- * @param year The year parsed from the value.
- * @param month The month parsed from the value.
- * @param day The day parsed from the value.
- * @param hour The hour parsed from the value.
- * @param minute The minute parsed from the value.
- * @param second The second parsed from the value.
- * @param millisecond The millisecond parsed from the value.
- *
- * @return The normalized representation of the generalized time parsed from
- * the value.
- *
- * @throws DirectoryException If a problem occurs while attempting to decode
- * the end of the generalized time value.
- */
- private ByteString processValueEnd(String valueString, int endPos, int year,
- int month, int day, int hour, int minute,
- int second, int millisecond)
- throws DirectoryException
- {
- // First, check to see if we are at the end of the string. If so, then
- // that could either result in an exception or assuming that we should just
- // use the local time zone.
- int length = valueString.length();
- if (endPos >= length)
- {
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT;
- String message = getMessage(msgID, valueString);
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- GregorianCalendar calendar =
- new GregorianCalendar(year, (month-1), day, hour, minute, second);
- calendar.setTimeZone(utcTimeZone);
- calendar.set(Calendar.MILLISECOND, millisecond);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- String message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
- }
- }
- }
-
-
- // See what the character is at the specified position. If it is a 'Z',
- // then make sure it's the end of the value and treat it as a UTC date.
- char c = valueString.charAt(endPos);
- if (c == 'Z')
- {
- if (endPos == (length-1))
- {
- GregorianCalendar calendar =
- new GregorianCalendar(year, (month-1), day, hour, minute, second);
- calendar.setTimeZone(utcTimeZone);
- calendar.set(Calendar.MILLISECOND, millisecond);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- String message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
- }
- }
- else
- {
- // This is weird because the Z wasn't the last character. If we should
- // enforce strict syntax checking, then throw an exception. Otherwise,
- // return what we've got so far.
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, 'Z', endPos);
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- GregorianCalendar calendar =
- new GregorianCalendar(TimeZone.getTimeZone("UTC"));
- calendar.setTimeZone(utcTimeZone);
- calendar.set(year, (month-1), day, hour, minute, second);
- calendar.set(Calendar.MILLISECOND, millisecond);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- String message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
- }
- }
- }
- }
-
-
- // If the character is a plus or minus, then take the next two or four
- // digits and use them as a time zone offset.
- else if ((c == '-') || (c == '+'))
- {
- int offset;
- int charsRemaining = length - endPos - 1;
- if (charsRemaining == 2)
- {
- // The offset specifies the number of hours off GMT.
- try
- {
- offset = Integer.parseInt(valueString.substring(endPos+1)) * 3600000;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
- String message = getMessage(msgID, valueString,
- valueString.substring(endPos));
-
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.MILD_ERROR,
- message, msgID);
- offset = 0;
- }
- }
- }
- else if (charsRemaining == 4)
- {
- // The offset specifies the number of hours and minutes off GMT.
- try
- {
- String hourStr = valueString.substring(endPos+1, endPos+3);
- String minStr = valueString.substring(endPos+3, endPos+5);
- offset = (Integer.parseInt(hourStr) * 3600000) +
- (Integer.parseInt(minStr) * 60000);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
- String message = getMessage(msgID, valueString,
- valueString.substring(endPos));
-
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.MILD_ERROR,
- message, msgID);
- offset = 0;
- }
- }
- }
- else
- {
- // It is an invalid offset, so either throw an exception or assume the
- // local time zone.
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
- String message = getMessage(msgID, valueString,
- valueString.substring(endPos));
-
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.MILD_ERROR,
- message, msgID);
- offset = TimeZone.getDefault().getRawOffset();
- }
- }
-
- GregorianCalendar calendar = new GregorianCalendar(year, (month-1), day,
- hour, minute, second);
- calendar.setTimeZone(utcTimeZone);
- calendar.set(Calendar.MILLISECOND, millisecond);
- calendar.set(Calendar.ZONE_OFFSET, offset);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- String message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
- }
- }
-
-
- // If we've gotten here, then there was an illegal character at the end of
- // the value. Either throw an exception or assume the default time zone.
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, c, endPos);
-
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.MILD_ERROR, message,
- msgID);
-
- GregorianCalendar calendar = new GregorianCalendar(year, (month-1), day,
- hour, minute, second);
- calendar.setTimeZone(utcTimeZone);
- calendar.set(Calendar.MILLISECOND, millisecond);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
+ return new ASN1OctetString(value.value());
}
}
}
@@ -872,9 +243,21 @@
*/
public boolean areEqual(ByteString value1, ByteString value2)
{
- // Since the values are already normalized, we just need to compare the
- // associated byte arrays.
- return Arrays.equals(value1.value(), value2.value());
+ try
+ {
+ long time1 = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(value1);
+ long time2 = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(value2);
+ return (time1 == time2);
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ return false;
+ }
}
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java b/opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java
index 7b8148f..e99d558 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java
@@ -29,8 +29,6 @@
import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.concurrent.locks.ReentrantLock;
@@ -39,13 +37,11 @@
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.types.AcceptRejectWarn;
import org.opends.server.types.ByteString;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.ErrorLogCategory;
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
@@ -66,9 +62,6 @@
public class GeneralizedTimeOrderingMatchingRule
extends OrderingMatchingRule
{
-
-
-
/**
* The serial version identifier required to satisfy the compiler because this
* class implements the <CODE>java.io.Serializable</CODE> interface. This
@@ -218,651 +211,30 @@
public ByteString normalizeValue(ByteString value)
throws DirectoryException
{
- String valueString = value.stringValue().toUpperCase();
- int length = valueString.length();
-
-
- //Make sure that it has at least eleven characters and parse the first ten
- // as the year, month, day, and hour.
- if (length < 11)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT;
- String message = getMessage(msgID, valueString);
-
- switch (DirectoryServer.getSyntaxEnforcementPolicy())
- {
- case REJECT:
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- case WARN:
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.SEVERE_WARNING,
- message, msgID);
- return new ASN1OctetString(valueString);
- default:
- return new ASN1OctetString(valueString);
- }
- }
-
-
- // The year, month, day, and hour must always be specified.
- int year;
- int month;
- int day;
- int hour;
try
{
- year = Integer.parseInt(valueString.substring(0, 4));
- month = Integer.parseInt(valueString.substring(4, 6));
- day = Integer.parseInt(valueString.substring(6, 8));
- hour = Integer.parseInt(valueString.substring(8, 10));
+ long timestamp = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(value);
+ return new ASN1OctetString(GeneralizedTimeSyntax.format(timestamp));
}
- catch (Exception e)
+ catch (DirectoryException de)
{
if (debugEnabled())
{
- debugCaught(DebugLogLevel.ERROR, e);
+ debugCaught(DebugLogLevel.ERROR, de);
}
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE;
- String message = getMessage(msgID, valueString,
- String.valueOf(e));
-
switch (DirectoryServer.getSyntaxEnforcementPolicy())
{
case REJECT:
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
+ throw de;
+
case WARN:
logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.SEVERE_WARNING,
- message, msgID);
- return new ASN1OctetString(valueString);
+ de.getErrorMessage(), de.getErrorMessageID());
+ return new ASN1OctetString(value.value());
+
default:
- return new ASN1OctetString(valueString);
- }
- }
-
-
- // The minute may come next, but if not then it should indicate that we've
- // hit the end of the value.
- int minute;
- if (isDigit(valueString.charAt(10)))
- {
- try
- {
- minute = Integer.parseInt(valueString.substring(10, 12));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE;
- String message = getMessage(msgID, valueString,
- String.valueOf(e));
-
- switch (DirectoryServer.getSyntaxEnforcementPolicy())
- {
- case REJECT:
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- case WARN:
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.SEVERE_WARNING,
- message, msgID);
- return new ASN1OctetString(valueString);
- default:
- return new ASN1OctetString(valueString);
- }
- }
- }
- else
- {
- return processValueEnd(valueString, 10, year, month, day, hour, 0, 0, 0);
- }
-
-
- // The second should come next, but if not then it should indicate that
- // we've hit the end of the value.
- int second;
- if (length < 13)
- {
- // Technically, this is invalid. If we're enforcing strict syntax
- // adherence, then throw an exception. Otherwise, just assume that it's
- // a time with a second of zero and parse it in the local time zone.
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT;
- String message = getMessage(msgID, valueString);
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- GregorianCalendar calendar =
- new GregorianCalendar(year, (month-1), day, hour, minute, 0);
- calendar.setTimeZone(utcTimeZone);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- String message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
- }
- }
- }
- else
- {
- if (isDigit(valueString.charAt(12)))
- {
- try
- {
- second = Integer.parseInt(valueString.substring(12, 14));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE;
- String message = getMessage(msgID, valueString,
- String.valueOf(e));
-
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- else
- {
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.MILD_ERROR,
- message, msgID);
- return new ASN1OctetString(valueString);
- }
- }
- }
- else
- {
- return processValueEnd(valueString, 12, year, month, day, hour, minute,
- 0, 0);
- }
- }
-
-
- // If the next character is a period, then it will start the sub-second
- // portion of the value. Otherwise, it should indicate that we've hit the
- // end of the value.
- if (length < 15)
- {
- // Technically, this is invalid. If we're enforcing strict syntax
- // adherence, then throw an exception. Otherwise, just assume that it's
- // a time with a second of zero and parse it in the local time zone.
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT;
- String message = getMessage(msgID, valueString);
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- GregorianCalendar calendar =
- new GregorianCalendar(year, (month-1), day, hour, minute, second);
- calendar.setTimeZone(utcTimeZone);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- String message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
- }
- }
- }
- else
- {
- if (valueString.charAt(14) == '.')
- {
- // There should be some number of digits following the decimal point to
- // indicate the sub-second value. We'll read all of them now, but may
- // throw some away later.
- char c;
- int pos = 15;
- StringBuilder buffer = new StringBuilder(3);
- for ( ; pos < length; pos++)
- {
- if (isDigit(c = valueString.charAt(pos)))
- {
- buffer.append(c);
- }
- else
- {
- break;
- }
- }
-
- int millisecond;
- switch (buffer.length())
- {
- case 0:
- millisecond = 0;
- break;
- case 1:
- millisecond = (100 * Integer.parseInt(buffer.toString()));
- break;
- case 2:
- millisecond = (10 * Integer.parseInt(buffer.toString()));
- break;
- case 3:
- millisecond = Integer.parseInt(buffer.toString());
- break;
- default:
- // We only want three digits for the millisecond, but if the fourth
- // digit is greater than or equal to five, then we may need to round
- // up.
- millisecond = Integer.parseInt(buffer.toString().substring(0, 3));
- switch (buffer.charAt(3))
- {
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- millisecond++;
- break;
- }
- break;
- }
-
- return processValueEnd(valueString, pos, year, month, day, hour, minute,
- second, millisecond);
- }
- else
- {
- return processValueEnd(valueString, 14, year, month, day, hour, minute,
- second, 0);
- }
- }
- }
-
-
-
- /**
- * Processes the specified portion of the value as the end of the generalized
- * time specification. If the character at the specified location is a 'Z',
- * then it will be assumed that the value is already in UTC. If it is a '+'
- * or '-', then it will be assumed that the remainder is an offset from UTC.
- * Otherwise, it will be an error.
- *
- * @param valueString The value being parsed as a generalized time string.
- * @param endPos The position at which the end of the value begins.
- * @param year The year parsed from the value.
- * @param month The month parsed from the value.
- * @param day The day parsed from the value.
- * @param hour The hour parsed from the value.
- * @param minute The minute parsed from the value.
- * @param second The second parsed from the value.
- * @param millisecond The millisecond parsed from the value.
- *
- * @return The normalized representation of the generalized time parsed from
- * the value.
- *
- * @throws DirectoryException If a problem occurs while attempting to decode
- * the end of the generalized time value.
- */
- private ByteString processValueEnd(String valueString, int endPos, int year,
- int month, int day, int hour, int minute,
- int second, int millisecond)
- throws DirectoryException
- {
- // First, check to see if we are at the end of the string. If so, then
- // that could either result in an exception or assuming that we should just
- // use the local time zone.
- int length = valueString.length();
- if (endPos >= length)
- {
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT;
- String message = getMessage(msgID, valueString);
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- GregorianCalendar calendar =
- new GregorianCalendar(year, (month-1), day, hour, minute, second);
- calendar.setTimeZone(utcTimeZone);
- calendar.set(Calendar.MILLISECOND, millisecond);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- String message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
- }
- }
- }
-
-
- // See what the character is at the specified position. If it is a 'Z',
- // then make sure it's the end of the value and treat it as a UTC date.
- char c = valueString.charAt(endPos);
- if (c == 'Z')
- {
- if (endPos == (length-1))
- {
- GregorianCalendar calendar =
- new GregorianCalendar(year, (month-1), day, hour, minute, second);
- calendar.setTimeZone(utcTimeZone);
- calendar.set(Calendar.MILLISECOND, millisecond);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- String message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
- }
- }
- else
- {
- // This is weird because the Z wasn't the last character. If we should
- // enforce strict syntax checking, then throw an exception. Otherwise,
- // return what we've got so far.
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, 'Z', endPos);
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- GregorianCalendar calendar =
- new GregorianCalendar(TimeZone.getTimeZone("UTC"));
- calendar.setTimeZone(utcTimeZone);
- calendar.set(year, (month-1), day, hour, minute, second);
- calendar.set(Calendar.MILLISECOND, millisecond);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- String message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
- }
- }
- }
- }
-
-
- // If the character is a plus or minus, then take the next two or four
- // digits and use them as a time zone offset.
- else if ((c == '-') || (c == '+'))
- {
- int offset;
- int charsRemaining = length - endPos - 1;
- if (charsRemaining == 2)
- {
- // The offset specifies the number of hours off GMT.
- try
- {
- offset = Integer.parseInt(valueString.substring(endPos+1)) * 3600000;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
- String message = getMessage(msgID, valueString,
- valueString.substring(endPos));
-
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.MILD_ERROR,
- message, msgID);
- offset = 0;
- }
- }
- }
- else if (charsRemaining == 4)
- {
- // The offset specifies the number of hours and minutes off GMT.
- try
- {
- String hourStr = valueString.substring(endPos+1, endPos+3);
- String minStr = valueString.substring(endPos+3, endPos+5);
- offset = (Integer.parseInt(hourStr) * 3600000) +
- (Integer.parseInt(minStr) * 1000);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
- String message = getMessage(msgID, valueString,
- valueString.substring(endPos));
-
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.MILD_ERROR,
- message, msgID);
- offset = 0;
- }
- }
- }
- else
- {
- // It is an invalid offset, so either throw an exception or assume the
- // local time zone.
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
- String message = getMessage(msgID, valueString,
- valueString.substring(endPos));
-
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.MILD_ERROR,
- message, msgID);
- offset = TimeZone.getDefault().getRawOffset();
- }
- }
-
- GregorianCalendar calendar = new GregorianCalendar(year, (month-1), day,
- hour, minute, second);
- calendar.setTimeZone(utcTimeZone);
- calendar.set(Calendar.MILLISECOND, millisecond);
- calendar.set(Calendar.ZONE_OFFSET, offset);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- String message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
- }
- }
-
-
- // If we've gotten here, then there was an illegal character at the end of
- // the value. Either throw an exception or assume the default time zone.
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, c, endPos);
-
- if (DirectoryServer.getSyntaxEnforcementPolicy() ==
- AcceptRejectWarn.REJECT)
- {
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID);
- }
- else
- {
- logError(ErrorLogCategory.SCHEMA, ErrorLogSeverity.MILD_ERROR, message,
- msgID);
-
- GregorianCalendar calendar = new GregorianCalendar(year, (month-1), day,
- hour, minute, second);
- calendar.setTimeZone(utcTimeZone);
- calendar.set(Calendar.MILLISECOND, millisecond);
-
- dateFormatLock.lock();
-
- try
- {
- return new ASN1OctetString(dateFormat.format(calendar.getTime()));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE;
- message = getMessage(msgID, valueString,
- stackTraceToSingleLineString(e));
-
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- message, msgID, e);
- }
- finally
- {
- dateFormatLock.unlock();
+ return new ASN1OctetString(value.value());
}
}
}
@@ -884,7 +256,33 @@
*/
public int compareValues(ByteString value1, ByteString value2)
{
- return compare(value1.value(), value2.value());
+ try
+ {
+ long time1 = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(value1);
+ long time2 = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(value2);
+
+ if (time1 == time2)
+ {
+ return 0;
+ }
+ else if (time1 > time2)
+ {
+ return 1;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ return 0;
+ }
}
@@ -904,36 +302,7 @@
*/
public int compare(byte[] b1, byte[] b2)
{
- int minLength = Math.min(b1.length, b2.length);
-
- for (int i=0; i < minLength; i++)
- {
- if (b1[i] == b2[i])
- {
- continue;
- }
- else if (b1[i] < b2[i])
- {
- return -1;
- }
- else if (b1[i] > b2[i])
- {
- return 1;
- }
- }
-
- if (b1.length == b2.length)
- {
- return 0;
- }
- else if (b1.length < b2.length)
- {
- return -1;
- }
- else
- {
- return 1;
- }
+ return compareValues(new ASN1OctetString(b1), new ASN1OctetString(b2));
}
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeSyntax.java b/opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeSyntax.java
index f507779..cc204be 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeSyntax.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/schema/GeneralizedTimeSyntax.java
@@ -29,7 +29,9 @@
import java.text.SimpleDateFormat;
+import java.util.Calendar;
import java.util.Date;
+import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.concurrent.locks.ReentrantLock;
@@ -70,9 +72,6 @@
public class GeneralizedTimeSyntax
extends AttributeSyntax
{
-
-
-
/**
* The lock that will be used to provide threadsafe access to the date
* formatter.
@@ -284,714 +283,16 @@
public boolean valueIsAcceptable(ByteString value,
StringBuilder invalidReason)
{
- // Get the value as a string and verify that it is at least long enough for
- // "YYYYMMDDhhZ", which is the shortest allowed value.
- String valueString = value.stringValue().toUpperCase();
- int length = valueString.length();
- if (length < 11)
+ try
{
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT;
- String message = getMessage(msgID, valueString);
- invalidReason.append(message);
+ decodeGeneralizedTimeValue(value);
+ return true;
+ }
+ catch (DirectoryException de)
+ {
+ invalidReason.append(de.getErrorMessage());
return false;
}
-
-
- // The first four characters are the century and year, and they must be
- // numeric digits between 0 and 9.
- for (int i=0; i < 4; i++)
- {
- switch (valueString.charAt(i))
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- // These are all fine.
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_YEAR;
- String message = getMessage(msgID, valueString,
- valueString.charAt(i));
- invalidReason.append(message);
- return false;
- }
- }
-
-
- // The next two characters are the month, and they must form the string
- // representation of an integer between 01 and 12.
- char m1 = valueString.charAt(4);
- char m2 = valueString.charAt(5);
- switch (m1)
- {
- case '0':
- // m2 must be a digit between 1 and 9.
- switch (m2)
- {
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- // These are all fine.
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH;
- String message = getMessage(msgID, valueString,
- valueString.substring(4, 6));
- invalidReason.append(message);
- return false;
- }
- break;
- case '1':
- // m2 must be a digit between 0 and 2.
- switch (m2)
- {
- case '0':
- case '1':
- case '2':
- // These are all fine.
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH;
- String message = getMessage(msgID, valueString,
- valueString.substring(4, 6));
- invalidReason.append(message);
- return false;
- }
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH;
- String message = getMessage(msgID, valueString,
- valueString.substring(4, 6));
- invalidReason.append(message);
- return false;
- }
-
-
- // The next two characters should be the day of the month, and they must
- // form the string representation of an integer between 01 and 31.
- // This doesn't do any validation against the year or month, so it will
- // allow dates like April 31, or February 29 in a non-leap year, but we'll
- // let those slide.
- char d1 = valueString.charAt(6);
- char d2 = valueString.charAt(7);
- switch (d1)
- {
- case '0':
- // d2 must be a digit between 1 and 9.
- switch (d2)
- {
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- // These are all fine.
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY;
- String message = getMessage(msgID, valueString,
- valueString.substring(6, 8));
- invalidReason.append(message);
- return false;
- }
- break;
- case '1':
- // Treated the same as '2'.
- case '2':
- // d2 must be a digit between 0 and 9.
- switch (d2)
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- // These are all fine.
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY;
- String message = getMessage(msgID, valueString,
- valueString.substring(6, 8));
- invalidReason.append(message);
- return false;
- }
- break;
- case '3':
- // d2 must be either 0 or 1.
- switch (d2)
- {
- case '0':
- case '1':
- // These are all fine.
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY;
- String message = getMessage(msgID, valueString,
- valueString.substring(6, 8));
- invalidReason.append(message);
- return false;
- }
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY;
- String message = getMessage(msgID, valueString,
- valueString.substring(6, 8));
- invalidReason.append(message);
- return false;
- }
-
-
- // The next two characters must be the hour, and they must form the string
- // representation of an integer between 00 and 23.
- char h1 = valueString.charAt(8);
- char h2 = valueString.charAt(9);
- switch (h1)
- {
- case '0':
- // This is treated the same as '1'.
- case '1':
- switch (h2)
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- // These are all fine.
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR;
- String message = getMessage(msgID, valueString,
- valueString.substring(8, 10));
- invalidReason.append(message);
- return false;
- }
- break;
- case '2':
- // This must be a digit between 0 and 3.
- switch (h2)
- {
- case '0':
- case '1':
- case '2':
- case '3':
- // These are all fine.
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR;
- String message = getMessage(msgID, valueString,
- valueString.substring(8, 10));
- invalidReason.append(message);
- return false;
- }
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR;
- String message = getMessage(msgID, valueString,
- valueString.substring(8, 10));
- invalidReason.append(message);
- return false;
- }
-
-
- // Next, there should be either two digits comprising an integer between 00
- // and 59 (for the minute), a letter 'Z' (for the UTC specifier), or a plus
- // or minus sign followed by two or four digits (for the UTC offset).
- m1 = valueString.charAt(10);
- switch (m1)
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- // There must be at least two more characters, and the next one must
- // be a digit between 0 and 9.
- if (length < 13)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, m1, 10);
- invalidReason.append(message);
- return false;
- }
-
- switch (valueString.charAt(11))
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- // These are all fine.
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE;
- String message = getMessage(msgID, valueString,
- valueString.substring(10, 12));
- invalidReason.append(message);
- return false;
- }
-
- break;
- case 'Z':
- // This is fine only if we are at the end of the value.
- if (length == 11)
- {
- return true;
- }
- else
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, m1, 10);
- invalidReason.append(message);
- return false;
- }
-
- case '+':
- case '-':
- // These are fine only if there are exactly two or four more digits that
- // specify a valid offset.
- if ((length == 13) || (length == 15))
- {
- return hasValidOffset(valueString, 11, invalidReason);
- }
- else
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, m1, 10);
- invalidReason.append(message);
- return false;
- }
-
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, m1, 10);
- invalidReason.append(message);
- return false;
- }
-
-
- // Next, there should be either two digits comprising an integer between 00
- // and 60 (for the second, including a possible leap second), a letter 'Z'
- // (for the UTC specifier), or a plus or minus sign followed by two or four
- // digits (for the UTC offset).
- char s1 = valueString.charAt(12);
- switch (s1)
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- // There must be at least two more characters, and the next one must
- // be a digit between 0 and 9.
- if (length < 15)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, s1, 12);
- invalidReason.append(message);
- return false;
- }
-
- switch (valueString.charAt(13))
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- // These are all fine.
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SECOND;
- String message = getMessage(msgID, valueString,
- valueString.substring(12, 14));
- invalidReason.append(message);
- return false;
- }
-
- break;
- case '6':
- // There must be at least two more characters and the next one must be
- // a 0.
- if (length < 15)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, s1, 12);
- invalidReason.append(message);
- return false;
- }
-
- if (valueString.charAt(13) != '0')
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SECOND;
- String message = getMessage(msgID, valueString,
- valueString.substring(12, 14));
- invalidReason.append(message);
- return false;
- }
-
- break;
- case 'Z':
- // This is fine only if we are at the end of the value.
- if (length == 13)
- {
- return true;
- }
- else
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, s1, 12);
- invalidReason.append(message);
- return false;
- }
-
- case '+':
- case '-':
- // These are fine only if there are exactly two or four more digits that
- // specify a valid offset.
- if ((length == 15) || (length == 17))
- {
- return hasValidOffset(valueString, 13, invalidReason);
- }
- else
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, s1, 12);
- invalidReason.append(message);
- return false;
- }
-
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, s1, 12);
- invalidReason.append(message);
- return false;
- }
-
-
- // Next, there should be either a period or comma followed by between one
- // and three digits (to specify the sub-second), a letter 'Z' (for the UTC
- // specifier), or a plus or minus sign followed by two our four digits (for
- // the UTC offset).
- switch (valueString.charAt(14))
- {
- case '.':
- case ',':
- // There will be a sub-second portion. Walk through the rest of the
- // value until we find a Z, +, or -.
- boolean endFound = false;
- int pos = 15;
- while (pos < length)
- {
-
- switch (valueString.charAt(pos))
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- // These are fine as long as we don't have more than three.
- if (pos > 17)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_LONG_SUBSECOND;
- String message = getMessage(msgID, value);
- invalidReason.append(message);
- return false;
- }
-
- break;
- case 'Z':
- // This must be the end of the string and there must have been
- // at least one sub-second digit.
- if (pos == 15)
- {
- int msgID =
- MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SUBSECOND;
- String message = getMessage(msgID, value);
- invalidReason.append(message);
- return false;
- }
-
- if (pos != (length-1))
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString,
- valueString.charAt(pos), pos);
- invalidReason.append(message);
- return false;
- }
-
- return true;
-
- case '+':
- case '-':
- // There must have been at least one sub-second digit, and there
- // must be either two or four digits left.
- if (pos == 15)
- {
- int msgID =
- MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SUBSECOND;
- String message = getMessage(msgID, value);
- invalidReason.append(message);
- return false;
- }
- else if ((length != 17) && (length != 19))
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString,
- valueString.charAt(pos), pos);
- invalidReason.append(message);
- return false;
- }
- else
- {
- return hasValidOffset(valueString, pos+1, invalidReason);
- }
-
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString,
- valueString.charAt(pos), pos);
- invalidReason.append(message);
- return false;
- }
-
- pos++;
- }
-
-
- // There must be at least two more characters and the first must be a
- // digit.
- if (length < 16)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, s1, 12);
- invalidReason.append(message);
- return false;
- }
-
- break;
-
- case 'Z':
- // This is fine only if we are at the end of the value.
- if (length == 15)
- {
- return true;
- }
- else
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString,
- valueString.charAt(14), 14);
- invalidReason.append(message);
- return false;
- }
-
- case '+':
- case '-':
- // These are fine only if there are exactly two or four more digits that
- // specify a valid offset.
- if ((length == 17) || (length == 19))
- {
- return hasValidOffset(valueString, 15, invalidReason);
- }
- else
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString,
- valueString.charAt(14), 14);
- invalidReason.append(message);
- return false;
- }
-
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
- String message = getMessage(msgID, valueString, valueString.charAt(14),
- 14);
- invalidReason.append(message);
- return false;
- }
-
- return true;
- }
-
-
-
- /**
- * Indicates whether the provided string contains a valid set of two or four
- * UTC offset digits. The provided string must have either two or four
- * characters from the provided start position to the end of the value.
- *
- * @param value The whole value, including the offset.
- * @param startPos The position of the first character that is
- * contained in the offset.
- * @param invalidReason The buffer to which the invalid reason may be
- * appended if the string does not contain a valid set
- * of UTC offset digits.
- *
- * @return <CODE>true</CODE> if the provided offset string is valid, or
- * <CODE>false</CODE> if it is not.
- */
- private boolean hasValidOffset(String value, int startPos,
- StringBuilder invalidReason)
- {
- int offsetLength = value.length() - startPos;
- if (offsetLength < 2)
- {
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT;
- String message = getMessage(msgID, value);
- invalidReason.append(message);
- return false;
- }
-
- // The first two characters must be an integer between 00 and 23.
- switch (value.charAt(startPos))
- {
- case '0':
- case '1':
- switch (value.charAt(startPos+1))
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- // These are all fine.
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
- String message = getMessage(msgID, value,
- value.substring(startPos,
- startPos+offsetLength));
- invalidReason.append(message);
- return false;
- }
- break;
- case '2':
- switch (value.charAt(startPos+1))
- {
- case '0':
- case '1':
- case '2':
- case '3':
- // These are all fine.
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
- String message = getMessage(msgID, value,
- value.substring(startPos,
- startPos+offsetLength));
- invalidReason.append(message);
- return false;
- }
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
- String message = getMessage(msgID, value,
- value.substring(startPos,
- startPos+offsetLength));
- invalidReason.append(message);
- return false;
- }
-
-
- // If there are two more characters, then they must be an integer between
- // 00 and 59.
- if (offsetLength == 4)
- {
- switch (value.charAt(startPos+2))
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- switch (value.charAt(startPos+3))
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- // These are all fine.
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
- String message =
- getMessage(msgID, value,value.substring(startPos,
- startPos+offsetLength));
- invalidReason.append(message);
- return false;
- }
- break;
- default:
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
- String message = getMessage(msgID, value,
- value.substring(startPos,
- startPos+offsetLength));
- invalidReason.append(message);
- return false;
- }
- }
-
- return true;
}
@@ -1086,35 +387,1082 @@
* Decodes the provided normalized value as a generalized time value and
* retrieves a timestamp containing its representation.
*
- * @param normalizedValue The normalized generalized time value to decode to
- * a Java <CODE>Date</CODE>.
+ * @param value The normalized value to decode using the generalized time
+ * syntax.
*
* @return The timestamp created from the provided generalized time value.
*
* @throws DirectoryException If the provided value cannot be parsed as a
* valid generalized time string.
*/
- public static long decodeGeneralizedTimeValue(ByteString normalizedValue)
+ public static long decodeGeneralizedTimeValue(ByteString value)
throws DirectoryException
{
- String valueString = normalizedValue.stringValue();
+ int year = 0;
+ int month = 0;
+ int day = 0;
+ int hour = 0;
+ int minute = 0;
+ int second = 0;
+
+
+ // Get the value as a string and verify that it is at least long enough for
+ // "YYYYMMDDhhZ", which is the shortest allowed value.
+ String valueString = value.stringValue().toUpperCase();
+ int length = valueString.length();
+ if (length < 11)
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT;
+ String message = getMessage(msgID, valueString);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
+ msgID);
+ }
+
+
+ // The first four characters are the century and year, and they must be
+ // numeric digits between 0 and 9.
+ for (int i=0; i < 4; i++)
+ {
+ switch (valueString.charAt(i))
+ {
+ case '0':
+ year = (year * 10);
+ break;
+
+ case '1':
+ year = (year * 10) + 1;
+ break;
+
+ case '2':
+ year = (year * 10) + 2;
+ break;
+
+ case '3':
+ year = (year * 10) + 3;
+ break;
+
+ case '4':
+ year = (year * 10) + 4;
+ break;
+
+ case '5':
+ year = (year * 10) + 5;
+ break;
+
+ case '6':
+ year = (year * 10) + 6;
+ break;
+
+ case '7':
+ year = (year * 10) + 7;
+ break;
+
+ case '8':
+ year = (year * 10) + 8;
+ break;
+
+ case '9':
+ year = (year * 10) + 9;
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_YEAR;
+ String message = getMessage(msgID, valueString,
+ valueString.charAt(i));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ }
+
+
+ // The next two characters are the month, and they must form the string
+ // representation of an integer between 01 and 12.
+ char m1 = valueString.charAt(4);
+ char m2 = valueString.charAt(5);
+ switch (m1)
+ {
+ case '0':
+ // m2 must be a digit between 1 and 9.
+ switch (m2)
+ {
+ case '1':
+ month = Calendar.JANUARY;
+ break;
+
+ case '2':
+ month = Calendar.FEBRUARY;
+ break;
+
+ case '3':
+ month = Calendar.MARCH;
+ break;
+
+ case '4':
+ month = Calendar.APRIL;
+ break;
+
+ case '5':
+ month = Calendar.MAY;
+ break;
+
+ case '6':
+ month = Calendar.JUNE;
+ break;
+
+ case '7':
+ month = Calendar.JULY;
+ break;
+
+ case '8':
+ month = Calendar.AUGUST;
+ break;
+
+ case '9':
+ month = Calendar.SEPTEMBER;
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(4, 6));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ break;
+ case '1':
+ // m2 must be a digit between 0 and 2.
+ switch (m2)
+ {
+ case '0':
+ month = Calendar.OCTOBER;
+ break;
+
+ case '1':
+ month = Calendar.NOVEMBER;
+ break;
+
+ case '2':
+ month = Calendar.DECEMBER;
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(4, 6));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ break;
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(4, 6));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+
+ // The next two characters should be the day of the month, and they must
+ // form the string representation of an integer between 01 and 31.
+ // This doesn't do any validation against the year or month, so it will
+ // allow dates like April 31, or February 29 in a non-leap year, but we'll
+ // let those slide.
+ char d1 = valueString.charAt(6);
+ char d2 = valueString.charAt(7);
+ switch (d1)
+ {
+ case '0':
+ // d2 must be a digit between 1 and 9.
+ switch (d2)
+ {
+ case '1':
+ day = 1;
+ break;
+
+ case '2':
+ day = 2;
+ break;
+
+ case '3':
+ day = 3;
+ break;
+
+ case '4':
+ day = 4;
+ break;
+
+ case '5':
+ day = 5;
+ break;
+
+ case '6':
+ day = 6;
+ break;
+
+ case '7':
+ day = 7;
+ break;
+
+ case '8':
+ day = 8;
+ break;
+
+ case '9':
+ day = 9;
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(6, 8));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ break;
+
+ case '1':
+ // d2 must be a digit between 0 and 9.
+ switch (d2)
+ {
+ case '0':
+ day = 10;
+ break;
+
+ case '1':
+ day = 11;
+ break;
+
+ case '2':
+ day = 12;
+ break;
+
+ case '3':
+ day = 13;
+ break;
+
+ case '4':
+ day = 14;
+ break;
+
+ case '5':
+ day = 15;
+ break;
+
+ case '6':
+ day = 16;
+ break;
+
+ case '7':
+ day = 17;
+ break;
+
+ case '8':
+ day = 18;
+ break;
+
+ case '9':
+ day = 19;
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(6, 8));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ break;
+
+ case '2':
+ // d2 must be a digit between 0 and 9.
+ switch (d2)
+ {
+ case '0':
+ day = 20;
+ break;
+
+ case '1':
+ day = 21;
+ break;
+
+ case '2':
+ day = 22;
+ break;
+
+ case '3':
+ day = 23;
+ break;
+
+ case '4':
+ day = 24;
+ break;
+
+ case '5':
+ day = 25;
+ break;
+
+ case '6':
+ day = 26;
+ break;
+
+ case '7':
+ day = 27;
+ break;
+
+ case '8':
+ day = 28;
+ break;
+
+ case '9':
+ day = 29;
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(6, 8));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ break;
+
+ case '3':
+ // d2 must be either 0 or 1.
+ switch (d2)
+ {
+ case '0':
+ day = 30;
+ break;
+
+ case '1':
+ day = 31;
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(6, 8));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(6, 8));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+
+ // The next two characters must be the hour, and they must form the string
+ // representation of an integer between 00 and 23.
+ char h1 = valueString.charAt(8);
+ char h2 = valueString.charAt(9);
+ switch (h1)
+ {
+ case '0':
+ switch (h2)
+ {
+ case '0':
+ hour = 0;
+ break;
+
+ case '1':
+ hour = 1;
+ break;
+
+ case '2':
+ hour = 2;
+ break;
+
+ case '3':
+ hour = 3;
+ break;
+
+ case '4':
+ hour = 4;
+ break;
+
+ case '5':
+ hour = 5;
+ break;
+
+ case '6':
+ hour = 6;
+ break;
+
+ case '7':
+ hour = 7;
+ break;
+
+ case '8':
+ hour = 8;
+ break;
+
+ case '9':
+ hour = 9;
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(8, 10));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ break;
+
+ case '1':
+ switch (h2)
+ {
+ case '0':
+ hour = 10;
+ break;
+
+ case '1':
+ hour = 11;
+ break;
+
+ case '2':
+ hour = 12;
+ break;
+
+ case '3':
+ hour = 13;
+ break;
+
+ case '4':
+ hour = 14;
+ break;
+
+ case '5':
+ hour = 15;
+ break;
+
+ case '6':
+ hour = 16;
+ break;
+
+ case '7':
+ hour = 17;
+ break;
+
+ case '8':
+ hour = 18;
+ break;
+
+ case '9':
+ hour = 19;
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(8, 10));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ break;
+
+ case '2':
+ switch (h2)
+ {
+ case '0':
+ hour = 20;
+ break;
+
+ case '1':
+ hour = 21;
+ break;
+
+ case '2':
+ hour = 22;
+ break;
+
+ case '3':
+ hour = 23;
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(8, 10));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(8, 10));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+
+ // Next, there should be either two digits comprising an integer between 00
+ // and 59 (for the minute), a letter 'Z' (for the UTC specifier), a plus
+ // or minus sign followed by two or four digits (for the UTC offset), or a
+ // period or comma representing the fraction.
+ m1 = valueString.charAt(10);
+ switch (m1)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ // There must be at least two more characters, and the next one must
+ // be a digit between 0 and 9.
+ if (length < 13)
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
+ String message = getMessage(msgID, valueString, m1, 10);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+
+ minute = 10 * (m1 - '0');
+
+ switch (valueString.charAt(11))
+ {
+ case '0':
+ break;
+
+ case '1':
+ minute += 1;
+ break;
+
+ case '2':
+ minute += 2;
+ break;
+
+ case '3':
+ minute += 3;
+ break;
+
+ case '4':
+ minute += 4;
+ break;
+
+ case '5':
+ minute += 5;
+ break;
+
+ case '6':
+ minute += 6;
+ break;
+
+ case '7':
+ minute += 7;
+ break;
+
+ case '8':
+ minute += 8;
+ break;
+
+ case '9':
+ minute += 9;
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(10, 12));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+ break;
+
+ case 'Z':
+ // This is fine only if we are at the end of the value.
+ if (length == 11)
+ {
+ try
+ {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setLenient(false);
+ calendar.setTimeZone(TimeZone.getTimeZone(TIME_ZONE_UTC));
+ calendar.set(year, month, day, hour, minute, second);
+ calendar.set(Calendar.MILLISECOND, 0);
+ return calendar.getTimeInMillis();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ // This should only happen if the provided date wasn't legal
+ // (e.g., September 31).
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME;
+ String message = getMessage(msgID, valueString, String.valueOf(e));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID, e);
+ }
+ }
+ else
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
+ String message = getMessage(msgID, valueString, m1, 10);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+ case '+':
+ case '-':
+ // These are fine only if there are exactly two or four more digits that
+ // specify a valid offset.
+ if ((length == 13) || (length == 15))
+ {
+ try
+ {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setLenient(false);
+ calendar.setTimeZone(getTimeZoneForOffset(valueString, 10));
+ calendar.set(year, month, day, hour, minute, second);
+ calendar.set(Calendar.MILLISECOND, 0);
+ return calendar.getTimeInMillis();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ // This should only happen if the provided date wasn't legal
+ // (e.g., September 31).
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME;
+ String message = getMessage(msgID, valueString, String.valueOf(e));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID, e);
+ }
+ }
+ else
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
+ String message = getMessage(msgID, valueString, m1, 10);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+ case '.':
+ case ',':
+ return finishDecodingFraction(valueString, 11, year, month, day, hour,
+ minute, second, 3600000);
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
+ String message = getMessage(msgID, valueString, m1, 10);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+
+ // Next, there should be either two digits comprising an integer between 00
+ // and 60 (for the second, including a possible leap second), a letter 'Z'
+ // (for the UTC specifier), a plus or minus sign followed by two or four
+ // digits (for the UTC offset), or a period or comma to start the fraction.
+ char s1 = valueString.charAt(12);
+ switch (s1)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ // There must be at least two more characters, and the next one must
+ // be a digit between 0 and 9.
+ if (length < 15)
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
+ String message = getMessage(msgID, valueString, s1, 12);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+
+ second = 10 * (s1 - '0');
+
+ switch (valueString.charAt(13))
+ {
+ case '0':
+ break;
+
+ case '1':
+ second += 1;
+ break;
+
+ case '2':
+ second += 2;
+ break;
+
+ case '3':
+ second += 3;
+ break;
+
+ case '4':
+ second += 4;
+ break;
+
+ case '5':
+ second += 5;
+ break;
+
+ case '6':
+ second += 6;
+ break;
+
+ case '7':
+ second += 7;
+ break;
+
+ case '8':
+ second += 8;
+ break;
+
+ case '9':
+ second += 9;
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(12, 14));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+ break;
+
+ case '6':
+ // There must be at least two more characters and the next one must be
+ // a 0.
+ if (length < 15)
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
+ String message = getMessage(msgID, valueString, s1, 12);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+ if (valueString.charAt(13) != '0')
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SECOND;
+ String message = getMessage(msgID, valueString,
+ valueString.substring(12, 14));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+ second = 60;
+ break;
+
+ case 'Z':
+ // This is fine only if we are at the end of the value.
+ if (length == 13)
+ {
+ try
+ {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setLenient(false);
+ calendar.setTimeZone(TimeZone.getTimeZone(TIME_ZONE_UTC));
+ calendar.set(year, month, day, hour, minute, second);
+ calendar.set(Calendar.MILLISECOND, 0);
+ return calendar.getTimeInMillis();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ // This should only happen if the provided date wasn't legal
+ // (e.g., September 31).
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME;
+ String message = getMessage(msgID, valueString, String.valueOf(e));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID, e);
+ }
+ }
+ else
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
+ String message = getMessage(msgID, valueString, s1, 12);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+ case '+':
+ case '-':
+ // These are fine only if there are exactly two or four more digits that
+ // specify a valid offset.
+ if ((length == 15) || (length == 17))
+ {
+ try
+ {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setLenient(false);
+ calendar.setTimeZone(getTimeZoneForOffset(valueString, 12));
+ calendar.set(year, month, day, hour, minute, second);
+ calendar.set(Calendar.MILLISECOND, 0);
+ return calendar.getTimeInMillis();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ // This should only happen if the provided date wasn't legal
+ // (e.g., September 31).
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME;
+ String message = getMessage(msgID, valueString, String.valueOf(e));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID, e);
+ }
+ }
+ else
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
+ String message = getMessage(msgID, valueString, s1, 12);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+ case '.':
+ case ',':
+ return finishDecodingFraction(valueString, 13, year, month, day, hour,
+ minute, second, 60000);
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
+ String message = getMessage(msgID, valueString, s1, 12);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+
+ // Next, there should be either a period or comma followed by between one
+ // and three digits (to specify the sub-second), a letter 'Z' (for the UTC
+ // specifier), or a plus or minus sign followed by two our four digits (for
+ // the UTC offset).
+ switch (valueString.charAt(14))
+ {
+ case '.':
+ case ',':
+ return finishDecodingFraction(valueString, 15, year, month, day, hour,
+ minute, second, 1000);
+
+ case 'Z':
+ // This is fine only if we are at the end of the value.
+ if (length == 15)
+ {
+ try
+ {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setLenient(false);
+ calendar.setTimeZone(TimeZone.getTimeZone(TIME_ZONE_UTC));
+ calendar.set(year, month, day, hour, minute, second);
+ calendar.set(Calendar.MILLISECOND, 0);
+ return calendar.getTimeInMillis();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ // This should only happen if the provided date wasn't legal
+ // (e.g., September 31).
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME;
+ String message = getMessage(msgID, valueString, String.valueOf(e));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID, e);
+ }
+ }
+ else
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
+ String message = getMessage(msgID, valueString,
+ valueString.charAt(14), 14);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+ case '+':
+ case '-':
+ // These are fine only if there are exactly two or four more digits that
+ // specify a valid offset.
+ if ((length == 17) || (length == 19))
+ {
+ try
+ {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setLenient(false);
+ calendar.setTimeZone(getTimeZoneForOffset(valueString, 14));
+ calendar.set(year, month, day, hour, minute, second);
+ calendar.set(Calendar.MILLISECOND, 0);
+ return calendar.getTimeInMillis();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ // This should only happen if the provided date wasn't legal
+ // (e.g., September 31).
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME;
+ String message = getMessage(msgID, valueString, String.valueOf(e));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID, e);
+ }
+ }
+ else
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
+ String message = getMessage(msgID, valueString,
+ valueString.charAt(14), 14);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR;
+ String message = getMessage(msgID, valueString, valueString.charAt(14),
+ 14);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ }
+
+
+
+ /**
+ * Completes decoding the generalized time value containing a fractional
+ * component. It will also decode the trailing 'Z' or offset.
+ *
+ * @param value The whole value, including the fractional component and
+ * time zone information.
+ * @param startPos The position of the first character after the period
+ * in the value string.
+ * @param year The year decoded from the provided value.
+ * @param month The month decoded from the provided value.
+ * @param day The day decoded from the provided value.
+ * @param hour The hour decoded from the provided value.
+ * @param minute The minute decoded from the provided value.
+ * @param second The second decoded from the provided value.
+ * @param multiplier The multiplier value that should be used to scale the
+ * fraction appropriately. If it's a fraction of an hour,
+ * then it should be 3600000 (60*60*1000). If it's a
+ * fraction of a minute, then it should be 60000. If it's
+ * a fraction of a second, then it should be 1000.
+ *
+ * @return The timestamp created from the provided generalized time value
+ * including the fractional element.
+ *
+ * @throws DirectoryException If the provided value cannot be parsed as a
+ * valid generalized time string.
+ */
+ private static long finishDecodingFraction(String value, int startPos,
+ int year, int month, int day,
+ int hour, int minute, int second,
+ int multiplier)
+ throws DirectoryException
+ {
+ int length = value.length();
+ StringBuilder fractionBuffer = new StringBuilder(2 + length - startPos);
+ fractionBuffer.append("0.");
+
+ TimeZone timeZone = null;
+
+outerLoop:
+ for (int i=startPos; i < length; i++)
+ {
+ char c = value.charAt(i);
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ fractionBuffer.append(c);
+ break;
+
+ case 'Z':
+ // This is only acceptable if we're at the end of the value.
+ if (i != (value.length() - 1))
+ {
+ int msgID =
+ MSGID_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR;
+ String message = getMessage(msgID, value, String.valueOf(c));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+ timeZone = TimeZone.getTimeZone(TIME_ZONE_UTC);
+ break outerLoop;
+
+ case '+':
+ case '-':
+ timeZone = getTimeZoneForOffset(value, i);
+ break outerLoop;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR;
+ String message = getMessage(msgID, value, String.valueOf(c));
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ }
+
+ if (fractionBuffer.length() == 2)
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_EMPTY_FRACTION;
+ String message = getMessage(msgID, value);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
+ msgID);
+ }
+
+ if (timeZone == null)
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_NO_TIME_ZONE_INFO;
+ String message = getMessage(msgID, value);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
+ msgID);
+ }
+
+ Double fractionValue = Double.parseDouble(fractionBuffer.toString());
+ long additionalMilliseconds = Math.round(fractionValue * multiplier);
+
try
{
- dateFormatLock.lock();
-
- try
- {
- return dateFormat.parse(valueString).getTime();
- }
- catch (Exception e)
- {
- // We'll let this one be handled by the outer try/catch block.
- throw e;
- }
- finally
- {
- dateFormatLock.unlock();
- }
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setLenient(false);
+ calendar.setTimeZone(timeZone);
+ calendar.set(year, month, day, hour, minute, second);
+ calendar.set(Calendar.MILLISECOND, 0);
+ return calendar.getTimeInMillis() + additionalMilliseconds;
}
catch (Exception e)
{
@@ -1123,12 +1471,160 @@
debugCaught(DebugLogLevel.ERROR, e);
}
- int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE;
- String message = getMessage(msgID, valueString, String.valueOf(e));
-
+ // This should only happen if the provided date wasn't legal
+ // (e.g., September 31).
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME;
+ String message = getMessage(msgID, value, String.valueOf(e));
throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
message, msgID, e);
}
}
+
+
+
+ /**
+ * Decodes a time zone offset from the provided value.
+ *
+ * @param value The whole value, including the offset.
+ * @param startPos The position of the first character that is
+ * contained in the offset. This should be the
+ * position of the plus or minus character.
+ *
+ * @return The {@code TimeZone} object representing the decoded time zone.
+ *
+ * @throws DirectoryException If the provided value does not contain a valid
+ * offset.
+ */
+ private static TimeZone getTimeZoneForOffset(String value, int startPos)
+ throws DirectoryException
+ {
+ String offSetStr = value.substring(startPos);
+ if ((offSetStr.length() != 3) && (offSetStr.length() != 5))
+ {
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
+ String message = getMessage(msgID, value, offSetStr);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message,
+ msgID);
+ }
+
+
+ // The first character must be either a plus or minus.
+ switch (offSetStr.charAt(0))
+ {
+ case '+':
+ case '-':
+ // These are OK.
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
+ String message = getMessage(msgID, value, offSetStr);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+
+ // The first two characters must be an integer between 00 and 23.
+ switch (offSetStr.charAt(1))
+ {
+ case '0':
+ case '1':
+ switch (offSetStr.charAt(2))
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ // These are all fine.
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
+ String message = getMessage(msgID, value, offSetStr);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ break;
+
+ case '2':
+ switch (offSetStr.charAt(2))
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ // These are all fine.
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
+ String message = getMessage(msgID, value, offSetStr);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
+ String message = getMessage(msgID, value, offSetStr);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+
+
+ // If there are two more characters, then they must be an integer between
+ // 00 and 59.
+ if (offSetStr.length() == 5)
+ {
+ switch (offSetStr.charAt(3))
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ switch (offSetStr.charAt(4))
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ // These are all fine.
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
+ String message = getMessage(msgID, value, offSetStr);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ break;
+
+ default:
+ int msgID = MSGID_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET;
+ String message = getMessage(msgID, value, offSetStr);
+ throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ message, msgID);
+ }
+ }
+
+
+ // If we've gotten here, then it looks like a valid offset. We can create a
+ // time zone by using "GMT" followed by the offset.
+ return TimeZone.getTimeZone("GMT" + offSetStr);
+ }
}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRuleTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRuleTest.java
index 201f56f..7cd4e24 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRuleTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/GeneralizedTimeEqualityMatchingRuleTest.java
@@ -52,6 +52,15 @@
{"2006090613mmZ"},
{"20060906135030.011"},
{"20060906135030Zx"},
+ {"20060906135030.Z"},
+ {"20060906135030.aZ"},
+ {"20060906135030"},
+ {"20060906135030.123"},
+ {"20060906135030-2500"},
+ {"20060906135030-2070"},
+ {"20060931135030Z"},
+ {"20060229135030Z"},
+ {"20060230135030Z"},
};
}
@@ -63,16 +72,20 @@
public Object[][] createEqualityMatchingRuleTest()
{
return new Object [][] {
- {"2006090613Z", "20060906130000.000Z", true},
- {"200609061350Z", "20060906135000.000Z", true},
- {"200609061351Z", "20060906135000.000Z", false},
- {"20060906135030Z", "20060906135030.000Z", true},
- {"20060906135030.3Z", "20060906135030.300Z", true},
- {"20060906135030.30Z", "20060906135030.300Z", true},
- {"20060906135030.Z", "20060906135030.000Z", true},
- {"20060906135030.0118Z", "20060906135030.012Z", true},
- {"20060906135030+01", "20060906125030.000Z", true},
- {"20060906135030+0101", "20060906124930.000Z", true},
+ {"2006090613Z", "20060906130000.000Z", true},
+ {"200609061350Z", "20060906135000.000Z", true},
+ {"200609061351Z", "20060906135000.000Z", false},
+ {"20060906135030Z", "20060906135030.000Z", true},
+ {"20060906135030.3Z", "20060906135030.300Z", true},
+ {"20060906135030.30Z", "20060906135030.300Z", true},
+ {"20060906135030Z", "20060906135030.000Z", true},
+ {"20060906135030.0Z", "20060906135030.000Z", true},
+ {"20060906135030.0118Z", "20060906135030.012Z", true},
+ {"20060906135030+01", "20060906125030.000Z", true},
+ {"20060906135030+0101", "20060906124930.000Z", true},
+ {"20070417055812.318-0500", "20070417105812.318Z", true},
+ {"2007041705.5Z", "20070417053000.000Z", true},
+ {"200704170558.5Z", "20070417055830.000Z", true},
};
}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRuleTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRuleTest.java
index e99d7e4..b66674f 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRuleTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRuleTest.java
@@ -56,11 +56,9 @@
{"20060912180129.1hZ"},
{"20060906135030+aa01"},
{"2006"},
- /* disabled because these tests are failing
- * see issue 675
- * {"20060906135030+3359"},
- * {"20060906135030+2389"},
- * {"20060906135030+2361"},*/
+ {"20060906135030+3359"},
+ {"20060906135030+2389"},
+ {"20060906135030+2361"},
{"20060906135030+"},
{"20060906135030+0"},
{"20060906135030+010"},
--
Gitblit v1.10.0