From e399742925d1a8a1ae3dae4a86bf25d3d02e8f9c Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Wed, 09 May 2012 15:28:30 +0000
Subject: [PATCH] Fix OPENDJ-355: Add fluent API for decoding attributes
---
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/GeneralizedTime.java | 594 ++++++++++++++++++++++++++++++++--------------------------
1 files changed, 326 insertions(+), 268 deletions(-)
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/GeneralizedTime.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/GeneralizedTime.java
similarity index 71%
rename from opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/GeneralizedTime.java
rename to opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/GeneralizedTime.java
index 953e92a..4dd8b96 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/GeneralizedTime.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/GeneralizedTime.java
@@ -23,7 +23,7 @@
*
* Copyright 2012 ForgeRock AS.
*/
-package com.forgerock.opendj.util;
+package org.forgerock.opendj.ldap;
import static org.forgerock.opendj.ldap.CoreMessages.*;
@@ -33,30 +33,88 @@
import java.util.TimeZone;
import org.forgerock.i18n.LocalizableMessage;
-import org.forgerock.opendj.ldap.ByteSequence;
-import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.i18n.LocalizedIllegalArgumentException;
+
+import com.forgerock.opendj.util.Validator;
/**
- * Utility class for encoding and decoding generalized time syntax values.
+ * An LDAP generalized time as defined in RFC 4517. This class facilitates
+ * parsing of generalized time values to and from {@link Date} and
+ * {@link Calendar} classes.
+ * <p>
+ * The following are examples of generalized time values:
+ *
+ * <pre>
+ * 199412161032Z
+ * 199412160532-0500
+ * </pre>
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4517#section-3.3.13">RFC 4517 -
+ * Lightweight Directory Access Protocol (LDAP): Syntaxes and Matching
+ * Rules </a>
*/
-public final class GeneralizedTime {
+public final class GeneralizedTime implements Comparable<GeneralizedTime> {
// UTC TimeZone is assumed to never change over JVM lifetime
private static final TimeZone TIME_ZONE_UTC_OBJ = TimeZone.getTimeZone("UTC");
/**
- * Returns the provided generalized time syntax value decoded as a
- * {@code Calendar}.
+ * Returns a generalized time representing the provided {@code Calendar}.
+ * <p>
+ * The provided calendar will be defensively copied in order to preserve
+ * immutability.
*
- * @param value
- * The generalized time value to be decoded.
- * @return The decoded {@code Calendar}.
- * @throws DecodeException
- * If the provided value cannot be parsed as a valid generalized
- * time string.
+ * @param calendar
+ * The calendar to be converted to a generalized time.
+ * @return A generalized time representing the provided {@code Calendar}.
*/
- public static Calendar decode(final ByteSequence value) throws DecodeException {
+ public static GeneralizedTime valueOf(final Calendar calendar) {
+ Validator.ensureNotNull(calendar);
+ return new GeneralizedTime((Calendar) calendar.clone(), null, -1L, null);
+ }
+
+ /**
+ * Returns a generalized time representing the provided {@code Date}.
+ * <p>
+ * The provided date will be defensively copied in order to preserve
+ * immutability.
+ *
+ * @param date
+ * The date to be converted to a generalized time.
+ * @return A generalized time representing the provided {@code Date}.
+ */
+ public static GeneralizedTime valueOf(final Date date) {
+ Validator.ensureNotNull(date);
+ return new GeneralizedTime(null, (Date) date.clone(), -1L, null);
+ }
+
+ /**
+ * Returns a generalized time representing the provided time in milliseconds
+ * since the epoch.
+ *
+ * @param timeMS
+ * The time to be converted to a generalized time.
+ * @return A generalized time representing the provided time in milliseconds
+ * since the epoch.
+ */
+ public static GeneralizedTime valueOf(final long timeMS) {
+ Validator.ensureTrue(timeMS >= 0, "timeMS must be >= 0");
+ return new GeneralizedTime(null, null, timeMS, null);
+ }
+
+ /**
+ * Parses the provided string as an LDAP generalized time.
+ *
+ * @param time
+ * The generalized time value to be parsed.
+ * @return The parsed generalized time.
+ * @throws LocalizedIllegalArgumentException
+ * If {@code time} cannot be parsed as a valid generalized time
+ * string.
+ * @throws NullPointerException
+ * If {@code time} was {@code null}.
+ */
+ public static GeneralizedTime valueOf(final String time) {
int year = 0;
int month = 0;
int day = 0;
@@ -66,14 +124,12 @@
// Get the value as a string and verify that it is at least long
// enough for "YYYYMMDDhhZ", which is the shortest allowed value.
- final String valueString = value.toString().toUpperCase();
+ final String valueString = time.toUpperCase();
final int length = valueString.length();
if (length < 11) {
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT.get(valueString);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
// The first four characters are the century and year, and they must
@@ -124,9 +180,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_YEAR.get(valueString, String
.valueOf(valueString.charAt(i)));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
}
@@ -178,9 +232,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH.get(valueString,
valueString.substring(4, 6));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
case '1':
@@ -202,18 +254,14 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH.get(valueString,
valueString.substring(4, 6));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
default:
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH.get(valueString, valueString
.substring(4, 6));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
// The next two characters should be the day of the month, and they
@@ -267,9 +315,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY.get(valueString, valueString
.substring(6, 8));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
@@ -320,9 +366,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY.get(valueString, valueString
.substring(6, 8));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
@@ -373,9 +417,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY.get(valueString, valueString
.substring(6, 8));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
@@ -394,9 +436,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY.get(valueString, valueString
.substring(6, 8));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
@@ -404,9 +444,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY.get(valueString, valueString
.substring(6, 8));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
// The next two characters must be the hour, and they must form the
@@ -460,9 +498,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR.get(valueString, valueString
.substring(8, 10));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
@@ -512,9 +548,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR.get(valueString, valueString
.substring(8, 10));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
@@ -540,9 +574,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR.get(valueString, valueString
.substring(8, 10));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
@@ -550,9 +582,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR.get(valueString, valueString
.substring(8, 10));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
// Next, there should be either two digits comprising an integer
@@ -574,9 +604,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR.get(valueString, String
.valueOf(m1), 10);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
minute = 10 * (m1 - '0');
@@ -625,9 +653,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE.get(valueString,
valueString.substring(10, 12));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
@@ -641,9 +667,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR.get(valueString, String
.valueOf(m1), 10);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
case '+':
@@ -657,9 +681,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR.get(valueString, String
.valueOf(m1), 10);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
case '.':
@@ -671,9 +693,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR.get(valueString, String
.valueOf(m1), 10);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
// Next, there should be either two digits comprising an integer
@@ -695,9 +715,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR.get(valueString, String
.valueOf(s1), 12);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
second = 10 * (s1 - '0');
@@ -746,9 +764,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE.get(valueString,
valueString.substring(12, 14));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
@@ -760,18 +776,14 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR.get(valueString, String
.valueOf(s1), 12);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
if (valueString.charAt(13) != '0') {
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SECOND.get(valueString,
valueString.substring(12, 14));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
second = 60;
@@ -786,9 +798,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR.get(valueString, String
.valueOf(s1), 12);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
case '+':
@@ -802,9 +812,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR.get(valueString, String
.valueOf(s1), 12);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
case '.':
@@ -816,9 +824,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR.get(valueString, String
.valueOf(s1), 12);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
// Next, there should be either a period or comma followed by
@@ -840,9 +846,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR.get(valueString, String
.valueOf(valueString.charAt(14)), 14);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
case '+':
@@ -856,129 +860,19 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR.get(valueString, String
.valueOf(valueString.charAt(14)), 14);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
default:
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR.get(valueString, String
.valueOf(valueString.charAt(14)), 14);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
}
/**
- * Returns the generalized time syntax encoding of the provided
- * {@code Calendar}.
- *
- * @param value
- * The calendar to be encoded.
- * @return The generalized time syntax encoding.
- */
- public static ByteString encode(final Calendar value) {
- return encode(value.getTimeInMillis());
- }
-
- /**
- * Returns the generalized time syntax encoding of the provided {@code Date}
- * .
- *
- * @param value
- * The date to be encoded.
- * @return The generalized time syntax encoding.
- */
- public static ByteString encode(final Date value) {
- return encode(value.getTime());
- }
-
- /**
- * Returns the generalized time syntax encoding of the provided date
- * represented as milliseconds since the epoch.
- *
- * @param value
- * The date in milli-seconds since the epoch.
- * @return The generalized time syntax encoding.
- */
- public static ByteString encode(final long value) {
- // Generalized time has the format yyyyMMddHHmmss.SSS'Z'
-
- // Do this in a thread-safe non-synchronized fashion.
- // (Simple)DateFormat is neither fast nor thread-safe.
- final StringBuilder sb = new StringBuilder(19);
- final GregorianCalendar calendar = new GregorianCalendar(TIME_ZONE_UTC_OBJ);
- calendar.setLenient(false);
- calendar.setTimeInMillis(value);
-
- // Format the year yyyy.
- int n = calendar.get(Calendar.YEAR);
- if (n < 0) {
- throw new IllegalArgumentException("Year cannot be < 0:" + n);
- } else if (n < 10) {
- sb.append("000");
- } else if (n < 100) {
- sb.append("00");
- } else if (n < 1000) {
- sb.append("0");
- }
- sb.append(n);
-
- // Format the month MM.
- n = calendar.get(Calendar.MONTH) + 1;
- if (n < 10) {
- sb.append("0");
- }
- sb.append(n);
-
- // Format the day dd.
- n = calendar.get(Calendar.DAY_OF_MONTH);
- if (n < 10) {
- sb.append("0");
- }
- sb.append(n);
-
- // Format the hour HH.
- n = calendar.get(Calendar.HOUR_OF_DAY);
- if (n < 10) {
- sb.append("0");
- }
- sb.append(n);
-
- // Format the minute mm.
- n = calendar.get(Calendar.MINUTE);
- if (n < 10) {
- sb.append("0");
- }
- sb.append(n);
-
- // Format the seconds ss.
- n = calendar.get(Calendar.SECOND);
- if (n < 10) {
- sb.append("0");
- }
- sb.append(n);
-
- // Format the milli-seconds.
- sb.append('.');
- n = calendar.get(Calendar.MILLISECOND);
- if (n < 10) {
- sb.append("00");
- } else if (n < 100) {
- sb.append("0");
- }
- sb.append(n);
-
- // Format the timezone (always Z).
- sb.append('Z');
-
- return ByteString.valueOf(sb.toString());
- }
-
- /**
- * Returns a Calendar object representing the provided date / time
+ * Returns a generalized time object representing the provided date / time
* parameters.
*
* @param value
@@ -997,29 +891,26 @@
* The second.
* @param tz
* The timezone.
- * @return A Calendar object representing the provided date / time
+ * @return A generalized time representing the provided date / time
* parameters.
- * @throws DecodeException
- * If the calendar could not be created.
+ * @throws LocalizedIllegalArgumentException
+ * If the generalized time could not be created.
*/
- private static Calendar createTime(final String value, final int year, final int month,
- final int day, final int hour, final int minute, final int second, final TimeZone tz)
- throws DecodeException {
+ private static GeneralizedTime createTime(final String value, final int year, final int month,
+ final int day, final int hour, final int minute, final int second, final TimeZone tz) {
try {
final GregorianCalendar calendar = new GregorianCalendar();
calendar.setLenient(false);
calendar.setTimeZone(tz);
calendar.set(year, month, day, hour, minute, second);
calendar.set(Calendar.MILLISECOND, 0);
- return calendar;
+ return new GeneralizedTime(calendar, null, -1L, value);
} catch (final Exception e) {
// This should only happen if the provided date wasn't legal
// (e.g., September 31).
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME.get(value, String.valueOf(e));
- final DecodeException de = DecodeException.error(message, e);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", de);
- throw de;
+ throw new LocalizedIllegalArgumentException(message, e);
}
}
@@ -1053,13 +944,13 @@
* should be 1000.
* @return The timestamp created from the provided generalized time value
* including the fractional element.
- * @throws DecodeException
+ * @throws LocalizedIllegalArgumentException
* If the provided value cannot be parsed as a valid generalized
* time string.
*/
- private static Calendar finishDecodingFraction(final String value, final int startPos,
+ private static GeneralizedTime finishDecodingFraction(final String value, final int startPos,
final int year, final int month, final int day, final int hour, final int minute,
- final int second, final int multiplier) throws DecodeException {
+ final int second, final int multiplier) {
final int length = value.length();
final StringBuilder fractionBuffer = new StringBuilder((2 + length) - startPos);
fractionBuffer.append("0.");
@@ -1089,10 +980,7 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR.get(value,
String.valueOf(c));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
- "finishDecodingFraction", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
timeZone = TIME_ZONE_UTC_OBJ;
@@ -1107,27 +995,20 @@
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR.get(value, String
.valueOf(c));
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG
- .throwing("GeneralizedTimeSyntax", "finishDecodingFraction", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
}
if (fractionBuffer.length() == 2) {
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_EMPTY_FRACTION.get(value);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "finishDecodingFraction", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
if (timeZone == null) {
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_NO_TIME_ZONE_INFO.get(value);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "finishDecodingFraction", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
final Double fractionValue = Double.parseDouble(fractionBuffer.toString());
@@ -1139,16 +1020,13 @@
calendar.setTimeZone(timeZone);
calendar.set(year, month, day, hour, minute, second);
calendar.set(Calendar.MILLISECOND, additionalMilliseconds);
- return calendar;
+ return new GeneralizedTime(calendar, null, -1L, value);
} catch (final Exception e) {
-
// This should only happen if the provided date wasn't legal
// (e.g., September 31).
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME.get(value, String.valueOf(e));
- final DecodeException de = DecodeException.error(message, e);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "valueIsAcceptable", de);
- throw de;
+ throw new LocalizedIllegalArgumentException(message, e);
}
}
@@ -1165,15 +1043,12 @@
* @throws DecodeException
* If the provided value does not contain a valid offset.
*/
- private static TimeZone getTimeZoneForOffset(final String value, final int startPos)
- throws DecodeException {
+ private static TimeZone getTimeZoneForOffset(final String value, final int startPos) {
final String offSetStr = value.substring(startPos);
if ((offSetStr.length() != 3) && (offSetStr.length() != 5)) {
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET.get(value, offSetStr);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "getTimeZoneForOffset", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
// The first character must be either a plus or minus.
@@ -1186,9 +1061,7 @@
default:
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET.get(value, offSetStr);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "getTimeZoneForOffset", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
// The first two characters must be an integer between 00 and 23.
@@ -1212,9 +1085,7 @@
default:
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET.get(value, offSetStr);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "getTimeZoneForOffset", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
@@ -1230,18 +1101,14 @@
default:
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET.get(value, offSetStr);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "getTimeZoneForOffset", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
default:
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET.get(value, offSetStr);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "getTimeZoneForOffset", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
// If there are two more characters, then they must be an integer
@@ -1271,19 +1138,14 @@
default:
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET.get(value, offSetStr);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "getTimeZoneForOffset",
- e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
break;
default:
final LocalizableMessage message =
WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET.get(value, offSetStr);
- final DecodeException e = DecodeException.error(message);
- StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "getTimeZoneForOffset", e);
- throw e;
+ throw new LocalizedIllegalArgumentException(message);
}
}
@@ -1292,8 +1154,204 @@
return TimeZone.getTimeZone("GMT" + offSetStr);
}
- private GeneralizedTime() {
- // Prevent instantiation.
+ // Lazily constructed internal representations.
+ private volatile Calendar calendar;
+ private volatile Date date;
+ private volatile String stringValue;
+ private volatile long timeMS;
+
+ private GeneralizedTime(final Calendar calendar, final Date date, final long time,
+ final String stringValue) {
+ this.calendar = calendar;
+ this.date = date;
+ this.timeMS = time;
+ this.stringValue = stringValue;
}
+ /**
+ * {@inheritDoc}
+ */
+ public int compareTo(final GeneralizedTime o) {
+ final Long timeMS1 = getTimeInMillis();
+ final Long timeMS2 = o.getTimeInMillis();
+ return timeMS1.compareTo(timeMS2);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ } else if (obj instanceof GeneralizedTime) {
+ return getTimeInMillis() == ((GeneralizedTime) obj).getTimeInMillis();
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the value of this generalized time in milliseconds since the
+ * epoch.
+ *
+ * @return The value of this generalized time in milliseconds since the
+ * epoch.
+ */
+ public long getTimeInMillis() {
+ long tmpTimeMS = timeMS;
+ if (tmpTimeMS == -1) {
+ if (date != null) {
+ tmpTimeMS = date.getTime();
+ } else {
+ tmpTimeMS = calendar.getTimeInMillis();
+ }
+ timeMS = tmpTimeMS;
+ }
+ return tmpTimeMS;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ return ((Long) getTimeInMillis()).hashCode();
+ }
+
+ /**
+ * Returns a {@code Calendar} representation of this generalized time.
+ * <p>
+ * Subsequent modifications to the returned calendar will not alter the
+ * internal state of this generalized time.
+ *
+ * @return A {@code Calendar} representation of this generalized time.
+ */
+ public Calendar toCalendar() {
+ Calendar tmpCalendar = calendar;
+ if (tmpCalendar == null) {
+ tmpCalendar = new GregorianCalendar(TIME_ZONE_UTC_OBJ);
+ tmpCalendar.setLenient(false);
+ tmpCalendar.setTimeInMillis(getTimeInMillis());
+ calendar = tmpCalendar;
+ }
+ return (Calendar) tmpCalendar.clone();
+ }
+
+ /**
+ * Returns a {@code Date} representation of this generalized time.
+ * <p>
+ * Subsequent modifications to the returned date will not alter the internal
+ * state of this generalized time.
+ *
+ * @return A {@code Date} representation of this generalized time.
+ */
+ public Date toDate() {
+ Date tmpDate = date;
+ if (tmpDate == null) {
+ tmpDate = new Date(getTimeInMillis());
+ date = tmpDate;
+ }
+ return (Date) tmpDate.clone();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String toString() {
+ String tmpString = stringValue;
+ if (tmpString == null) {
+ // Do this in a thread-safe non-synchronized fashion.
+ // (Simple)DateFormat is neither fast nor thread-safe.
+ final StringBuilder sb = new StringBuilder(19);
+ final Calendar tmpCalendar = toCalendar();
+
+ // Format the year yyyy.
+ int n = tmpCalendar.get(Calendar.YEAR);
+ if (n < 0) {
+ throw new IllegalArgumentException("Year cannot be < 0:" + n);
+ } else if (n < 10) {
+ sb.append("000");
+ } else if (n < 100) {
+ sb.append("00");
+ } else if (n < 1000) {
+ sb.append("0");
+ }
+ sb.append(n);
+
+ // Format the month MM.
+ n = tmpCalendar.get(Calendar.MONTH) + 1;
+ if (n < 10) {
+ sb.append("0");
+ }
+ sb.append(n);
+
+ // Format the day dd.
+ n = tmpCalendar.get(Calendar.DAY_OF_MONTH);
+ if (n < 10) {
+ sb.append("0");
+ }
+ sb.append(n);
+
+ // Format the hour HH.
+ n = tmpCalendar.get(Calendar.HOUR_OF_DAY);
+ if (n < 10) {
+ sb.append("0");
+ }
+ sb.append(n);
+
+ // Format the minute mm.
+ n = tmpCalendar.get(Calendar.MINUTE);
+ if (n < 10) {
+ sb.append("0");
+ }
+ sb.append(n);
+
+ // Format the seconds ss.
+ n = tmpCalendar.get(Calendar.SECOND);
+ if (n < 10) {
+ sb.append("0");
+ }
+ sb.append(n);
+
+ // Format the milli-seconds.
+ n = tmpCalendar.get(Calendar.MILLISECOND);
+ if (n != 0) {
+ sb.append('.');
+ if (n < 10) {
+ sb.append("00");
+ } else if (n < 100) {
+ sb.append("0");
+ }
+ sb.append(n);
+ }
+
+ // Format the timezone.
+ n = tmpCalendar.get(Calendar.ZONE_OFFSET); /* ms */
+ if (n == 0) {
+ sb.append('Z');
+ } else {
+ if (n < 0) {
+ sb.append('-');
+ n = -n;
+ } else {
+ sb.append('+');
+ }
+ n = n / 60000; // Minutes.
+
+ final int h = n / 60;
+ if (h < 10) {
+ sb.append("0");
+ }
+ sb.append(h);
+
+ final int m = n % 60;
+ if (m < 10) {
+ sb.append("0");
+ }
+ sb.append(m);
+ }
+ tmpString = sb.toString();
+ stringValue = tmpString;
+ }
+ return stringValue;
+ }
}
--
Gitblit v1.10.0