From c657fa9ccde2ac75a4ee0cddbbb4e28bc7e904c0 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Tue, 21 Jun 2011 20:52:08 +0000
Subject: [PATCH] Partial fix for OPENDJ-205: Add support for rejecting and skipping records to the LDIF readers
---
opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java | 2
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java | 2
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java | 50 +
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFStream.java | 4
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java | 238 ++++++----
opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptionsTest.java | 4
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java | 2
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core.properties | 84 ++-
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryReader.java | 105 ++-
opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFChangeRecordReaderTestCase.java | 471 +++++++++++++++++++++
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/EntryWriter.java | 2
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/ChangeRecordWriter.java | 2
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java | 135 +++--
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/RejectedRecordListener.java | 141 ++++++
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java | 29
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFWriter.java | 4
16 files changed, 1,018 insertions(+), 257 deletions(-)
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
index 875da3b..c7e21d1 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
@@ -784,6 +784,9 @@
* @param attributeDescription
* The LDAP string representation of an attribute description.
* @return The parsed attribute description.
+ * @throws UnknownSchemaElementException
+ * If {@code attributeDescription} contains an attribute type which
+ * is not contained in the default schema and the schema is strict.
* @throws LocalizedIllegalArgumentException
* If {@code attributeDescription} is not a valid LDAP string
* representation of an attribute description.
@@ -791,7 +794,8 @@
* If {@code attributeDescription} was {@code null}.
*/
public static AttributeDescription valueOf(final String attributeDescription)
- throws LocalizedIllegalArgumentException, NullPointerException
+ throws UnknownSchemaElementException, LocalizedIllegalArgumentException,
+ NullPointerException
{
return valueOf(attributeDescription, Schema.getDefaultSchema());
}
@@ -807,17 +811,20 @@
* @param schema
* The schema to use when parsing the attribute description.
* @return The parsed attribute description.
+ * @throws UnknownSchemaElementException
+ * If {@code attributeDescription} contains an attribute type which
+ * is not contained in the provided schema and the schema is strict.
* @throws LocalizedIllegalArgumentException
* If {@code attributeDescription} is not a valid LDAP string
* representation of an attribute description.
* @throws NullPointerException
- * If {@code attributeDescription} or {@code schema} was {@code
- * null}.
+ * If {@code attributeDescription} or {@code schema} was
+ * {@code null}.
*/
@SuppressWarnings("serial")
public static AttributeDescription valueOf(final String attributeDescription,
- final Schema schema) throws LocalizedIllegalArgumentException,
- NullPointerException
+ final Schema schema) throws UnknownSchemaElementException,
+ LocalizedIllegalArgumentException, NullPointerException
{
Validator.ensureNotNull(attributeDescription, schema);
@@ -1005,17 +1012,7 @@
}
// Get the attribute type from the schema.
- final AttributeType attributeType;
- try
- {
- attributeType = schema.getAttributeType(oid);
- }
- catch (final UnknownSchemaElementException e)
- {
- final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_TYPE_NOT_FOUND
- .get(attributeDescription, e.getMessageObject());
- throw new LocalizedIllegalArgumentException(message);
- }
+ final AttributeType attributeType = schema.getAttributeType(oid);
// If we're already at the end of the attribute description then it
// does not contain any options.
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java
index 939eac6..86bb032 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java
@@ -91,7 +91,7 @@
addRFC3112(builder);
addSunProprietary(builder);
- SINGLETON = builder.toSchema().nonStrict();
+ SINGLETON = builder.toSchema().asNonStrictSchema();
}
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java
index f36b605..5e55697 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java
@@ -54,7 +54,7 @@
{
try
{
- DN dn = DN.valueOf(value.toString(), schema.nonStrict());
+ DN dn = DN.valueOf(value.toString(), schema.asNonStrictSchema());
StringBuilder builder = new StringBuilder(value.length());
return ByteString.valueOf(normalizeDN(builder, dn));
}
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
index 1759a1e..f64b02e 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
@@ -2446,12 +2446,16 @@
/**
- * Indicates whether or not this schema is strict. Attribute type queries in
- * non-strict schema always succeed: if the requested attribute type is not
- * found then a temporary attribute type is created automatically having the
- * Octet String syntax and associated matching rules. Strict schema, on the
- * other hand, throw an {@link UnknownSchemaElementException} whenever an
- * attempt is made to retrieve a non-existent attribute type.
+ * Indicates whether or not this schema is strict.
+ * <p>
+ * Attribute type queries against non-strict schema always succeed: if the
+ * requested attribute type is not found then a temporary attribute type is
+ * created automatically having the Octet String syntax and associated
+ * matching rules.
+ * <p>
+ * Strict schema, on the other hand, throw an
+ * {@link UnknownSchemaElementException} whenever an attempt is made to
+ * retrieve a non-existent attribute type.
*
* @return {@code true} if this schema is strict.
*/
@@ -2463,16 +2467,14 @@
/**
- * Returns a non-strict view of this schema. Attribute type queries in
- * non-strict schema always succeed: if the requested attribute type is not
- * found then a temporary attribute type is created automatically having the
- * Octet String syntax and associated matching rules. Strict schema, on the
- * other hand, throw an {@link UnknownSchemaElementException} whenever an
- * attempt is made to retrieve a non-existent attribute type.
+ * Returns a non-strict view of this schema.
+ * <p>
+ * See the description of {@link #isStrict()} for more details.
*
* @return A non-strict view of this schema.
+ * @see Schema#isStrict()
*/
- public Schema nonStrict()
+ public Schema asNonStrictSchema()
{
if (impl.isStrict())
{
@@ -2487,6 +2489,28 @@
/**
+ * Returns a strict view of this schema.
+ * <p>
+ * See the description of {@link #isStrict()} for more details.
+ *
+ * @return A strict view of this schema.
+ * @see Schema#isStrict()
+ */
+ public Schema asStrictSchema()
+ {
+ if (impl.isStrict())
+ {
+ return this;
+ }
+ else
+ {
+ return new Schema(((NonStrictImpl) impl).strictImpl);
+ }
+ }
+
+
+
+ /**
* Adds the definitions of all the schema elements contained in this schema to
* the provided subschema subentry. Any existing attributes (including schema
* definitions) contained in the provided entry will be preserved.
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java
index d2fb8c8..4230d08 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java
@@ -46,6 +46,8 @@
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.*;
+import org.forgerock.opendj.ldap.schema.Schema;
+import org.forgerock.opendj.ldap.schema.UnknownSchemaElementException;
import com.forgerock.opendj.util.Base64;
import com.forgerock.opendj.util.Validator;
@@ -155,7 +157,7 @@
/**
- *{@inheritDoc}
+ * {@inheritDoc}
*/
public String readLine() throws IOException
{
@@ -209,7 +211,7 @@
/**
- *{@inheritDoc}
+ * {@inheritDoc}
*/
public String readLine() throws IOException
{
@@ -226,7 +228,11 @@
- boolean validateSchema = true;
+ RejectedRecordListener rejectedRecordListener = RejectedRecordListener.FAIL_FAST;
+
+ Schema schema = Schema.getDefaultSchema().asNonStrictSchema();
+
+ boolean validateSchema = false;
private final LDIFReaderImpl impl;
@@ -322,8 +328,8 @@
{
// The value did not have a valid base64-encoding.
final LocalizableMessage message = ERR_LDIF_COULD_NOT_BASE64_DECODE_ATTR
- .get(entryDN.toString(), record.lineNumber, ldifLine, e
- .getMessageObject());
+ .get(entryDN.toString(), record.lineNumber, ldifLine,
+ e.getMessageObject());
throw DecodeException.error(message);
}
}
@@ -345,8 +351,9 @@
catch (final Exception e)
{
// The URL was malformed or had an invalid protocol.
- final LocalizableMessage message = ERR_LDIF_INVALID_URL.get(entryDN
- .toString(), record.lineNumber, attrName, String.valueOf(e));
+ final LocalizableMessage message = ERR_LDIF_INVALID_URL.get(
+ entryDN.toString(), record.lineNumber, attrName,
+ String.valueOf(e));
throw DecodeException.error(message);
}
@@ -370,9 +377,9 @@
{
// We were unable to read the contents of that URL for some
// reason.
- final LocalizableMessage message = ERR_LDIF_URL_IO_ERROR.get(entryDN
- .toString(), record.lineNumber, attrName, String
- .valueOf(contentURL), String.valueOf(e));
+ final LocalizableMessage message = ERR_LDIF_URL_IO_ERROR.get(
+ entryDN.toString(), record.lineNumber, attrName,
+ String.valueOf(contentURL), String.valueOf(e));
throw DecodeException.error(message);
}
finally
@@ -583,7 +590,8 @@
final void readLDIFRecordAttributeValue(final LDIFRecord record,
- final String ldifLine, final Entry entry) throws DecodeException
+ final String ldifLine, final Entry entry,
+ final List<LocalizableMessage> schemaErrors) throws DecodeException
{
// Parse the attribute description.
final int colonPos = parseColonPosition(record, ldifLine);
@@ -594,9 +602,25 @@
{
attributeDescription = AttributeDescription.valueOf(attrDescr, schema);
}
+ catch (final UnknownSchemaElementException e)
+ {
+ final LocalizableMessage message = ERR_LDIF_UNKNOWN_ATTRIBUTE_TYPE.get(
+ record.lineNumber, entry.getName().toString(), attrDescr);
+ if (validateSchema)
+ {
+ schemaErrors.add(message);
+ return;
+ }
+ else
+ {
+ throw DecodeException.error(message);
+ }
+ }
catch (final LocalizedIllegalArgumentException e)
{
- throw DecodeException.error(e.getMessageObject());
+ final LocalizableMessage message = ERR_LDIF_MALFORMED_ATTRIBUTE_NAME.get(
+ record.lineNumber, entry.getName().toString(), attrDescr);
+ throw DecodeException.error(message);
}
// Now parse the attribute value.
@@ -617,9 +641,10 @@
{
if (validateSchema && attributeDescription.containsOption("binary"))
{
- final LocalizableMessage message = ERR_LDIF_INVALID_ATTR_OPTION.get(
- entry.getName().toString(), record.lineNumber, attrDescr);
- throw DecodeException.error(message);
+ final LocalizableMessage message = ERR_LDIF_UNEXPECTED_BINARY_OPTION
+ .get(record.lineNumber, entry.getName().toString(), attrDescr);
+ schemaErrors.add(message);
+ return;
}
}
else
@@ -636,10 +661,11 @@
if (!attributeDescription.getAttributeType().getSyntax()
.valueIsAcceptable(value, invalidReason))
{
- final LocalizableMessage message = WARN_LDIF_VALUE_VIOLATES_SYNTAX
- .get(entry.getName().toString(), record.lineNumber, value
- .toString(), attrDescr, invalidReason);
- throw DecodeException.error(message);
+ final LocalizableMessage message = WARN_LDIF_MALFORMED_ATTRIBUTE_VALUE
+ .get(record.lineNumber, entry.getName().toString(),
+ value.toString(), attrDescr, invalidReason);
+ schemaErrors.add(message);
+ return;
}
}
@@ -654,25 +680,29 @@
if (!attributeDescription.getAttributeType().getSyntax()
.valueIsAcceptable(value, invalidReason))
{
- final LocalizableMessage message = WARN_LDIF_VALUE_VIOLATES_SYNTAX
- .get(entry.getName().toString(), record.lineNumber, value
- .toString(), attrDescr, invalidReason);
- throw DecodeException.error(message);
+ final LocalizableMessage message = WARN_LDIF_MALFORMED_ATTRIBUTE_VALUE
+ .get(record.lineNumber, entry.getName().toString(),
+ value.toString(), attrDescr, invalidReason);
+ schemaErrors.add(message);
+ return;
}
- if (!attribute.add(value))
+ if (!attribute.add(value) && validateSchema)
{
- final LocalizableMessage message = WARN_LDIF_DUPLICATE_ATTR.get(entry
- .getName().toString(), record.lineNumber, attrDescr, value
- .toString());
- throw DecodeException.error(message);
+ final LocalizableMessage message = WARN_LDIF_DUPLICATE_ATTRIBUTE_VALUE
+ .get(record.lineNumber, entry.getName().toString(), attrDescr,
+ value.toString());
+ schemaErrors.add(message);
+ return;
}
- if (attributeDescription.getAttributeType().isSingleValue())
+ if (validateSchema
+ && attributeDescription.getAttributeType().isSingleValue())
{
- final LocalizableMessage message = ERR_LDIF_MULTIPLE_VALUES_FOR_SINGLE_VALUED_ATTR
- .get(entry.getName().toString(), record.lineNumber, attrDescr);
- throw DecodeException.error(message);
+ final LocalizableMessage message = ERR_LDIF_MULTI_VALUED_SINGLE_VALUED_ATTRIBUTE
+ .get(record.lineNumber, entry.getName().toString(), attrDescr);
+ schemaErrors.add(message);
+ return;
}
}
else
@@ -787,15 +817,13 @@
final String readLDIFRecordKeyValuePair(final LDIFRecord record,
final KeyValuePair pair, final boolean allowBase64)
- throws DecodeException
{
final String ldifLine = record.iterator.next();
final int colonPos = ldifLine.indexOf(":");
if (colonPos <= 0)
{
- final LocalizableMessage message = ERR_LDIF_NO_ATTR_NAME.get(
- record.lineNumber, ldifLine);
- throw DecodeException.error(message);
+ pair.key = null;
+ return ldifLine;
}
pair.key = ldifLine.substring(0, colonPos);
@@ -804,10 +832,8 @@
final int length = ldifLine.length();
if (colonPos == length - 1)
{
- // FIXME: improve error.
- final LocalizableMessage message = LocalizableMessage
- .raw("Malformed changetype attribute");
- throw DecodeException.error(message);
+ pair.key = null;
+ return ldifLine;
}
if (allowBase64 && ldifLine.charAt(colonPos + 1) == ':')
@@ -826,11 +852,8 @@
}
catch (final LocalizedIllegalArgumentException e)
{
- // The value did not have a valid base64-encoding.
- // FIXME: improve error.
- final LocalizableMessage message = LocalizableMessage
- .raw("Malformed base64 changetype attribute");
- throw DecodeException.error(message);
+ pair.key = null;
+ return ldifLine;
}
}
else
@@ -852,19 +875,29 @@
- final void rejectLDIFRecord(final LDIFRecord record,
+ final void handleMalformedRecord(final LDIFRecord record,
final LocalizableMessage message) throws DecodeException
{
- // FIXME: not yet implemented.
- throw DecodeException.error(message);
+ rejectedRecordListener.handleMalformedRecord(record.lineNumber,
+ record.ldifLines, message);
}
- final void skipLDIFRecord(final LDIFRecord record,
- final LocalizableMessage message)
+ final void handleSchemaValidationFailure(final LDIFRecord record,
+ final List<LocalizableMessage> messages) throws DecodeException
{
- // FIXME: not yet implemented.
+ rejectedRecordListener.handleSchemaValidationFailure(record.lineNumber,
+ record.ldifLines, messages);
+ }
+
+
+
+ final void handleSkippedRecord(final LDIFRecord record,
+ final LocalizableMessage message) throws DecodeException
+ {
+ rejectedRecordListener.handleSkippedRecord(record.lineNumber,
+ record.ldifLines, message);
}
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFStream.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFStream.java
index 4ae83d8..6c7abe9 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFStream.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFStream.java
@@ -23,6 +23,7 @@
*
*
* Copyright 2009 Sun Microsystems, Inc.
+ * Portions copyright 2011 ForgeRock AS
*/
package org.forgerock.opendj.ldif;
@@ -39,7 +40,6 @@
import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.Matcher;
import org.forgerock.opendj.ldap.schema.AttributeType;
-import org.forgerock.opendj.ldap.schema.Schema;
@@ -57,8 +57,6 @@
final Set<AttributeDescription> includeAttributes = new HashSet<AttributeDescription>();
- Schema schema = Schema.getDefaultSchema();
-
final Set<DN> includeBranches = new HashSet<DN>();
final Set<DN> excludeBranches = new HashSet<DN>();
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFWriter.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFWriter.java
index 16de300..0a866a7 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFWriter.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFWriter.java
@@ -23,6 +23,7 @@
*
*
* Copyright 2009 Sun Microsystems, Inc.
+ * Portions copyright 2011 ForgeRock AS
*/
package org.forgerock.opendj.ldif;
@@ -39,6 +40,7 @@
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.controls.Control;
+import org.forgerock.opendj.ldap.schema.Schema;
import com.forgerock.opendj.util.Base64;
import com.forgerock.opendj.util.Validator;
@@ -253,6 +255,8 @@
private final StringBuilder builder = new StringBuilder(80);
+ Schema schema = Schema.getDefaultSchema();
+
/**
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/ChangeRecordWriter.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/ChangeRecordWriter.java
index a23a36a..0dfac63 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/ChangeRecordWriter.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/ChangeRecordWriter.java
@@ -43,8 +43,6 @@
/**
* An interface for writing change records to a data source, typically an LDIF
* file.
- * <p>
- * TODO: FilteredChangeRecordWriter
*/
public interface ChangeRecordWriter extends Closeable, Flushable
{
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/EntryWriter.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/EntryWriter.java
index afd60c0..b24b4df 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/EntryWriter.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/EntryWriter.java
@@ -39,8 +39,6 @@
/**
* An interface for writing entries to a data source, typically an LDIF file.
- * <p>
- * TODO: FilteredChangeRecordWriter
*/
public interface EntryWriter extends Closeable, Flushable
{
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java
index 0d0e7ed..df050fa 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java
@@ -35,10 +35,7 @@
import java.io.IOException;
import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.NoSuchElementException;
+import java.util.*;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
@@ -47,6 +44,7 @@
import org.forgerock.opendj.ldap.requests.ModifyRequest;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.schema.Schema;
+import org.forgerock.opendj.ldap.schema.UnknownSchemaElementException;
import com.forgerock.opendj.util.Validator;
@@ -335,6 +333,25 @@
/**
+ * Sets the rejected record listener which should be notified whenever a
+ * record is skipped, malformed, or fails schema validation.
+ * <p>
+ * By default the {@link RejectedRecordListener#FAIL_FAST} listener is used.
+ *
+ * @param listener
+ * The rejected record listener.
+ * @return A reference to this {@code LDIFChangeRecordReader}.
+ */
+ public LDIFChangeRecordReader setRejectedRecordListener(
+ final RejectedRecordListener listener)
+ {
+ this.rejectedRecordListener = listener;
+ return this;
+ }
+
+
+
+ /**
* Sets the schema which should be used for decoding change records that are
* read from LDIF. The default schema is used if no other is specified.
*
@@ -346,7 +363,8 @@
public LDIFChangeRecordReader setSchema(final Schema schema)
{
Validator.ensureNotNull(schema);
- this.schema = schema;
+ this.schema = validateSchema ? schema.asStrictSchema() : schema
+ .asNonStrictSchema();
return this;
}
@@ -354,7 +372,12 @@
/**
* Specifies whether or not schema validation should be performed for change
- * records that are read from LDIF. The default is {@code true} .
+ * records that are read from LDIF.
+ * <p>
+ * When enabled, the LDIF reader will implicitly use a strict schema so that
+ * unrecognized attribute types will be detected.
+ * <p>
+ * Schema validation is disabled by default.
*
* @param validateSchema
* {@code true} if schema validation should be performed, or
@@ -364,6 +387,8 @@
public LDIFChangeRecordReader setValidateSchema(final boolean validateSchema)
{
this.validateSchema = validateSchema;
+ this.schema = validateSchema ? schema.asStrictSchema() : schema
+ .asNonStrictSchema();
return this;
}
@@ -374,104 +399,92 @@
{
while (nextChangeRecord == null)
{
- LDIFRecord record = null;
-
// Read the set of lines that make up the next entry.
- record = readLDIFRecord();
+ final LDIFRecord record = readLDIFRecord();
if (record == null)
{
nextChangeRecord = EOF;
break;
}
- // Read the DN of the entry and see if it is one that should be
- // included in the import.
- DN entryDN;
try
{
- entryDN = readLDIFRecordDN(record);
+ // Read the DN of the entry and see if it is one that should be
+ // included in the import.
+ final DN entryDN = readLDIFRecordDN(record);
if (entryDN == null)
{
// Skip version record.
continue;
}
- }
- catch (final DecodeException e)
- {
- rejectLDIFRecord(record, e.getMessageObject());
- continue;
- }
- // Skip if branch containing the entry DN is excluded.
- if (isBranchExcluded(entryDN))
- {
- final LocalizableMessage message = LocalizableMessage
- .raw("Skipping entry because it is in excluded branch");
- skipLDIFRecord(record, message);
- continue;
- }
+ // Skip if branch containing the entry DN is excluded.
+ if (isBranchExcluded(entryDN))
+ {
+ final LocalizableMessage message = ERR_LDIF_CHANGE_EXCLUDED_BY_DN
+ .get(record.lineNumber, entryDN.toString());
+ handleSkippedRecord(record, message);
+ continue;
+ }
- ChangeRecord changeRecord = null;
- try
- {
if (!record.iterator.hasNext())
{
- // FIXME: improve error.
- final LocalizableMessage message = LocalizableMessage
- .raw("Missing changetype");
+ final LocalizableMessage message = ERR_LDIF_NO_CHANGE_TYPE.get(
+ record.lineNumber, entryDN.toString());
throw DecodeException.error(message);
}
final KeyValuePair pair = new KeyValuePair();
final String ldifLine = readLDIFRecordKeyValuePair(record, pair, false);
+ if (pair.key == null)
+ {
+ final LocalizableMessage message = ERR_LDIF_MALFORMED_CHANGE_TYPE
+ .get(record.lineNumber, entryDN.toString(), ldifLine);
+ throw DecodeException.error(message);
+ }
if (!toLowerCase(pair.key).equals("changetype"))
{
// Default to add change record.
- changeRecord = parseAddChangeRecordEntry(entryDN, ldifLine, record);
+ nextChangeRecord = parseAddChangeRecordEntry(entryDN, ldifLine,
+ record);
}
else
{
final String changeType = toLowerCase(pair.value);
if (changeType.equals("add"))
{
- changeRecord = parseAddChangeRecordEntry(entryDN, null, record);
+ nextChangeRecord = parseAddChangeRecordEntry(entryDN, null, record);
}
else if (changeType.equals("delete"))
{
- changeRecord = parseDeleteChangeRecordEntry(entryDN, record);
+ nextChangeRecord = parseDeleteChangeRecordEntry(entryDN, record);
}
else if (changeType.equals("modify"))
{
- changeRecord = parseModifyChangeRecordEntry(entryDN, record);
+ nextChangeRecord = parseModifyChangeRecordEntry(entryDN, record);
}
else if (changeType.equals("modrdn"))
{
- changeRecord = parseModifyDNChangeRecordEntry(entryDN, record);
+ nextChangeRecord = parseModifyDNChangeRecordEntry(entryDN, record);
}
else if (changeType.equals("moddn"))
{
- changeRecord = parseModifyDNChangeRecordEntry(entryDN, record);
+ nextChangeRecord = parseModifyDNChangeRecordEntry(entryDN, record);
}
else
{
- // FIXME: improve error.
- final LocalizableMessage message = ERR_LDIF_INVALID_CHANGETYPE_ATTRIBUTE
- .get(pair.value, "add, delete, modify, moddn, modrdn");
+ final LocalizableMessage message = ERR_LDIF_BAD_CHANGE_TYPE.get(
+ record.lineNumber, entryDN.toString(), pair.value);
throw DecodeException.error(message);
}
}
}
catch (final DecodeException e)
{
- rejectLDIFRecord(record, e.getMessageObject());
+ handleMalformedRecord(record, e.getMessageObject());
continue;
}
-
- if (changeRecord != null)
- {
- nextChangeRecord = changeRecord;
- }
}
return nextChangeRecord;
}
@@ -484,17 +497,24 @@
{
// Use an Entry for the AttributeSequence.
final Entry entry = new LinkedHashMapEntry(entryDN);
+ final List<LocalizableMessage> schemaErrors = new LinkedList<LocalizableMessage>();
if (lastLDIFLine != null)
{
// This line was read when looking for the change type.
- readLDIFRecordAttributeValue(record, lastLDIFLine, entry);
+ readLDIFRecordAttributeValue(record, lastLDIFLine, entry, schemaErrors);
}
while (record.iterator.hasNext())
{
final String ldifLine = record.iterator.next();
- readLDIFRecordAttributeValue(record, ldifLine, entry);
+ readLDIFRecordAttributeValue(record, ldifLine, entry, schemaErrors);
+ }
+
+ if (!schemaErrors.isEmpty())
+ {
+ handleSchemaValidationFailure(record, schemaErrors);
+ return null;
}
return Requests.newAddRequest(entry);
@@ -507,9 +527,8 @@
{
if (record.iterator.hasNext())
{
- // FIXME: include line number in error.
- final LocalizableMessage message = ERR_LDIF_INVALID_DELETE_ATTRIBUTES
- .get();
+ final LocalizableMessage message = ERR_LDIF_MALFORMED_DELETE.get(
+ record.lineNumber, entryDN.toString());
throw DecodeException.error(message);
}
@@ -525,10 +544,18 @@
final KeyValuePair pair = new KeyValuePair();
final List<ByteString> attributeValues = new ArrayList<ByteString>();
+ final List<LocalizableMessage> schemaErrors = new LinkedList<LocalizableMessage>();
while (record.iterator.hasNext())
{
- readLDIFRecordKeyValuePair(record, pair, false);
+ String ldifLine = readLDIFRecordKeyValuePair(record, pair, false);
+ if (pair.key == null)
+ {
+ final LocalizableMessage message = ERR_LDIF_MALFORMED_MODIFICATION_TYPE
+ .get(record.lineNumber, entryDN.toString(), ldifLine);
+ throw DecodeException.error(message);
+ }
+
final String changeType = toLowerCase(pair.key);
ModificationType modType;
@@ -550,9 +577,8 @@
}
else
{
- // FIXME: improve error.
- final LocalizableMessage message = ERR_LDIF_INVALID_MODIFY_ATTRIBUTE
- .get(pair.key, "add, delete, replace, increment");
+ final LocalizableMessage message = ERR_LDIF_BAD_MODIFICATION_TYPE.get(
+ record.lineNumber, entryDN.toString(), pair.key);
throw DecodeException.error(message);
}
@@ -561,9 +587,25 @@
{
attributeDescription = AttributeDescription.valueOf(pair.value, schema);
}
+ catch (final UnknownSchemaElementException e)
+ {
+ final LocalizableMessage message = ERR_LDIF_UNKNOWN_ATTRIBUTE_TYPE.get(
+ record.lineNumber, entryDN.toString(), pair.value);
+ if (validateSchema)
+ {
+ schemaErrors.add(message);
+ continue;
+ }
+ else
+ {
+ throw DecodeException.error(message);
+ }
+ }
catch (final LocalizedIllegalArgumentException e)
{
- throw DecodeException.error(e.getMessageObject());
+ final LocalizableMessage message = ERR_LDIF_MALFORMED_ATTRIBUTE_NAME
+ .get(record.lineNumber, entryDN.toString(), pair.value);
+ throw DecodeException.error(message);
}
// Skip the attribute if requested before performing any schema
@@ -580,9 +622,10 @@
{
if (validateSchema && attributeDescription.containsOption("binary"))
{
- final LocalizableMessage message = ERR_LDIF_INVALID_ATTR_OPTION.get(
- entryDN.toString(), record.lineNumber, pair.value);
- throw DecodeException.error(message);
+ final LocalizableMessage message = ERR_LDIF_UNEXPECTED_BINARY_OPTION
+ .get(record.lineNumber, entryDN.toString(), pair.value);
+ schemaErrors.add(message);
+ continue;
}
}
else
@@ -595,7 +638,7 @@
attributeValues.clear();
while (record.iterator.hasNext())
{
- final String ldifLine = record.iterator.next();
+ ldifLine = record.iterator.next();
if (ldifLine.equals("-"))
{
break;
@@ -613,7 +656,11 @@
}
catch (final LocalizedIllegalArgumentException e)
{
- throw DecodeException.error(e.getMessageObject());
+ // No need to catch schema exception here because it implies that the
+ // attribute name is wrong.
+ final LocalizableMessage message = ERR_LDIF_MALFORMED_ATTRIBUTE_NAME
+ .get(record.lineNumber, entryDN.toString(), attrDescr);
+ throw DecodeException.error(message);
}
// Ensure that the binary option is present if required.
@@ -625,9 +672,9 @@
if (!attributeDescription2.equals(attributeDescription))
{
- // TODO: include line number.
- final LocalizableMessage message = ERR_LDIF_INVALID_CHANGERECORD_ATTRIBUTE
- .get(attributeDescription2.toString(),
+ final LocalizableMessage message = ERR_LDIF_ATTRIBUTE_NAME_MISMATCH
+ .get(record.lineNumber, entryDN.toString(),
+ attributeDescription2.toString(),
attributeDescription.toString());
throw DecodeException.error(message);
}
@@ -642,6 +689,12 @@
modifyRequest.addModification(change);
}
+ if (!schemaErrors.isEmpty())
+ {
+ handleSchemaValidationFailure(record, schemaErrors);
+ return null;
+ }
+
return modifyRequest;
}
@@ -655,19 +708,18 @@
// Parse the newrdn.
if (!record.iterator.hasNext())
{
- // TODO: include line number.
- final LocalizableMessage message = ERR_LDIF_NO_MOD_DN_ATTRIBUTES.get();
+ final LocalizableMessage message = ERR_LDIF_NO_NEW_RDN.get(
+ record.lineNumber, entryDN.toString());
throw DecodeException.error(message);
}
final KeyValuePair pair = new KeyValuePair();
- String ldifLine = record.iterator.next();
- readLDIFRecordKeyValuePair(record, pair, true);
- if (!toLowerCase(pair.key).equals("newrdn"))
+ String ldifLine = readLDIFRecordKeyValuePair(record, pair, true);
+
+ if (pair.key == null || !toLowerCase(pair.key).equals("newrdn"))
{
- // FIXME: improve error.
- final LocalizableMessage message = LocalizableMessage
- .raw("Missing newrdn");
+ final LocalizableMessage message = ERR_LDIF_MALFORMED_NEW_RDN.get(
+ record.lineNumber, entryDN.toString(), ldifLine);
throw DecodeException.error(message);
}
@@ -678,27 +730,24 @@
}
catch (final LocalizedIllegalArgumentException e)
{
- final LocalizableMessage message = ERR_LDIF_INVALID_DN.get(
- record.lineNumber, ldifLine, e.getMessageObject());
+ final LocalizableMessage message = ERR_LDIF_MALFORMED_NEW_RDN.get(
+ record.lineNumber, entryDN.toString(), pair.value);
throw DecodeException.error(message);
}
// Parse the deleteoldrdn.
if (!record.iterator.hasNext())
{
- // TODO: include line number.
- final LocalizableMessage message = ERR_LDIF_NO_DELETE_OLDRDN_ATTRIBUTE
- .get();
+ final LocalizableMessage message = ERR_LDIF_NO_DELETE_OLD_RDN.get(
+ record.lineNumber, entryDN.toString());
throw DecodeException.error(message);
}
- ldifLine = record.iterator.next();
- readLDIFRecordKeyValuePair(record, pair, true);
- if (!toLowerCase(pair.key).equals("deleteoldrdn"))
+ ldifLine = readLDIFRecordKeyValuePair(record, pair, true);
+ if (pair.key == null || !toLowerCase(pair.key).equals("deleteoldrdn"))
{
- // FIXME: improve error.
- final LocalizableMessage message = LocalizableMessage
- .raw("Missing deleteoldrdn");
+ final LocalizableMessage message = ERR_LDIF_MALFORMED_DELETE_OLD_RDN.get(
+ record.lineNumber, entryDN.toString(), ldifLine);
throw DecodeException.error(message);
}
@@ -714,22 +763,19 @@
}
else
{
- // FIXME: improve error.
- final LocalizableMessage message = ERR_LDIF_INVALID_DELETE_OLDRDN_ATTRIBUTE
- .get(pair.value);
+ final LocalizableMessage message = ERR_LDIF_MALFORMED_DELETE_OLD_RDN.get(
+ record.lineNumber, entryDN.toString(), pair.value);
throw DecodeException.error(message);
}
// Parse the newsuperior if present.
if (record.iterator.hasNext())
{
- ldifLine = record.iterator.next();
- readLDIFRecordKeyValuePair(record, pair, true);
- if (!toLowerCase(pair.key).equals("newsuperior"))
+ ldifLine = readLDIFRecordKeyValuePair(record, pair, true);
+ if (pair.key == null || !toLowerCase(pair.key).equals("newsuperior"))
{
- // FIXME: improve error.
- final LocalizableMessage message = LocalizableMessage
- .raw("Missing newsuperior");
+ final LocalizableMessage message = ERR_LDIF_MALFORMED_NEW_SUPERIOR.get(
+ record.lineNumber, entryDN.toString(), ldifLine);
throw DecodeException.error(message);
}
@@ -740,8 +786,8 @@
}
catch (final LocalizedIllegalArgumentException e)
{
- final LocalizableMessage message = ERR_LDIF_INVALID_DN.get(
- record.lineNumber, ldifLine, e.getMessageObject());
+ final LocalizableMessage message = ERR_LDIF_MALFORMED_NEW_SUPERIOR.get(
+ record.lineNumber, entryDN.toString(), pair.value);
throw DecodeException.error(message);
}
}
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryReader.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryReader.java
index 6a891c1..5f13925 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryReader.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryReader.java
@@ -23,6 +23,7 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
+ * Portions copyright 2011 ForgeRock AS
*/
package org.forgerock.opendj.ldif;
@@ -34,6 +35,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
+import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
@@ -361,6 +363,25 @@
/**
+ * Sets the rejected record listener which should be notified whenever a
+ * record is skipped, malformed, or fails schema validation.
+ * <p>
+ * By default the {@link RejectedRecordListener#FAIL_FAST} listener is used.
+ *
+ * @param listener
+ * The rejected record listener.
+ * @return A reference to this {@code LDIFEntryReader}.
+ */
+ public LDIFEntryReader setRejectedRecordListener(
+ final RejectedRecordListener listener)
+ {
+ this.rejectedRecordListener = listener;
+ return this;
+ }
+
+
+
+ /**
* Sets the schema which should be used for decoding entries that are read
* from LDIF. The default schema is used if no other is specified.
*
@@ -372,7 +393,8 @@
public LDIFEntryReader setSchema(final Schema schema)
{
Validator.ensureNotNull(schema);
- this.schema = schema;
+ this.schema = validateSchema ? schema.asStrictSchema() : schema
+ .asNonStrictSchema();
return this;
}
@@ -380,7 +402,12 @@
/**
* Specifies whether or not schema validation should be performed for entries
- * that are read from LDIF. The default is {@code true}.
+ * that are read from LDIF.
+ * <p>
+ * When enabled, this LDIF reader will implicitly use a strict schema so that
+ * unrecognized attribute types will be detected.
+ * <p>
+ * Schema validation is disabled by default.
*
* @param validateSchema
* {@code true} if schema validation should be performed, or
@@ -390,6 +417,8 @@
public LDIFEntryReader setValidateSchema(final boolean validateSchema)
{
this.validateSchema = validateSchema;
+ this.schema = validateSchema ? schema.asStrictSchema() : schema
+ .asNonStrictSchema();
return this;
}
@@ -399,69 +428,65 @@
{
while (nextEntry == null)
{
- LDIFRecord record = null;
-
// Read the set of lines that make up the next entry.
- record = readLDIFRecord();
+ final LDIFRecord record = readLDIFRecord();
if (record == null)
{
nextEntry = EOF;
break;
}
- // Read the DN of the entry and see if it is one that should be
- // included in the import.
- DN entryDN;
try
{
- entryDN = readLDIFRecordDN(record);
+ // Read the DN of the entry and see if it is one that should be
+ // included in the import.
+ final DN entryDN = readLDIFRecordDN(record);
if (entryDN == null)
{
// Skip version record.
continue;
}
- }
- catch (final DecodeException e)
- {
- rejectLDIFRecord(record, e.getMessageObject());
- continue;
- }
- // Skip if branch containing the entry DN is excluded.
- if (isBranchExcluded(entryDN))
- {
- final LocalizableMessage message = LocalizableMessage
- .raw("Skipping entry because it is in excluded branch");
- skipLDIFRecord(record, message);
- continue;
- }
+ // Skip if branch containing the entry DN is excluded.
+ if (isBranchExcluded(entryDN))
+ {
+ final LocalizableMessage message = ERR_LDIF_ENTRY_EXCLUDED_BY_DN.get(
+ record.lineNumber, entryDN.toString());
+ handleSkippedRecord(record, message);
+ continue;
+ }
- // Use an Entry for the AttributeSequence.
- final Entry entry = new LinkedHashMapEntry(entryDN);
- try
- {
+ // Use an Entry for the AttributeSequence.
+ final Entry entry = new LinkedHashMapEntry(entryDN);
+ final List<LocalizableMessage> schemaErrors = new LinkedList<LocalizableMessage>();
while (record.iterator.hasNext())
{
final String ldifLine = record.iterator.next();
- readLDIFRecordAttributeValue(record, ldifLine, entry);
+ readLDIFRecordAttributeValue(record, ldifLine, entry, schemaErrors);
}
+
+ // Skip if the entry is excluded by any filters.
+ if (isEntryExcluded(entry))
+ {
+ final LocalizableMessage message = ERR_LDIF_ENTRY_EXCLUDED_BY_FILTER
+ .get(record.lineNumber, entryDN.toString());
+ handleSkippedRecord(record, message);
+ continue;
+ }
+
+ if (!schemaErrors.isEmpty())
+ {
+ handleSchemaValidationFailure(record, schemaErrors);
+ continue;
+ }
+
+ nextEntry = entry;
}
catch (final DecodeException e)
{
- rejectLDIFRecord(record, e.getMessageObject());
+ handleMalformedRecord(record, e.getMessageObject());
continue;
}
-
- // Skip if the entry is excluded by any filters.
- if (isEntryExcluded(entry))
- {
- final LocalizableMessage message = LocalizableMessage
- .raw("Skipping entry due to exclusing filters");
- skipLDIFRecord(record, message);
- continue;
- }
-
- nextEntry = entry;
}
return nextEntry;
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/RejectedRecordListener.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/RejectedRecordListener.java
new file mode 100644
index 0000000..79e167e
--- /dev/null
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/RejectedRecordListener.java
@@ -0,0 +1,141 @@
+/*
+ * 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
+ * trunk/opendj3/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
+ * trunk/opendj3/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 2011 ForgeRock AS
+ */
+
+package org.forgerock.opendj.ldif;
+
+
+
+import java.util.List;
+
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.ldap.DecodeException;
+
+
+
+/**
+ * A listener interface which is notified whenever records are skipped,
+ * malformed, or fail schema validation.
+ */
+public interface RejectedRecordListener
+{
+ /**
+ * The default handler which ignores skipped records but which terminates
+ * processing by throwing a {@code DecodeException} as soon as a record is
+ * found to be malformed or rejected due to a schema validation failure.
+ */
+ public static final RejectedRecordListener FAIL_FAST = new RejectedRecordListener()
+ {
+
+ @Override
+ public void handleMalformedRecord(final long lineNumber,
+ final List<String> ldifRecord, final LocalizableMessage reason)
+ throws DecodeException
+ {
+ // Fail fast.
+ throw DecodeException.error(reason);
+ }
+
+
+
+ @Override
+ public void handleSchemaValidationFailure(final long lineNumber,
+ final List<String> ldifRecord, final List<LocalizableMessage> reasons)
+ throws DecodeException
+ {
+ // Fail fast - just use first message.
+ throw DecodeException.error(reasons.get(0));
+ }
+
+
+
+ @Override
+ public void handleSkippedRecord(final long lineNumber,
+ final List<String> ldifRecord, final LocalizableMessage reason)
+ throws DecodeException
+ {
+ // Ignore skipped records.
+ }
+ };
+
+
+
+ /**
+ * Invoked when a record was rejected because it was malformed in some way and
+ * could not be decoded.
+ *
+ * @param lineNumber
+ * The line number within the source location in which the malformed
+ * record is located, if known, otherwise {@code -1}.
+ * @param ldifRecord
+ * An LDIF representation of the malformed record.
+ * @param reason
+ * The reason why the record is malformed.
+ * @throws DecodeException
+ * If processing should terminate.
+ */
+ void handleMalformedRecord(long lineNumber, List<String> ldifRecord,
+ LocalizableMessage reason) throws DecodeException;
+
+
+
+ /**
+ * Invoked when a record was rejected because it does not conform to the
+ * schema and schema validation is enabled.
+ *
+ * @param lineNumber
+ * The line number within the source location in which the rejected
+ * record is located, if known, otherwise {@code -1}.
+ * @param ldifRecord
+ * An LDIF representation of the record which failed schema
+ * validation.
+ * @param reasons
+ * The reasons why the record failed schema validation.
+ * @throws DecodeException
+ * If processing should terminate.
+ */
+ void handleSchemaValidationFailure(long lineNumber, List<String> ldifRecord,
+ List<LocalizableMessage> reasons) throws DecodeException;
+
+
+
+ /**
+ * Invoked when a record was skipped because it did not match filter criteria
+ * defined by the reader.
+ *
+ * @param lineNumber
+ * The line number within the source location in which the skipped
+ * record is located, if known, otherwise {@code -1}.
+ * @param ldifRecord
+ * An LDIF representation of the skipped record.
+ * @param reason
+ * The reason why the record was skipped.
+ * @throws DecodeException
+ * If processing should terminate.
+ */
+ void handleSkippedRecord(long lineNumber, List<String> ldifRecord,
+ LocalizableMessage reason) throws DecodeException;
+
+}
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core.properties b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core.properties
index 160c302..6c6c410 100755
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core.properties
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core.properties
@@ -477,8 +477,6 @@
failed and will be removed from the schema: %s
ERR_NO_SUBSCHEMA_SUBENTRY_ATTR=The entry %s does not include \
a subschemaSubentry attribute
-ERR_ATTRIBUTE_DESCRIPTION_TYPE_NOT_FOUND=The attribute description "%s" \
- could not be parsed due to the following reason: %s
ERR_RDN_TYPE_NOT_FOUND=The RDN "%s" could not be parsed due to the \
following reason: %s
ERR_DN_TYPE_NOT_FOUND=The DN "%s" could not be parsed due to the \
@@ -880,34 +878,12 @@
ERR_LDIF_COULD_NOT_BASE64_DECODE_ATTR=Unable to parse LDIF entry %s \
starting at line %d because it was not possible to base64-decode the \
attribute on line "%s": %s
-WARN_LDIF_DUPLICATE_ATTR=Entry %s read from LDIF starting at line %d \
- includes a duplicate attribute %s with value %s. The second occurrence of \
- that attribute value has been skipped
-ERR_LDIF_MULTIPLE_VALUES_FOR_SINGLE_VALUED_ATTR=Entry %s starting at \
- line %d includes multiple values for single-valued attribute %s
ERR_LDIF_INVALID_URL=Unable to parse LDIF entry %s starting at line \
%d because the value of attribute %s was to be read from a URL but the URL \
was invalid: %s
ERR_LDIF_URL_IO_ERROR=Unable to parse LDIF entry %s starting at line \
%d because the value of attribute %s was to be read from URL %s but an error \
occurred while trying to read that content: %s
-ERR_LDIF_INVALID_DELETE_ATTRIBUTES=Error in the LDIF change record \
- entry. Invalid attributes specified for the delete operation
-ERR_LDIF_NO_MOD_DN_ATTRIBUTES=Error in the LDIF change record \
- entry. No attributes specified for the mod DN operation
-ERR_LDIF_NO_DELETE_OLDRDN_ATTRIBUTE=Error in the LDIF change record \
- entry. No delete old RDN attribute specified for the mod DN operation
-ERR_LDIF_INVALID_DELETE_OLDRDN_ATTRIBUTE=Error in the LDIF change \
- record entry. Invalid value "%s" for the delete old RDN attribute specified \
- for the mod DN operation
-ERR_LDIF_INVALID_CHANGERECORD_ATTRIBUTE=Error in the LDIF change \
- record entry. Invalid attribute "%s" specified. Expecting attribute "%s"
-ERR_LDIF_INVALID_MODIFY_ATTRIBUTE=Error in the LDIF change record \
- entry. Invalid attribute "%s" specified. Expecting one of the following \
- attributes "%s"
-ERR_LDIF_INVALID_CHANGETYPE_ATTRIBUTE=Error in the LDIF change \
- record entry. Invalid value "%s" for the changetype specified. Expecting one \
- of the following values "%s"
ERR_LDAPURL_NO_SCHEME=The provided string "%s" cannot be decoded \
as an LDAP URL because it does not contain a protocol scheme
ERR_LDAPURL_BAD_SCHEME=The provided string "%s" cannot be decoded \
@@ -930,11 +906,6 @@
ERR_LDAPURL_INVALID_HEX_BYTE=The provided URL component "%s" could \
not be decoded because the character at byte %d was not a valid hexadecimal \
digit
-WARN_LDIF_VALUE_VIOLATES_SYNTAX=Entry %s read from LDIF starting at \
- line %d includes value "%s" for attribute %s that is invalid according to the \
- associated syntax: %s
-ERR_LDIF_INVALID_ATTR_OPTION=Unable to parse LDIF entry %s starting \
- at line %d because it has an invalid binary option for attribute %s
ERR_INVALID_ESCAPE_CHAR=The value %s cannot be decoded because %c \
is not a valid escape character
WARN_READ_LDIF_RECORD_NO_CHANGE_RECORD_FOUND=The provided LDIF \
@@ -1303,3 +1274,58 @@
the optional attribute "%s" which is not defined in the schema
WARN_ATTR_SYNTAX_NOT_IMPLEMENTED1=The "%s" syntax with OID %s is not \
implemented. It will be substituted by the default syntax with OID %s
+ERR_LDIF_ENTRY_EXCLUDED_BY_DN=Skipping LDIF entry starting at line %d with \
+ distinguished name "%s" because it is within an excluded branch
+ERR_LDIF_ENTRY_EXCLUDED_BY_FILTER=Skipping LDIF entry starting at line %d with \
+ distinguished name "%s" because it does not meet the filter criteria
+ERR_LDIF_CHANGE_EXCLUDED_BY_DN=Skipping LDIF change record starting at line %d \
+ with distinguished name "%s" because it is within an excluded branch
+ERR_LDIF_NO_CHANGE_TYPE=Unable to parse LDIF change record starting at line %d \
+ with distinguished name "%s" because there was no change type
+ERR_LDIF_MALFORMED_CHANGE_TYPE=Unable to parse LDIF change record starting at line %d \
+ with distinguished name "%s" because it contained a malformed changetype \
+ "%s"
+ERR_LDIF_BAD_CHANGE_TYPE=Unable to parse LDIF change record starting at line %d \
+ with distinguished name "%s" because it contained an unrecognized changetype \
+ "%s". The changetype must be one of add, delete, modify, modrdn, or moddn
+ERR_LDIF_MALFORMED_DELETE=Unable to parse LDIF delete record starting at line %d \
+ with distinguished name "%s" because it contained additional lines after the \
+ changetype when none were expected
+ERR_LDIF_BAD_MODIFICATION_TYPE=Unable to parse LDIF modify record starting at line %d \
+ with distinguished name "%s" because it contained an unrecognized modification type \
+ "%s". The modification type must be one of add, delete, replace, or increment
+ERR_LDIF_MALFORMED_MODIFICATION_TYPE=Unable to parse LDIF modify record starting at line %d \
+ with distinguished name "%s" because it contained a malformed modification type \
+ "%s"
+ERR_LDIF_UNKNOWN_ATTRIBUTE_TYPE=Rejecting the LDIF change record \
+ starting at line %d with distinguished name "%s" because it contains an \
+ unrecognized attribute type "%s"
+ERR_LDIF_MALFORMED_ATTRIBUTE_NAME=Unable to parse LDIF change record \
+ starting at line %d with distinguished name "%s" because it contained a \
+ malformed attribute description "%s"
+ERR_LDIF_UNEXPECTED_BINARY_OPTION=Unable to parse LDIF change record starting \
+ at line %d with distinguished name "%s" because it has an unexpected binary \
+ option for attribute %s
+ERR_LDIF_ATTRIBUTE_NAME_MISMATCH=Unable to parse LDIF change record \
+ starting at line %d with distinguished name "%s" because it contained a \
+ an unexpected attribute "%s" when "%s" was expected
+WARN_LDIF_MALFORMED_ATTRIBUTE_VALUE=Rejecting the LDIF change record \
+ starting at line %d with distinguished name "%s" because it includes the \
+ value "%s" for attribute "%s" which is invalid according to the syntax: %s
+WARN_LDIF_DUPLICATE_ATTRIBUTE_VALUE=Rejecting the LDIF change record \
+ starting at line %d with distinguished name "%s" because it includes a \
+ duplicate attribute "%s" with value "%s"
+ERR_LDIF_MULTI_VALUED_SINGLE_VALUED_ATTRIBUTE=Rejecting the LDIF change record \
+ starting at line %d with distinguished name "%s" because it includes multiple \
+ values for single-valued attribute "%s"
+ERR_LDIF_NO_NEW_RDN=Unable to parse LDIF modify DN record starting at line %d \
+ with distinguished name "%s" because there was no new RDN
+ERR_LDIF_MALFORMED_NEW_RDN=Unable to parse LDIF modify DN record starting at line %d \
+ with distinguished name "%s" because it contained a malformed new RDN "%s"
+ERR_LDIF_NO_DELETE_OLD_RDN=Unable to parse LDIF modify DN record starting at line %d \
+ with distinguished name "%s" because there was no deleteoldrdn field
+ERR_LDIF_MALFORMED_DELETE_OLD_RDN=Unable to parse LDIF modify DN record starting at line %d \
+ with distinguished name "%s" because it contained a malformed deleteoldrdn "%s"
+ERR_LDIF_MALFORMED_NEW_SUPERIOR=Unable to parse LDIF modify DN record starting at line %d \
+ with distinguished name "%s" because it contained a malformed newsuperior "%s"
+
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
index fa053f4..0ba30b8 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
@@ -345,7 +345,7 @@
+ "caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch "
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )",
false);
- final Schema testSchema = builder.toSchema().nonStrict();
+ final Schema testSchema = builder.toSchema().asNonStrictSchema();
assertThat(testSchema.getWarnings()).isEmpty();
Schema.setDefaultSchema(testSchema);
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptionsTest.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptionsTest.java
index 22cbc8e..69d9e7d 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptionsTest.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptionsTest.java
@@ -87,7 +87,7 @@
SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema())
.setSchemaCompatOptions(SchemaCompatOptions.defaultOptions()
.allowMalformedNamesAndOptions(allowIllegalCharacters));
- Schema schema = builder.toSchema().nonStrict();
+ Schema schema = builder.toSchema().asNonStrictSchema();
AttributeDescription.valueOf(atd, schema);
}
@@ -136,7 +136,7 @@
SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema())
.setSchemaCompatOptions(SchemaCompatOptions.defaultOptions()
.allowMalformedNamesAndOptions(allowIllegalCharacters));
- Schema schema = builder.toSchema().nonStrict();
+ Schema schema = builder.toSchema().asNonStrictSchema();
AttributeDescription.valueOf(atd, schema);
}
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFChangeRecordReaderTestCase.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFChangeRecordReaderTestCase.java
new file mode 100644
index 0000000..cfbce2f
--- /dev/null
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFChangeRecordReaderTestCase.java
@@ -0,0 +1,471 @@
+/*
+ * 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
+ * trunk/opendj3/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
+ * trunk/opendj3/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 2011 ForgeRock AS
+ */
+
+package org.forgerock.opendj.ldif;
+
+
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.ldap.*;
+import org.forgerock.opendj.ldap.requests.AddRequest;
+import org.forgerock.opendj.ldap.requests.DeleteRequest;
+import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
+import org.forgerock.opendj.ldap.requests.ModifyRequest;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * This class tests the LDIFChangeRecordReader functionality.
+ */
+public final class LDIFChangeRecordReaderTestCase extends LDIFTestCase
+{
+ /**
+ * Tests reading a valid add change record with a changetype.
+ *
+ * @throws Exception
+ * if an unexpected error occurred.
+ */
+ @Test
+ public void testReadAddRecordWithChangeType() throws Exception
+ {
+ // @formatter:off
+ LDIFChangeRecordReader reader = new LDIFChangeRecordReader(
+ "dn: dc=example,dc=com",
+ "changetype: add",
+ "objectClass: top",
+ "objectClass: domainComponent",
+ "dc: example"
+ );
+ // @formatter:on
+
+ assertThat(reader.hasNext()).isTrue();
+ ChangeRecord record = reader.readChangeRecord();
+ assertThat(record).isInstanceOf(AddRequest.class);
+ AddRequest addRequest = (AddRequest) record;
+ assertThat((Object) addRequest.getName()).isEqualTo(
+ DN.valueOf("dc=example,dc=com"));
+ assertThat(
+ addRequest.containsAttribute("objectClass", "top", "domainComponent"))
+ .isTrue();
+ assertThat(addRequest.containsAttribute("dc", "example")).isTrue();
+ assertThat(addRequest.getAttributeCount()).isEqualTo(2);
+ }
+
+
+
+ /**
+ * Tests reading a valid add change record without a changetype.
+ *
+ * @throws Exception
+ * if an unexpected error occurred.
+ */
+ @Test
+ public void testReadAddRecordWithoutChangeType() throws Exception
+ {
+ // @formatter:off
+ LDIFChangeRecordReader reader = new LDIFChangeRecordReader(
+ "dn: dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: domainComponent",
+ "dc: example"
+ );
+ // @formatter:on
+
+ assertThat(reader.hasNext()).isTrue();
+ ChangeRecord record = reader.readChangeRecord();
+ assertThat(record).isInstanceOf(AddRequest.class);
+ AddRequest addRequest = (AddRequest) record;
+ assertThat((Object) addRequest.getName()).isEqualTo(
+ DN.valueOf("dc=example,dc=com"));
+ assertThat(
+ addRequest.containsAttribute("objectClass", "top", "domainComponent"))
+ .isTrue();
+ assertThat(addRequest.containsAttribute("dc", "example")).isTrue();
+ assertThat(addRequest.getAttributeCount()).isEqualTo(2);
+ }
+
+
+
+ /**
+ * Tests reading a valid modify change record.
+ *
+ * @throws Exception
+ * if an unexpected error occurred.
+ */
+ @Test
+ public void testReadModifyRecord() throws Exception
+ {
+ // @formatter:off
+ LDIFChangeRecordReader reader = new LDIFChangeRecordReader(
+ "dn: dc=example,dc=com",
+ "changetype: modify",
+ "add: description",
+ "-",
+ "add: description",
+ "description: value1",
+ "-",
+ "add: description",
+ "description: value1",
+ "description: value2",
+ "-",
+ "delete: description",
+ "-",
+ "delete: description",
+ "description: value1",
+ "-",
+ "delete: description",
+ "description: value1",
+ "description: value2",
+ "-",
+ "replace: description",
+ "-",
+ "replace: description",
+ "description: value1",
+ "-",
+ "replace: description",
+ "description: value1",
+ "description: value2",
+ "-",
+ "increment: description",
+ "description: 1"
+ );
+ // @formatter:on
+
+ assertThat(reader.hasNext()).isTrue();
+ ChangeRecord record = reader.readChangeRecord();
+ assertThat(record).isInstanceOf(ModifyRequest.class);
+ ModifyRequest modifyRequest = (ModifyRequest) record;
+ assertThat((Object) modifyRequest.getName()).isEqualTo(
+ DN.valueOf("dc=example,dc=com"));
+
+ Iterator<Modification> changes = modifyRequest.getModifications()
+ .iterator();
+ Modification modification;
+
+ modification = changes.next();
+ assertThat(modification.getModificationType()).isEqualTo(
+ ModificationType.ADD);
+ assertThat(modification.getAttribute()).isEqualTo(
+ new LinkedAttribute("description"));
+
+ modification = changes.next();
+ assertThat(modification.getModificationType()).isEqualTo(
+ ModificationType.ADD);
+ assertThat(modification.getAttribute()).isEqualTo(
+ new LinkedAttribute("description", "value1"));
+
+ modification = changes.next();
+ assertThat(modification.getModificationType()).isEqualTo(
+ ModificationType.ADD);
+ assertThat(modification.getAttribute()).isEqualTo(
+ new LinkedAttribute("description", "value1", "value2"));
+
+ modification = changes.next();
+ assertThat(modification.getModificationType()).isEqualTo(
+ ModificationType.DELETE);
+ assertThat(modification.getAttribute()).isEqualTo(
+ new LinkedAttribute("description"));
+
+ modification = changes.next();
+ assertThat(modification.getModificationType()).isEqualTo(
+ ModificationType.DELETE);
+ assertThat(modification.getAttribute()).isEqualTo(
+ new LinkedAttribute("description", "value1"));
+
+ modification = changes.next();
+ assertThat(modification.getModificationType()).isEqualTo(
+ ModificationType.DELETE);
+ assertThat(modification.getAttribute()).isEqualTo(
+ new LinkedAttribute("description", "value1", "value2"));
+
+ modification = changes.next();
+ assertThat(modification.getModificationType()).isEqualTo(
+ ModificationType.REPLACE);
+ assertThat(modification.getAttribute()).isEqualTo(
+ new LinkedAttribute("description"));
+
+ modification = changes.next();
+ assertThat(modification.getModificationType()).isEqualTo(
+ ModificationType.REPLACE);
+ assertThat(modification.getAttribute()).isEqualTo(
+ new LinkedAttribute("description", "value1"));
+
+ modification = changes.next();
+ assertThat(modification.getModificationType()).isEqualTo(
+ ModificationType.REPLACE);
+ assertThat(modification.getAttribute()).isEqualTo(
+ new LinkedAttribute("description", "value1", "value2"));
+
+ modification = changes.next();
+ assertThat(modification.getModificationType()).isEqualTo(
+ ModificationType.INCREMENT);
+ assertThat(modification.getAttribute()).isEqualTo(
+ new LinkedAttribute("description", "1"));
+
+ assertThat(changes.hasNext()).isFalse();
+ }
+
+
+
+ /**
+ * Tests reading a valid delete change record.
+ *
+ * @throws Exception
+ * if an unexpected error occurred.
+ */
+ @Test
+ public void testReadDeleteRecord() throws Exception
+ {
+ // @formatter:off
+ LDIFChangeRecordReader reader = new LDIFChangeRecordReader(
+ "dn: dc=example,dc=com",
+ "changetype: delete"
+ );
+ // @formatter:on
+
+ assertThat(reader.hasNext()).isTrue();
+ ChangeRecord record = reader.readChangeRecord();
+ assertThat(record).isInstanceOf(DeleteRequest.class);
+ DeleteRequest deleteRequest = (DeleteRequest) record;
+ assertThat((Object) deleteRequest.getName()).isEqualTo(
+ DN.valueOf("dc=example,dc=com"));
+ }
+
+
+
+ /**
+ * Tests reading a valid moddn change record.
+ *
+ * @throws Exception
+ * if an unexpected error occurred.
+ */
+ @Test
+ public void testReadModdnRecordWithoutNewSuperior() throws Exception
+ {
+ // @formatter:off
+ LDIFChangeRecordReader reader = new LDIFChangeRecordReader(
+ "dn: dc=example,dc=com",
+ "changetype: moddn",
+ "newrdn: dc=eggsample",
+ "deleteoldrdn: true"
+ );
+ // @formatter:on
+
+ assertThat(reader.hasNext()).isTrue();
+ ChangeRecord record = reader.readChangeRecord();
+ assertThat(record).isInstanceOf(ModifyDNRequest.class);
+ ModifyDNRequest modifyDNRequest = (ModifyDNRequest) record;
+ assertThat((Object) modifyDNRequest.getName()).isEqualTo(
+ DN.valueOf("dc=example,dc=com"));
+ assertThat((Object) modifyDNRequest.getNewRDN()).isEqualTo(
+ RDN.valueOf("dc=eggsample"));
+ assertThat(modifyDNRequest.isDeleteOldRDN()).isTrue();
+ assertThat(modifyDNRequest.getNewSuperior()).isNull();
+ }
+
+
+
+ /**
+ * Tests reading a valid moddn change record.
+ *
+ * @throws Exception
+ * if an unexpected error occurred.
+ */
+ @Test
+ public void testReadModdnRecordWithNewSuperior() throws Exception
+ {
+ // @formatter:off
+ LDIFChangeRecordReader reader = new LDIFChangeRecordReader(
+ "dn: dc=example,dc=com",
+ "changetype: moddn",
+ "newrdn: dc=eggsample",
+ "deleteoldrdn: true",
+ "newsuperior: dc=org"
+ );
+ // @formatter:on
+
+ assertThat(reader.hasNext()).isTrue();
+ ChangeRecord record = reader.readChangeRecord();
+ assertThat(record).isInstanceOf(ModifyDNRequest.class);
+ ModifyDNRequest modifyDNRequest = (ModifyDNRequest) record;
+ assertThat((Object) modifyDNRequest.getName()).isEqualTo(
+ DN.valueOf("dc=example,dc=com"));
+ assertThat((Object) modifyDNRequest.getNewRDN()).isEqualTo(
+ RDN.valueOf("dc=eggsample"));
+ assertThat(modifyDNRequest.isDeleteOldRDN()).isTrue();
+ assertThat((Object) modifyDNRequest.getNewSuperior()).isEqualTo(
+ DN.valueOf("dc=org"));
+ }
+
+
+
+ /**
+ * Tests reading a malformed record invokes the rejected record listener.
+ *
+ * @throws Exception
+ * if an unexpected error occurred.
+ */
+ @Test
+ public void testRejectedRecordListenerMalformedFirstRecord() throws Exception
+ {
+ RejectedRecordListener listener = mock(RejectedRecordListener.class);
+
+ // @formatter:off
+ LDIFChangeRecordReader reader = new LDIFChangeRecordReader(
+ "dn: baddn",
+ "changetype: add",
+ "objectClass: top",
+ "objectClass: domainComponent",
+ "dc: example"
+ ).setRejectedRecordListener(listener);
+ // @formatter:on
+
+ assertThat(reader.hasNext()).isFalse();
+
+ verify(listener).handleMalformedRecord(
+ eq(1L),
+ eq(Arrays.asList("dn: baddn", "changetype: add", "objectClass: top",
+ "objectClass: domainComponent", "dc: example")),
+ any(LocalizableMessage.class));
+ }
+
+
+
+ /**
+ * Tests reading a malformed record invokes the rejected record listener.
+ *
+ * @throws Exception
+ * if an unexpected error occurred.
+ */
+ @Test
+ public void testRejectedRecordListenerMalformedSecondRecord()
+ throws Exception
+ {
+ RejectedRecordListener listener = mock(RejectedRecordListener.class);
+
+ // @formatter:off
+ LDIFChangeRecordReader reader = new LDIFChangeRecordReader(
+ "dn: dc=example,dc=com",
+ "changetype: add",
+ "objectClass: top",
+ "objectClass: domainComponent",
+ "dc: example",
+ "",
+ "dn: baddn",
+ "changetype: add",
+ "objectClass: top",
+ "objectClass: domainComponent",
+ "dc: example"
+ ).setRejectedRecordListener(listener);
+ // @formatter:on
+
+ reader.readChangeRecord(); // Skip good record.
+ assertThat(reader.hasNext()).isFalse();
+
+ verify(listener).handleMalformedRecord(
+ eq(7L),
+ eq(Arrays.asList("dn: baddn", "changetype: add", "objectClass: top",
+ "objectClass: domainComponent", "dc: example")),
+ any(LocalizableMessage.class));
+ }
+
+
+
+ /**
+ * Tests reading a skipped record invokes the rejected record listener.
+ *
+ * @throws Exception
+ * if an unexpected error occurred.
+ */
+ @Test
+ public void testRejectedRecordListenerSkipsRecord() throws Exception
+ {
+ RejectedRecordListener listener = mock(RejectedRecordListener.class);
+
+ // @formatter:off
+ LDIFChangeRecordReader reader = new LDIFChangeRecordReader(
+ "dn: dc=example,dc=com",
+ "changetype: add",
+ "objectClass: top",
+ "objectClass: domainComponent",
+ "dc: example"
+ ).setRejectedRecordListener(listener).setExcludeBranch(DN.valueOf("dc=com"));
+ // @formatter:on
+
+ assertThat(reader.hasNext()).isFalse();
+
+ verify(listener)
+ .handleSkippedRecord(
+ eq(1L),
+ eq(Arrays.asList("dn: dc=example,dc=com", "changetype: add",
+ "objectClass: top", "objectClass: domainComponent",
+ "dc: example")), any(LocalizableMessage.class));
+ }
+
+
+
+ /**
+ * Tests reading a record which does not conform to the schema invokes the
+ * rejected record listener.
+ *
+ * @throws Exception
+ * if an unexpected error occurred.
+ */
+ @Test
+ public void testRejectedRecordListenerRejectsBadSchemaRecord()
+ throws Exception
+ {
+ RejectedRecordListener listener = mock(RejectedRecordListener.class);
+
+ // @formatter:off
+ LDIFChangeRecordReader reader = new LDIFChangeRecordReader(
+ "dn: dc=example,dc=com",
+ "changetype: add",
+ "objectClass: top",
+ "objectClass: domainComponent",
+ "dc: example",
+ "xxx: unknown attribute"
+ ).setRejectedRecordListener(listener).setValidateSchema(true);
+ // @formatter:on
+
+ assertThat(reader.hasNext()).isFalse();
+
+ verify(listener).handleSchemaValidationFailure(
+ eq(1L),
+ eq(Arrays.asList("dn: dc=example,dc=com", "changetype: add",
+ "objectClass: top", "objectClass: domainComponent", "dc: example",
+ "xxx: unknown attribute")), anyListOf(LocalizableMessage.class));
+ }
+}
--
Gitblit v1.10.0