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/com/forgerock/opendj/util/Functions.java | 435 +++++++++----
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeEqualityMatchingRuleImpl.java | 10
opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core.properties | 4
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/GeneralizedTimeTest.java | 132 ++++
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeParser.java | 194 +++--
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AttributeParserTestCase.java | 360 ++++++++++++
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/GeneralizedTime.java | 594 ++++++++++--------
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeOrderingMatchingRuleImpl.java | 10
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeSyntaxImpl.java | 11
9 files changed, 1,251 insertions(+), 499 deletions(-)
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Functions.java b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Functions.java
index 64c21f8..87302c0 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Functions.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Functions.java
@@ -27,13 +27,16 @@
package com.forgerock.opendj.util;
-import java.util.Calendar;
+import static org.forgerock.opendj.ldap.CoreMessages.FUNCTIONS_TO_INTEGER_FAIL;
+import static org.forgerock.opendj.ldap.CoreMessages.FUNCTIONS_TO_LONG_FAIL;
+import static org.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN;
+import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.AttributeDescription;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DN;
-import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.GeneralizedTime;
import org.forgerock.opendj.ldap.schema.Schema;
/**
@@ -60,28 +63,45 @@
}
- private static final Function<ByteString, AttributeDescription, Schema> BYTESTRING_TO_ATTRIBUTE_DESCRIPTION =
- new Function<ByteString, AttributeDescription, Schema>() {
-
- public AttributeDescription apply(final ByteString value, final Schema p) {
- // FIXME: what should we do if parsing fails?
- return AttributeDescription.valueOf(value.toString(), p);
- }
- };
-
- private static final Function<ByteString, String, Void> BYTESTRING_TO_BASE64 =
+ private static final Function<ByteString, String, Void> BYTESTRING_TO_STRING =
new Function<ByteString, String, Void>() {
-
public String apply(final ByteString value, final Void p) {
- return Base64.encode(value);
+ return value.toString();
}
};
- private static final Function<ByteString, Boolean, Void> BYTESTRING_TO_BOOLEAN =
- new Function<ByteString, Boolean, Void>() {
+ private static final Function<Object, Object, Void> IDENTITY =
+ new Function<Object, Object, Void>() {
+ public Object apply(final Object value, final Void p) {
+ return value;
+ }
+ };
- public Boolean apply(final ByteString value, final Void p) {
- final String valueString = StaticUtils.toLowerCase(value.toString());
+ private static final Function<String, String, Void> NORMALIZE_STRING =
+ new Function<String, String, Void>() {
+ public String apply(final String value, final Void p) {
+ return StaticUtils.toLowerCase(value).trim();
+ }
+ };
+
+ private static final Function<Object, ByteString, Void> OBJECT_TO_BYTESTRING =
+ new Function<Object, ByteString, Void>() {
+ public ByteString apply(final Object value, final Void p) {
+ return ByteString.valueOf(value);
+ }
+ };
+
+ private static final Function<String, AttributeDescription, Schema> STRING_TO_ATTRIBUTE_DESCRIPTION =
+ new Function<String, AttributeDescription, Schema>() {
+ public AttributeDescription apply(final String value, final Schema p) {
+ return AttributeDescription.valueOf(value, p);
+ }
+ };
+
+ private static final Function<String, Boolean, Void> STRING_TO_BOOLEAN =
+ new Function<String, Boolean, Void>() {
+ public Boolean apply(final String value, final Void p) {
+ final String valueString = StaticUtils.toLowerCase(value);
if (valueString.equals("true") || valueString.equals("yes")
|| valueString.equals("on") || valueString.equals("1")) {
@@ -90,86 +110,159 @@
|| valueString.equals("off") || valueString.equals("0")) {
return Boolean.FALSE;
} else {
- throw new NumberFormatException("Invalid boolean value \"" + valueString
- + "\"");
+ final LocalizableMessage message =
+ WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN.get(valueString);
+ throw new LocalizedIllegalArgumentException(message);
}
}
};
- private static final Function<ByteString, Calendar, Void> BYTESTRING_TO_CALENDAR =
- new Function<ByteString, Calendar, Void>() {
+ private static final Function<String, DN, Schema> STRING_TO_DN =
+ new Function<String, DN, Schema>() {
+ public DN apply(final String value, final Schema p) {
+ return DN.valueOf(value, p);
+ }
+ };
- public Calendar apply(final ByteString value, final Void p) {
+ private static final Function<String, GeneralizedTime, Void> STRING_TO_GENERALIZED_TIME =
+ new Function<String, GeneralizedTime, Void>() {
+ public GeneralizedTime apply(final String value, final Void p) {
+ return GeneralizedTime.valueOf(value);
+ }
+ };
+
+ private static final Function<String, Integer, Void> STRING_TO_INTEGER =
+ new Function<String, Integer, Void>() {
+ public Integer apply(final String value, final Void p) {
try {
- return GeneralizedTime.decode(value);
- } catch (DecodeException e) {
- throw new LocalizedIllegalArgumentException(e.getMessageObject(), e);
+ return Integer.valueOf(value);
+ } catch (final NumberFormatException e) {
+ final LocalizableMessage message = FUNCTIONS_TO_INTEGER_FAIL.get(value);
+ throw new LocalizedIllegalArgumentException(message);
}
}
};
- private static final Function<ByteString, DN, Schema> BYTESTRING_TO_DN =
- new Function<ByteString, DN, Schema>() {
-
- public DN apply(final ByteString value, final Schema p) {
- // FIXME: what should we do if parsing fails?
-
- // FIXME: we should have a ByteString valueOf
- // implementation.
- return DN.valueOf(value.toString(), p);
+ private static final Function<String, Long, Void> STRING_TO_LONG =
+ new Function<String, Long, Void>() {
+ public Long apply(final String value, final Void p) {
+ try {
+ return Long.valueOf(value);
+ } catch (final NumberFormatException e) {
+ final LocalizableMessage message = FUNCTIONS_TO_LONG_FAIL.get(value);
+ throw new LocalizedIllegalArgumentException(message);
+ }
}
};
- private static final Function<ByteString, Integer, Void> BYTESTRING_TO_INTEGER =
- new Function<ByteString, Integer, Void>() {
+ private static final Function<ByteString, AttributeDescription, Schema> BYTESTRING_TO_ATTRIBUTE_DESCRIPTION =
+ composeSecondP(valueToString(), STRING_TO_ATTRIBUTE_DESCRIPTION);
- public Integer apply(final ByteString value, final Void p) {
- // We do not use ByteString.toInt() as we are string based.
- return Integer.valueOf(value.toString());
- }
+ private static final Function<ByteString, Boolean, Void> BYTESTRING_TO_BOOLEAN = compose(
+ valueToString(), STRING_TO_BOOLEAN);
+
+ private static final Function<ByteString, DN, Schema> BYTESTRING_TO_DN = composeSecondP(
+ valueToString(), STRING_TO_DN);
+
+ private static final Function<ByteString, GeneralizedTime, Void> BYTESTRING_TO_GENERALIZED_TIME =
+ compose(valueToString(), STRING_TO_GENERALIZED_TIME);
+
+ private static final Function<ByteString, Integer, Void> BYTESTRING_TO_INTEGER = compose(
+ valueToString(), STRING_TO_INTEGER);
+
+ private static final Function<ByteString, Long, Void> BYTESTRING_TO_LONG = compose(
+ valueToString(), STRING_TO_LONG);
+
+ /**
+ * Returns the composition of two functions. The result of the first
+ * function will be passed to the second.
+ *
+ * @param <M>
+ * The type of input values transformed by this function.
+ * @param <N>
+ * The type of output values returned by this function.
+ * @param <X>
+ * The type of intermediate values passed between the two
+ * functions.
+ * @param first
+ * The first function which will consume the input.
+ * @param second
+ * The second function which will produce the result.
+ * @return The composition.
+ */
+ public static <M, X, N> Function<M, N, Void> compose(final Function<M, X, Void> first,
+ final Function<X, N, Void> second) {
+ return new Function<M, N, Void>() {
+ public N apply(final M value, final Void p) {
+ final X tmp = first.apply(value, p);
+ return second.apply(tmp, p);
};
+ };
+ }
- private static final Function<ByteString, Long, Void> BYTESTRING_TO_LONG =
- new Function<ByteString, Long, Void>() {
-
- public Long apply(final ByteString value, final Void p) {
- // We do not use ByteString.toLong() as we are string based.
- return Long.valueOf(value.toString());
- }
+ /**
+ * Returns the composition of two functions. The result of the first
+ * function will be passed to the second. The first function will be passed
+ * an additional parameter.
+ *
+ * @param <M>
+ * The type of input values transformed by this function.
+ * @param <N>
+ * The type of output values returned by this function.
+ * @param <X>
+ * The type of intermediate values passed between the two
+ * functions.
+ * @param <P>
+ * The type of the additional parameter to the first function's
+ * {@code apply} method. Use {@link java.lang.Void} for functions
+ * that do not need an additional parameter.
+ * @param first
+ * The first function which will consume the input.
+ * @param second
+ * The second function which will produce the result.
+ * @return The composition.
+ */
+ public static <M, X, N, P> Function<M, N, P> composeFirstP(final Function<M, X, P> first,
+ final Function<X, N, Void> second) {
+ return new Function<M, N, P>() {
+ public N apply(final M value, final P p) {
+ final X tmp = first.apply(value, p);
+ return second.apply(tmp, null);
};
+ };
+ }
- private static final Function<ByteString, String, Void> BYTESTRING_TO_STRING =
- new Function<ByteString, String, Void>() {
-
- public String apply(final ByteString value, final Void p) {
- return value.toString();
- }
+ /**
+ * Returns the composition of two functions. The result of the first
+ * function will be passed to the second. The second function will be passed
+ * an additional parameter.
+ *
+ * @param <M>
+ * The type of input values transformed by this function.
+ * @param <N>
+ * The type of output values returned by this function.
+ * @param <X>
+ * The type of intermediate values passed between the two
+ * functions.
+ * @param <P>
+ * The type of the additional parameter to the second function's
+ * {@code apply} method. Use {@link java.lang.Void} for functions
+ * that do not need an additional parameter.
+ * @param first
+ * The first function which will consume the input.
+ * @param second
+ * The second function which will produce the result.
+ * @return The composition.
+ */
+ public static <M, X, N, P> Function<M, N, P> composeSecondP(final Function<M, X, Void> first,
+ final Function<X, N, P> second) {
+ return new Function<M, N, P>() {
+ public N apply(final M value, final P p) {
+ final X tmp = first.apply(value, null);
+ return second.apply(tmp, p);
};
-
- private static final Function<Object, ByteString, Void> OBJECT_TO_BYTESTRING =
- new Function<Object, ByteString, Void>() {
-
- public ByteString apply(final Object value, final Void p) {
- return ByteString.valueOf(value);
- }
- };
-
- private static final Function<String, String, Void> NORMALIZE_STRING =
- new Function<String, String, Void>() {
-
- public String apply(final String value, final Void p) {
- return StaticUtils.toLowerCase(value).trim();
- }
- };
-
- private static final Function<Object, Object, Void> IDENTITY =
- new Function<Object, Object, Void>() {
-
- public Object apply(Object value, Void p) {
- return value;
- }
-
- };
+ };
+ }
/**
* Returns a function which which always invokes {@code function} with
@@ -232,28 +325,115 @@
}
/**
- * Returns a function which parses the string representation of a
- * {@code ByteString} as an {@code AttributeDescription} using the default
- * schema. Invalid values will result in a
+ * Returns a function which parses {@code AttributeDescription}s using the
+ * default schema. Invalid values will result in a
* {@code LocalizedIllegalArgumentException}.
*
- * @return A function which parses the string representation of a
- * {@code ByteString} as an {@code AttributeDescription}.
+ * @return A function which parses {@code AttributeDescription}s.
+ */
+ public static Function<String, AttributeDescription, Void> stringToAttributeDescription() {
+ return fixedFunction(STRING_TO_ATTRIBUTE_DESCRIPTION, Schema.getDefaultSchema());
+ }
+
+ /**
+ * Returns a function which parses {@code AttributeDescription}s using the
+ * provided schema. Invalid values will result in a
+ * {@code LocalizedIllegalArgumentException}.
+ *
+ * @param schema
+ * The schema to use for decoding attribute descriptions.
+ * @return A function which parses {@code AttributeDescription}s.
+ */
+ public static Function<String, AttributeDescription, Void> stringToAttributeDescription(
+ final Schema schema) {
+ return fixedFunction(STRING_TO_ATTRIBUTE_DESCRIPTION, schema);
+ }
+
+ /**
+ * Returns a function which parses {@code Boolean} values. The function will
+ * accept the values {@code 0}, {@code false}, {@code no}, {@code off},
+ * {@code 1}, {@code true}, {@code yes}, {@code on}. All other values will
+ * result in a {@code NumberFormatException}.
+ *
+ * @return A function which parses {@code Boolean} values.
+ */
+ public static Function<String, Boolean, Void> stringToBoolean() {
+ return STRING_TO_BOOLEAN;
+ }
+
+ /**
+ * Returns a function which parses {@code DN}s using the default schema.
+ * Invalid values will result in a {@code LocalizedIllegalArgumentException}
+ * .
+ *
+ * @return A function which parses {@code DN}s.
+ */
+ public static Function<String, DN, Void> stringToDN() {
+ return fixedFunction(STRING_TO_DN, Schema.getDefaultSchema());
+ }
+
+ /**
+ * Returns a function which parses {@code DN}s using the provided schema.
+ * Invalid values will result in a {@code LocalizedIllegalArgumentException}
+ * .
+ *
+ * @param schema
+ * The schema to use for decoding DNs.
+ * @return A function which parses {@code DN}s.
+ */
+ public static Function<String, DN, Void> stringToDN(final Schema schema) {
+ return fixedFunction(STRING_TO_DN, schema);
+ }
+
+ /**
+ * Returns a function which parses generalized time strings. Invalid values
+ * will result in a {@code LocalizedIllegalArgumentException}.
+ *
+ * @return A function which parses generalized time strings.
+ */
+ public static Function<String, GeneralizedTime, Void> stringToGeneralizedTime() {
+ return STRING_TO_GENERALIZED_TIME;
+ }
+
+ /**
+ * Returns a function which parses {@code Integer} string values. Invalid
+ * values will result in a {@code LocalizedIllegalArgumentException}.
+ *
+ * @return A function which parses {@code Integer} string values.
+ */
+ public static Function<String, Integer, Void> stringToInteger() {
+ return STRING_TO_INTEGER;
+ }
+
+ /**
+ * Returns a function which parses {@code Long} string values. Invalid
+ * values will result in a {@code LocalizedIllegalArgumentException}.
+ *
+ * @return A function which parses {@code Long} string values.
+ */
+ public static Function<String, Long, Void> stringToLong() {
+ return STRING_TO_LONG;
+ }
+
+ /**
+ * Returns a function which parses {@code AttributeDescription}s using the
+ * default schema. Invalid values will result in a
+ * {@code LocalizedIllegalArgumentException}.
+ *
+ * @return A function which parses {@code AttributeDescription}s.
*/
public static Function<ByteString, AttributeDescription, Void> valueToAttributeDescription() {
return fixedFunction(BYTESTRING_TO_ATTRIBUTE_DESCRIPTION, Schema.getDefaultSchema());
}
/**
- * Returns a function which parses the string representation of a
- * {@code ByteString} as an {@code AttributeDescription} using the provided
- * schema. Invalid values will result in a
+ * Returns a function which parses {@code AttributeDescription}s using the
+ * provided schema. Invalid values will result in a
* {@code LocalizedIllegalArgumentException}.
*
* @param schema
* The schema to use for decoding attribute descriptions.
- * @return A function which parses the string representation of a
- * {@code ByteString} as an {@code AttributeDescription}.
+ * @return A function which parses {@code AttributeDescription}s.
*/
public static Function<ByteString, AttributeDescription, Void> valueToAttributeDescription(
final Schema schema) {
@@ -261,85 +441,66 @@
}
/**
- * Returns a function which encodes a {@code ByteString} as {@code Base64}.
+ * Returns a function which parses {@code Boolean} values. The function will
+ * accept the values {@code 0}, {@code false}, {@code no}, {@code off},
+ * {@code 1}, {@code true}, {@code yes}, {@code on}. All other values will
+ * result in a {@code NumberFormatException}.
*
- * @return A function which encodes a {@code ByteString} as {@code Base64}.
- */
- public static Function<ByteString, String, Void> valueToBase64() {
- return BYTESTRING_TO_BASE64;
- }
-
- /**
- * Returns a function which parses the string representation of a
- * {@code ByteString} to a {@code Boolean}. The function will accept the
- * values {@code 0}, {@code false}, {@code no}, {@code off}, {@code 1},
- * {@code true}, {@code yes}, {@code on}. All other values will result in a
- * {@code NumberFormatException}.
- *
- * @return A function which transforms a {@code ByteString} to a
- * {@code Boolean}.
+ * @return A function which parses {@code Boolean} values.
*/
public static Function<ByteString, Boolean, Void> valueToBoolean() {
return BYTESTRING_TO_BOOLEAN;
}
/**
- * Returns a function which parses the string representation of a
- * {@code ByteString} as a generalized time syntax. Invalid values will
- * result in a {@code LocalizedIllegalArgumentException}.
+ * Returns a function which parses {@code DN}s using the default schema.
+ * Invalid values will result in a {@code LocalizedIllegalArgumentException}
+ * .
*
- * @return A function which parses the string representation of a
- * {@code ByteString} as generalized time syntax.
- */
- public static Function<ByteString, Calendar, Void> valueToCalendar() {
- return BYTESTRING_TO_CALENDAR;
- }
-
- /**
- * Returns a function which parses the string representation of a
- * {@code ByteString} as a {@code DN} using the default schema. Invalid
- * values will result in a {@code LocalizedIllegalArgumentException}.
- *
- * @return A function which parses the string representation of a
- * {@code ByteString} as an {@code DN}.
+ * @return A function which parses {@code DN}s.
*/
public static Function<ByteString, DN, Void> valueToDN() {
return fixedFunction(BYTESTRING_TO_DN, Schema.getDefaultSchema());
}
/**
- * Returns a function which parses the string representation of a
- * {@code ByteString} as a {@code DN} using the provided schema. Invalid
- * values will result in a {@code LocalizedIllegalArgumentException}.
+ * Returns a function which parses {@code DN}s using the provided schema.
+ * Invalid values will result in a {@code LocalizedIllegalArgumentException}
+ * .
*
* @param schema
* The schema to use for decoding DNs.
- * @return A function which parses the string representation of a
- * {@code ByteString} as an {@code DN}.
+ * @return A function which parses {@code DN}s.
*/
public static Function<ByteString, DN, Void> valueToDN(final Schema schema) {
return fixedFunction(BYTESTRING_TO_DN, schema);
}
/**
- * Returns a function which parses the string representation of a
- * {@code ByteString} as an {@code Integer}. Invalid values will result in a
- * {@code NumberFormatException}.
+ * Returns a function which parses generalized time strings. Invalid values
+ * will result in a {@code LocalizedIllegalArgumentException}.
*
- * @return A function which parses the string representation of a
- * {@code ByteString} as an {@code Integer}.
+ * @return A function which parses generalized time strings.
+ */
+ public static Function<ByteString, GeneralizedTime, Void> valueToGeneralizedTime() {
+ return BYTESTRING_TO_GENERALIZED_TIME;
+ }
+
+ /**
+ * Returns a function which parses {@code Integer} string values. Invalid
+ * values will result in a {@code LocalizedIllegalArgumentException}.
+ *
+ * @return A function which parses {@code Integer} string values.
*/
public static Function<ByteString, Integer, Void> valueToInteger() {
return BYTESTRING_TO_INTEGER;
}
/**
- * Returns a function which parses the string representation of a
- * {@code ByteString} as a {@code Long}. Invalid values will result in a
- * {@code NumberFormatException}.
+ * Returns a function which parses {@code Long} string values. Invalid
+ * values will result in a {@code LocalizedIllegalArgumentException}.
*
- * @return A function which parses the string representation of a
- * {@code ByteString} as a {@code Long}.
+ * @return A function which parses {@code Long} string values.
*/
public static Function<ByteString, Long, Void> valueToLong() {
return BYTESTRING_TO_LONG;
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeParser.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeParser.java
index ecffa5c..6606072 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeParser.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeParser.java
@@ -26,17 +26,17 @@
package org.forgerock.opendj.ldap;
+import static com.forgerock.opendj.util.Collections2.transformedCollection;
+
import java.util.Arrays;
-import java.util.Calendar;
import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.NoSuchElementException;
import java.util.Set;
import org.forgerock.opendj.ldap.schema.Schema;
-import com.forgerock.opendj.util.Base64;
-import com.forgerock.opendj.util.Collections2;
import com.forgerock.opendj.util.Function;
import com.forgerock.opendj.util.Functions;
@@ -105,7 +105,7 @@
* @return The first value decoded as an {@code AttributeDescription}.
*/
public AttributeDescription asAttributeDescription() {
- return asAttributeDescription(null);
+ return asAttributeDescription((AttributeDescription) null);
}
/**
@@ -122,25 +122,16 @@
}
/**
- * Returns the first value encoded as base64, or {@code null} if the
- * attribute does not contain any values.
- *
- * @return The first value encoded as base64.
- */
- public String asBase64() {
- return asBase64(null);
- }
-
- /**
- * Returns the first value encoded as base64, or {@code defaultValue} if the
+ * Returns the first value decoded as an {@code AttributeDescription} using
+ * the schema associated with this parser, or {@code defaultValue} if the
* attribute does not contain any values.
*
* @param defaultValue
* The default value to return if the attribute is empty.
- * @return The first value encoded as base64.
+ * @return The first value decoded as an {@code AttributeDescription}.
*/
- public String asBase64(final ByteString defaultValue) {
- return parseSingleValue(Functions.valueToBase64(), Base64.encode(defaultValue));
+ public AttributeDescription asAttributeDescription(final String defaultValue) {
+ return asAttributeDescription(AttributeDescription.valueOf(defaultValue, getSchema()));
}
/**
@@ -188,30 +179,6 @@
}
/**
- * Returns the first value decoded as a {@code Calendar} using the
- * generalized time syntax, or {@code null} if the attribute does not
- * contain any values.
- *
- * @return The first value decoded as a {@code Calendar}.
- */
- public Calendar asCalendar() {
- return asCalendar(null);
- }
-
- /**
- * Returns the first value decoded as an {@code Calendar} using the
- * generalized time syntax, or {@code defaultValue} if the attribute does
- * not contain any values.
- *
- * @param defaultValue
- * The default value to return if the attribute is empty.
- * @return The first value decoded as an {@code Calendar}.
- */
- public Calendar asCalendar(final Calendar defaultValue) {
- return parseSingleValue(Functions.valueToCalendar(), defaultValue);
- }
-
- /**
* Returns the first value decoded as a {@code DN} using the schema
* associated with this parser, or {@code null} if the attribute does not
* contain any values.
@@ -219,7 +186,7 @@
* @return The first value decoded as a {@code DN}.
*/
public DN asDN() {
- return asDN(null);
+ return asDN((DN) null);
}
/**
@@ -236,6 +203,43 @@
}
/**
+ * Returns the first value decoded as a {@code DN} using the schema
+ * associated with this parser, or {@code defaultValue} if the attribute
+ * does not contain any values.
+ *
+ * @param defaultValue
+ * The default value to return if the attribute is empty.
+ * @return The first value decoded as a {@code DN}.
+ */
+ public DN asDN(final String defaultValue) {
+ return asDN(DN.valueOf(defaultValue, getSchema()));
+ }
+
+ /**
+ * Returns the first value decoded as a {@code GeneralizedTime} using the
+ * generalized time syntax, or {@code null} if the attribute does not
+ * contain any values.
+ *
+ * @return The first value decoded as a {@code GeneralizedTime}.
+ */
+ public GeneralizedTime asGeneralizedTime() {
+ return asGeneralizedTime(null);
+ }
+
+ /**
+ * Returns the first value decoded as an {@code GeneralizedTime} using the
+ * generalized time syntax, or {@code defaultValue} if the attribute does
+ * not contain any values.
+ *
+ * @param defaultValue
+ * The default value to return if the attribute is empty.
+ * @return The first value decoded as an {@code GeneralizedTime}.
+ */
+ public GeneralizedTime asGeneralizedTime(final GeneralizedTime defaultValue) {
+ return parseSingleValue(Functions.valueToGeneralizedTime(), defaultValue);
+ }
+
+ /**
* Returns the first value decoded as an {@code Integer}, or {@code null} if
* the attribute does not contain any values.
*
@@ -281,6 +285,17 @@
/**
* Returns the values decoded as a set of {@code AttributeDescription}s
+ * using the schema associated with this parser, or an empty set if the
+ * attribute does not contain any values.
+ *
+ * @return The values decoded as a set of {@code AttributeDescription}s.
+ */
+ public Set<AttributeDescription> asSetOfAttributeDescription() {
+ return asSetOfAttributeDescription(Collections.<AttributeDescription> emptySet());
+ }
+
+ /**
+ * Returns the values decoded as a set of {@code AttributeDescription}s
* using the schema associated with this parser, or {@code defaultValues} if
* the attribute does not contain any values.
*
@@ -308,28 +323,17 @@
}
/**
- * Returns the values contained in the attribute encoded as base64, or
- * {@code defaultValues} if the attribute does not contain any values.
+ * Returns the values decoded as a set of {@code AttributeDescription}s
+ * using the schema associated with this parser, or {@code defaultValues} if
+ * the attribute does not contain any values.
*
* @param defaultValues
* The default values to return if the attribute is empty.
- * @return The values contained in the attribute encoded as base64.
+ * @return The values decoded as a set of {@code AttributeDescription}s.
*/
- public Set<String> asSetOfBase64(final Collection<ByteString> defaultValues) {
- return parseMultipleValues(Functions.valueToString(), Collections2.transformedCollection(
- defaultValues, Functions.valueToBase64(), null));
- }
-
- /**
- * Returns the values contained in the attribute encoded as base64, or
- * {@code defaultValues} if the attribute does not contain any values.
- *
- * @param defaultValues
- * The default values to return if the attribute is empty.
- * @return The values contained in the attribute encoded as base64.
- */
- public Set<String> asSetOfBase64(final String... defaultValues) {
- return asSetOfString(Arrays.asList(defaultValues));
+ public Set<AttributeDescription> asSetOfAttributeDescription(final String... defaultValues) {
+ return asSetOfAttributeDescription(transformedCollection(Arrays.asList(defaultValues),
+ Functions.stringToAttributeDescription(getSchema()), null));
}
/**
@@ -381,29 +385,14 @@
}
/**
- * Returns the values decoded as a set of {@code Calendar}s using the
- * generalized time syntax, or {@code defaultValues} if the attribute does
- * not contain any values.
+ * Returns the values decoded as a set of {@code DN}s using the schema
+ * associated with this parser, or an empty set if the attribute does not
+ * contain any values.
*
- * @param defaultValues
- * The default values to return if the attribute is empty.
- * @return The values decoded as a set of {@code Calendar}s.
+ * @return The values decoded as a set of {@code DN}s.
*/
- public Set<Calendar> asSetOfCalendar(final Calendar... defaultValues) {
- return asSetOfCalendar(Arrays.asList(defaultValues));
- }
-
- /**
- * Returns the values decoded as a set of {@code Calendar}s using the
- * generalized time syntax, or {@code defaultValues} if the attribute does
- * not contain any values.
- *
- * @param defaultValues
- * The default values to return if the attribute is empty.
- * @return The values decoded as a set of {@code Calendar}s.
- */
- public Set<Calendar> asSetOfCalendar(final Collection<Calendar> defaultValues) {
- return parseMultipleValues(Functions.valueToCalendar(), defaultValues);
+ public Set<DN> asSetOfDN() {
+ return asSetOfDN(Collections.<DN> emptySet());
}
/**
@@ -433,6 +422,47 @@
}
/**
+ * Returns the values decoded as a set of {@code DN}s using the schema
+ * associated with this parser, or {@code defaultValues} if the attribute
+ * does not contain any values.
+ *
+ * @param defaultValues
+ * The default values to return if the attribute is empty.
+ * @return The values decoded as a set of {@code DN}s.
+ */
+ public Set<DN> asSetOfDN(final String... defaultValues) {
+ return asSetOfDN(transformedCollection(Arrays.asList(defaultValues), Functions
+ .stringToDN(getSchema()), null));
+ }
+
+ /**
+ * Returns the values decoded as a set of {@code GeneralizedTime}s using the
+ * generalized time syntax, or {@code defaultValues} if the attribute does
+ * not contain any values.
+ *
+ * @param defaultValues
+ * The default values to return if the attribute is empty.
+ * @return The values decoded as a set of {@code GeneralizedTime}s.
+ */
+ public Set<GeneralizedTime> asSetOfGeneralizedTime(
+ final Collection<GeneralizedTime> defaultValues) {
+ return parseMultipleValues(Functions.valueToGeneralizedTime(), defaultValues);
+ }
+
+ /**
+ * Returns the values decoded as a set of {@code GeneralizedTime}s using the
+ * generalized time syntax, or {@code defaultValues} if the attribute does
+ * not contain any values.
+ *
+ * @param defaultValues
+ * The default values to return if the attribute is empty.
+ * @return The values decoded as a set of {@code GeneralizedTime}s.
+ */
+ public Set<GeneralizedTime> asSetOfGeneralizedTime(final GeneralizedTime... defaultValues) {
+ return asSetOfGeneralizedTime(Arrays.asList(defaultValues));
+ }
+
+ /**
* Returns the values decoded as a set of {@code Integer}s, or
* {@code defaultValues} if the attribute does not contain any values.
*
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;
+ }
}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeEqualityMatchingRuleImpl.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeEqualityMatchingRuleImpl.java
index e7191f6..6682e1f 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeEqualityMatchingRuleImpl.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeEqualityMatchingRuleImpl.java
@@ -26,11 +26,11 @@
*/
package org.forgerock.opendj.ldap.schema;
+import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DecodeException;
-
-import com.forgerock.opendj.util.GeneralizedTime;
+import org.forgerock.opendj.ldap.GeneralizedTime;
/**
* This class defines the generalizedTimeMatch matching rule defined in X.520
@@ -39,6 +39,10 @@
final class GeneralizedTimeEqualityMatchingRuleImpl extends AbstractMatchingRuleImpl {
public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value)
throws DecodeException {
- return ByteString.valueOf(GeneralizedTime.decode(value).getTimeInMillis());
+ try {
+ return ByteString.valueOf(GeneralizedTime.valueOf(value.toString()).getTimeInMillis());
+ } catch (LocalizedIllegalArgumentException e) {
+ throw DecodeException.error(e.getMessageObject());
+ }
}
}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeOrderingMatchingRuleImpl.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeOrderingMatchingRuleImpl.java
index c7cb533..f28821e 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeOrderingMatchingRuleImpl.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeOrderingMatchingRuleImpl.java
@@ -26,11 +26,11 @@
*/
package org.forgerock.opendj.ldap.schema;
+import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DecodeException;
-
-import com.forgerock.opendj.util.GeneralizedTime;
+import org.forgerock.opendj.ldap.GeneralizedTime;
/**
* This class defines the generalizedTimeOrderingMatch matching rule defined in
@@ -39,6 +39,10 @@
final class GeneralizedTimeOrderingMatchingRuleImpl extends AbstractOrderingMatchingRuleImpl {
public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value)
throws DecodeException {
- return ByteString.valueOf(GeneralizedTime.decode(value).getTimeInMillis());
+ try {
+ return ByteString.valueOf(GeneralizedTime.valueOf(value.toString()).getTimeInMillis());
+ } catch (LocalizedIllegalArgumentException e) {
+ throw DecodeException.error(e.getMessageObject());
+ }
}
}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeSyntaxImpl.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeSyntaxImpl.java
index 1b28a5b..0ba5d70 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeSyntaxImpl.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeSyntaxImpl.java
@@ -33,10 +33,9 @@
import static org.forgerock.opendj.ldap.schema.SchemaConstants.SYNTAX_GENERALIZED_TIME_NAME;
import org.forgerock.i18n.LocalizableMessageBuilder;
+import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.ByteSequence;
-import org.forgerock.opendj.ldap.DecodeException;
-
-import com.forgerock.opendj.util.GeneralizedTime;
+import org.forgerock.opendj.ldap.GeneralizedTime;
/**
* This class implements the fax attribute syntax. This should be restricted to
@@ -85,10 +84,10 @@
public boolean valueIsAcceptable(final Schema schema, final ByteSequence value,
final LocalizableMessageBuilder invalidReason) {
try {
- GeneralizedTime.decode(value);
+ GeneralizedTime.valueOf(value.toString());
return true;
- } catch (final DecodeException de) {
- invalidReason.append(de.getMessageObject());
+ } catch (final LocalizedIllegalArgumentException e) {
+ invalidReason.append(e.getMessageObject());
return false;
}
}
diff --git a/opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core.properties b/opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core.properties
index de8ee7b..b54b134 100755
--- a/opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core.properties
+++ b/opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core.properties
@@ -1399,3 +1399,7 @@
entry does not exist
REJECTED_CHANGE_FAIL_MODIFYDN_DUPE=The entry "%s" could not be renamed because \
there is already an entry with the same name
+FUNCTIONS_TO_INTEGER_FAIL=The provided value "%s" could not be parsed as an \
+ integer
+FUNCTIONS_TO_LONG_FAIL=The provided value "%s" could not be parsed as an \
+ long
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AttributeParserTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AttributeParserTestCase.java
new file mode 100644
index 0000000..ce524df
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AttributeParserTestCase.java
@@ -0,0 +1,360 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2012 ForgeRock AS.
+ */
+
+package org.forgerock.opendj.ldap;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+import java.util.NoSuchElementException;
+
+import org.fest.util.Collections;
+import org.forgerock.i18n.LocalizedIllegalArgumentException;
+import org.testng.annotations.Test;
+
+/**
+ * Test {@code AttributeParser}.
+ */
+@SuppressWarnings("javadoc")
+public final class AttributeParserTestCase extends SdkTestCase {
+
+ @Test
+ public void testAsBooleanTrue() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "enabled: true");
+ assertThat(e.parseAttribute("enabled").asBoolean()).isTrue();
+ }
+
+ @Test
+ public void testAsBooleanFalse() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "enabled: false");
+ assertThat(e.parseAttribute("enabled").asBoolean()).isFalse();
+ }
+
+ @Test
+ public void testAsBooleanTrueDefaultFalse() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "enabled: true");
+ assertThat(e.parseAttribute("enabled").asBoolean(false)).isTrue();
+ }
+
+ @Test
+ public void testAsBooleanFalseDefaultTrue() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "enabled: false");
+ assertThat(e.parseAttribute("enabled").asBoolean(true)).isFalse();
+ }
+
+ @Test
+ public void testAsBooleanMissing() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(e.parseAttribute("enabled").asBoolean()).isNull();
+ }
+
+ @Test
+ public void testAsBooleanMissingDefaultTrue() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(e.parseAttribute("enabled").asBoolean(true)).isTrue();
+ }
+
+ @Test
+ public void testAsBooleanMissingDefaultFalse() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(e.parseAttribute("enabled").asBoolean(false)).isFalse();
+ }
+
+ @Test(expectedExceptions = { NoSuchElementException.class })
+ public void testAsBooleanMissingRequired() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ e.parseAttribute("enabled").requireValue().asBoolean();
+ }
+
+ @Test(expectedExceptions = { IllegalArgumentException.class })
+ public void testAsBooleanInvalid() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "enabled: xxx");
+ e.parseAttribute("enabled").asBoolean();
+ }
+
+ @Test
+ public void testAsInteger99() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "age: 99");
+ assertThat(e.parseAttribute("age").asInteger()).isEqualTo(99);
+ }
+
+ @Test
+ public void testAsInteger99Default100() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "age: 99");
+ assertThat(e.parseAttribute("age").asInteger(100)).isEqualTo(99);
+ }
+
+ @Test
+ public void testAsIntegerMissing() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(e.parseAttribute("age").asInteger()).isNull();
+ }
+
+ @Test
+ public void testAsIntegerMissingDefault100() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(e.parseAttribute("age").asInteger(100)).isEqualTo(100);
+ }
+
+ @Test(expectedExceptions = { NoSuchElementException.class })
+ public void testAsIntegerMissingRequired() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ e.parseAttribute("age").requireValue().asInteger();
+ }
+
+ @Test(expectedExceptions = { IllegalArgumentException.class })
+ public void testAsIntegerInvalid() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "age: xxx");
+ e.parseAttribute("age").asInteger();
+ }
+
+ @Test
+ public void testAsLong99() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "age: 99");
+ assertThat(e.parseAttribute("age").asLong()).isEqualTo(99);
+ }
+
+ @Test
+ public void testAsLong99Default100() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "age: 99");
+ assertThat(e.parseAttribute("age").asLong(100)).isEqualTo(99);
+ }
+
+ @Test
+ public void testAsLongMissing() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(e.parseAttribute("age").asLong()).isNull();
+ }
+
+ @Test
+ public void testAsLongMissingDefault100() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(e.parseAttribute("age").asLong(100)).isEqualTo(100);
+ }
+
+ @Test(expectedExceptions = { NoSuchElementException.class })
+ public void testAsLongMissingRequired() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ e.parseAttribute("age").requireValue().asLong();
+ }
+
+ @Test(expectedExceptions = { IllegalArgumentException.class })
+ public void testAsLongInvalid() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "age: xxx");
+ e.parseAttribute("age").asLong();
+ }
+
+ @Test
+ public void testAsDN() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "manager: cn=manager");
+ assertThat((Object) e.parseAttribute("manager").asDN()).isEqualTo(DN.valueOf("cn=manager"));
+ }
+
+ @Test
+ public void testAsDNDefault() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "manager: cn=manager");
+ assertThat((Object) e.parseAttribute("manager").asDN("cn=boss")).isEqualTo(
+ DN.valueOf("cn=manager"));
+ }
+
+ @Test
+ public void testAsDNMissing() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(e.parseAttribute("manager").asDN()).isNull();
+ }
+
+ @Test
+ public void testAsDNMissingDefault() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat((Object) e.parseAttribute("manager").asDN(DN.valueOf("cn=boss"))).isEqualTo(
+ DN.valueOf("cn=boss"));
+ }
+
+ @Test(expectedExceptions = { NoSuchElementException.class })
+ public void testAsDNMissingRequired() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ e.parseAttribute("manager").requireValue().asDN();
+ }
+
+ @Test(expectedExceptions = { IllegalArgumentException.class })
+ public void testAsDNInvalid() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "manager: xxx");
+ e.parseAttribute("manager").asDN();
+ }
+
+ @Test
+ public void testAsAttributeDescription() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "type: cn");
+ assertThat(e.parseAttribute("type").asAttributeDescription()).isEqualTo(
+ AttributeDescription.valueOf("cn"));
+ }
+
+ @Test
+ public void testAsAttributeDescriptionDefault() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "type: cn");
+ assertThat(e.parseAttribute("type").asAttributeDescription("sn")).isEqualTo(
+ AttributeDescription.valueOf("cn"));
+ }
+
+ @Test
+ public void testAsAttributeDescriptionMissing() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(e.parseAttribute("type").asAttributeDescription()).isNull();
+ }
+
+ @Test
+ public void testAsAttributeDescriptionMissingDefault() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(
+ e.parseAttribute("type").asAttributeDescription(AttributeDescription.valueOf("sn")))
+ .isEqualTo(AttributeDescription.valueOf("sn"));
+ }
+
+ @Test(expectedExceptions = { NoSuchElementException.class })
+ public void testAsAttributeDescriptionMissingRequired() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ e.parseAttribute("type").requireValue().asAttributeDescription();
+ }
+
+ @Test(expectedExceptions = { IllegalArgumentException.class })
+ public void testAsAttributeDescriptionInvalid() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "type: ;x");
+ e.parseAttribute("type").asAttributeDescription();
+ }
+
+ @Test
+ public void testAsString() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "type: cn");
+ assertThat(e.parseAttribute("type").asString()).isEqualTo(String.valueOf("cn"));
+ }
+
+ @Test
+ public void testAsStringDefault() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "type: cn");
+ assertThat(e.parseAttribute("type").asString("sn")).isEqualTo(String.valueOf("cn"));
+ }
+
+ @Test
+ public void testAsStringMissing() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(e.parseAttribute("type").asString()).isNull();
+ }
+
+ @Test
+ public void testAsStringMissingDefault() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(e.parseAttribute("type").asString(String.valueOf("sn"))).isEqualTo(
+ String.valueOf("sn"));
+ }
+
+ @Test(expectedExceptions = { NoSuchElementException.class })
+ public void testAsStringMissingRequired() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ e.parseAttribute("type").requireValue().asString();
+ }
+
+ @Test
+ public void testAsByteString() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "type: cn");
+ assertThat(e.parseAttribute("type").asByteString()).isEqualTo(ByteString.valueOf("cn"));
+ }
+
+ @Test
+ public void testAsByteStringDefault() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test", "type: cn");
+ assertThat(e.parseAttribute("type").asByteString(ByteString.valueOf("sn"))).isEqualTo(
+ ByteString.valueOf("cn"));
+ }
+
+ @Test
+ public void testAsByteStringMissing() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(e.parseAttribute("type").asByteString()).isNull();
+ }
+
+ @Test
+ public void testAsByteStringMissingDefault() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ assertThat(e.parseAttribute("type").asByteString(ByteString.valueOf("sn"))).isEqualTo(
+ ByteString.valueOf("sn"));
+ }
+
+ @Test(expectedExceptions = { NoSuchElementException.class })
+ public void testAsByteStringMissingRequired() {
+ Entry e = new LinkedHashMapEntry("dn: cn=test", "objectClass: test");
+ e.parseAttribute("type").requireValue().asByteString();
+ }
+
+ // Smoke test for set of methods: use one type only since the code is common
+ // and we've already tested the parsing.
+ @Test
+ public void testAsSetOfDN() {
+ Entry e =
+ new LinkedHashMapEntry("dn: cn=group", "objectClass: group", "member: cn=member1",
+ "member: cn=member2", "member: cn=member3");
+ assertThat(e.parseAttribute("member").asSetOfDN()).isEqualTo(
+ Collections.set(DN.valueOf("cn=member1"), DN.valueOf("cn=member2"), DN
+ .valueOf("cn=member3")));
+ }
+
+ @Test
+ public void testAsSetOfDNDefault() {
+ Entry e =
+ new LinkedHashMapEntry("dn: cn=group", "objectClass: group", "member: cn=member1",
+ "member: cn=member2", "member: cn=member3");
+ assertThat(e.parseAttribute("member").asSetOfDN("cn=dummy1", "cn=dummy2")).isEqualTo(
+ Collections.set(DN.valueOf("cn=member1"), DN.valueOf("cn=member2"), DN
+ .valueOf("cn=member3")));
+ }
+
+ @Test
+ public void testAsSetOfDNMissing() {
+ Entry e = new LinkedHashMapEntry("dn: cn=group", "objectClass: group");
+ assertThat(e.parseAttribute("member").asSetOfDN()).isEqualTo(
+ java.util.Collections.emptySet());
+ }
+
+ @Test
+ public void testAsSetOfDNMissingDefault() {
+ Entry e = new LinkedHashMapEntry("dn: cn=group", "objectClass: group");
+ assertThat(e.parseAttribute("member").asSetOfDN("cn=dummy1", "cn=dummy2")).isEqualTo(
+ Collections.set(DN.valueOf("cn=dummy1"), DN.valueOf("cn=dummy2")));
+ }
+
+ @Test(expectedExceptions = { NoSuchElementException.class })
+ public void testAsSetOfDNMissingRequired() {
+ Entry e = new LinkedHashMapEntry("dn: cn=group", "objectClass: group");
+ e.parseAttribute("member").requireValue().asSetOfDN();
+ }
+
+ @Test(expectedExceptions = { LocalizedIllegalArgumentException.class })
+ public void testAsSetOfDNInvalid() {
+ Entry e =
+ new LinkedHashMapEntry("dn: cn=group", "objectClass: group", "member: cn=member1",
+ "member: xxxx");
+ e.parseAttribute("member").asSetOfDN();
+ }
+
+}
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/GeneralizedTimeTest.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/GeneralizedTimeTest.java
new file mode 100644
index 0000000..19628a4
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/GeneralizedTimeTest.java
@@ -0,0 +1,132 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2009 Sun Microsystems, Inc.
+ * Portions copyright 2012 ForgeRock AS.
+ */
+package org.forgerock.opendj.ldap;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import org.forgerock.i18n.LocalizedIllegalArgumentException;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.fest.assertions.Assertions.assertThat;
+
+/**
+ * Generalized time tests.
+ */
+@SuppressWarnings("javadoc")
+public class GeneralizedTimeTest extends SdkTestCase {
+
+ @DataProvider
+ public Object[][] validStrings() {
+ return new Object[][] { { "2006090613Z" }, { "20060906135030+01" }, { "200609061350Z" },
+ { "20060906135030Z" }, { "20061116135030Z" }, { "20061126135030Z" },
+ { "20061231235959Z" }, { "20060906135030+0101" }, { "20060906135030+2359" }, };
+ }
+
+ @DataProvider
+ public Object[][] invalidStrings() {
+ return new Object[][] { { "20060906135030+3359" }, { "20060906135030+2389" },
+ { "20060906135030+2361" }, { "20060906135030+" }, { "20060906135030+0" },
+ { "20060906135030+010" }, { "20061200235959Z" }, { "2006121a235959Z" },
+ { "2006122a235959Z" }, { "20060031235959Z" }, { "20061331235959Z" },
+ { "20062231235959Z" }, { "20061232235959Z" }, { "2006123123595aZ" },
+ { "200a1231235959Z" }, { "2006j231235959Z" }, { "200612-1235959Z" },
+ { "20061231#35959Z" }, { "2006" }, };
+ }
+
+ @Test(expectedExceptions = { LocalizedIllegalArgumentException.class },
+ dataProvider = "invalidStrings")
+ public void testValueOfInvalidString(String s) {
+ GeneralizedTime.valueOf(s);
+ }
+
+ @Test(dataProvider = "validStrings")
+ public void testValueOfValidString(String s) {
+ assertThat(GeneralizedTime.valueOf(s).toString()).isEqualTo(s);
+ }
+
+ @Test
+ public void testValueOfLong() {
+ Date date = new Date();
+ GeneralizedTime time = GeneralizedTime.valueOf(date.getTime());
+ assertThat(time.getTimeInMillis()).isEqualTo(date.getTime());
+ assertThat(time.toDate()).isEqualTo(date);
+ }
+
+ @Test
+ public void testValueOfDate() {
+ Date date = new Date();
+ GeneralizedTime time = GeneralizedTime.valueOf(date);
+ assertThat(time.getTimeInMillis()).isEqualTo(date.getTime());
+ assertThat(time.toDate()).isEqualTo(date);
+ }
+
+ @Test
+ public void testValueOfCalendar() {
+ Calendar calendar = Calendar.getInstance();
+ GeneralizedTime time = GeneralizedTime.valueOf(calendar);
+ assertThat(time.getTimeInMillis()).isEqualTo(calendar.getTimeInMillis());
+ assertThat(time.toCalendar()).isEqualTo(calendar);
+ assertThat(time.toDate()).isEqualTo(calendar.getTime());
+ }
+
+ @Test
+ public void testEqualsTrue() {
+ GeneralizedTime gt1 = GeneralizedTime.valueOf("20060906135030+01");
+ GeneralizedTime gt2 = GeneralizedTime.valueOf("20060906125030Z");
+ assertThat(gt1).isEqualTo(gt2);
+ }
+
+ @Test
+ public void testEqualsFalse() {
+ GeneralizedTime gt1 = GeneralizedTime.valueOf("20060906135030Z");
+ GeneralizedTime gt2 = GeneralizedTime.valueOf("20060906135030+01");
+ assertThat(gt1).isNotEqualTo(gt2);
+ }
+
+ @Test
+ public void testCompareEquals() {
+ GeneralizedTime gt1 = GeneralizedTime.valueOf("20060906135030+01");
+ GeneralizedTime gt2 = GeneralizedTime.valueOf("20060906125030Z");
+ assertThat(gt1.compareTo(gt2)).isEqualTo(0);
+ }
+
+ @Test
+ public void testCompareLessThan() {
+ GeneralizedTime gt1 = GeneralizedTime.valueOf("20060906135030+01");
+ GeneralizedTime gt2 = GeneralizedTime.valueOf("20060906135030Z");
+ assertThat(gt1.compareTo(gt2) < 0).isTrue();
+ }
+
+ @Test
+ public void testCompareGreaterThan() {
+ GeneralizedTime gt1 = GeneralizedTime.valueOf("20060906135030Z");
+ GeneralizedTime gt2 = GeneralizedTime.valueOf("20060906135030+01");
+ assertThat(gt1.compareTo(gt2) > 0).isTrue();
+ }
+
+}
--
Gitblit v1.10.0