From c5ff2497147025d89987b2554267c9ee6b449467 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.
---
opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java | 707 +++-------------------------------------------------------
1 files changed, 38 insertions(+), 669 deletions(-)
diff --git a/opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java b/opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java
index 7b8148f..e99d558 100644
--- a/opends/src/server/org/opends/server/schema/GeneralizedTimeOrderingMatchingRule.java
+++ b/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));
}
}
--
Gitblit v1.10.0