From a849a42d97109bc9242c50c7abbd9857e865bb5e Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Fri, 24 Jun 2011 14:57:52 +0000
Subject: [PATCH] Fix OPENDJ-205: Add support for rejecting and skipping records to the LDIF readers
---
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java | 50
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java | 639 ++++++----
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java | 122 +
/dev/null | 227 ---
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaValidationPolicy.java | 505 ++++++++
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java | 133 +
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatTest.java | 16
opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core.properties | 45
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringSyntaxImpl.java | 4
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFEntryReaderTestCase.java | 4
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java | 1401 ++++++++++++++++++----
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryReader.java | 50
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFChangeRecordReaderTestCase.java | 56
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRule.java | 52
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/TelephoneNumberSyntaxImpl.java | 2
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/RejectedRecordListener.java | 28
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entries.java | 225 +++
17 files changed, 2,663 insertions(+), 896 deletions(-)
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entries.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entries.java
index 9e0f33c..de67fc7 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entries.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entries.java
@@ -23,18 +23,22 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
+ * Portions copyright 2011 ForgeRock AS
*/
package org.forgerock.opendj.ldap;
-import java.util.Collection;
-import java.util.Iterator;
+import static org.forgerock.opendj.ldap.AttributeDescription.objectClass;
+import java.util.*;
+
+import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
import org.forgerock.opendj.ldap.requests.Requests;
+import org.forgerock.opendj.ldap.schema.*;
import com.forgerock.opendj.util.Function;
import com.forgerock.opendj.util.Iterables;
@@ -352,6 +356,79 @@
/**
+ * Returns {@code true} if the provided entry is valid according to the
+ * specified schema and schema validation policy.
+ * <p>
+ * If attribute value validation is enabled then following checks will be
+ * performed:
+ * <ul>
+ * <li>checking that there is at least one value
+ * <li>checking that single-valued attributes contain only a single value
+ * </ul>
+ * In particular, attribute values will not be checked for conformance to
+ * their syntax since this is expected to have already been performed while
+ * adding the values to the entry.
+ *
+ * @param entry
+ * The entry to be validated.
+ * @param schema
+ * The schema against which the entry will be validated.
+ * @param policy
+ * The schema validation policy.
+ * @param errorMessages
+ * A collection into which any schema validation warnings or error
+ * messages can be placed, or {@code null} if they should not be
+ * saved.
+ * @return {@code true} if the provided entry is valid according to the
+ * specified schema and schema validation policy.
+ * @see Schema#validateEntry(Entry, SchemaValidationPolicy, Collection)
+ */
+ public static boolean conformsToSchema(final Entry entry,
+ final Schema schema, final SchemaValidationPolicy policy,
+ final Collection<LocalizableMessage> errorMessages)
+ {
+ return schema.validateEntry(entry, policy, errorMessages);
+ }
+
+
+
+ /**
+ * Returns {@code true} if the provided entry is valid according to the
+ * default schema and schema validation policy.
+ * <p>
+ * If attribute value validation is enabled then following checks will be
+ * performed:
+ * <ul>
+ * <li>checking that there is at least one value
+ * <li>checking that single-valued attributes contain only a single value
+ * </ul>
+ * In particular, attribute values will not be checked for conformance to
+ * their syntax since this is expected to have already been performed while
+ * adding the values to the entry.
+ *
+ * @param entry
+ * The entry to be validated.
+ * @param policy
+ * The schema validation policy.
+ * @param errorMessages
+ * A collection into which any schema validation warnings or error
+ * messages can be placed, or {@code null} if they should not be
+ * saved.
+ * @return {@code true} if the provided entry is valid according to the
+ * default schema and schema validation policy.
+ * @see Schema#validateEntry(Entry, SchemaValidationPolicy, Collection)
+ */
+ public static boolean conformsToSchema(final Entry entry,
+ final SchemaValidationPolicy policy,
+ final Collection<LocalizableMessage> errorMessages)
+ {
+ return conformsToSchema(entry, Schema.getDefaultSchema(), policy,
+ errorMessages);
+ }
+
+
+
+ /**
* Creates a new modify request containing a list of modifications which can
* be used to transform {@code fromEntry} into entry {@code toEntry}.
* <p>
@@ -379,7 +456,7 @@
* If {@code fromEntry} or {@code toEntry} were {@code null}.
* @see Requests#newModifyRequest(Entry, Entry)
*/
- public static final ModifyRequest diffEntries(final Entry fromEntry,
+ public static ModifyRequest diffEntries(final Entry fromEntry,
final Entry toEntry) throws NullPointerException
{
Validator.ensureNotNull(fromEntry, toEntry);
@@ -488,6 +565,146 @@
/**
+ * Returns an unmodifiable set containing the object classes associated with
+ * the provided entry. This method will ignore unrecognized object classes.
+ * <p>
+ * This method uses the default schema for decoding the object class attribute
+ * values.
+ *
+ * @param entry
+ * The entry whose object classes are required.
+ * @return An unmodifiable set containing the object classes associated with
+ * the provided entry.
+ */
+ public static Set<ObjectClass> getObjectClasses(final Entry entry)
+ {
+ return getObjectClasses(entry, Schema.getDefaultSchema());
+ }
+
+
+
+ /**
+ * Returns an unmodifiable set containing the object classes associated with
+ * the provided entry. This method will ignore unrecognized object classes.
+ *
+ * @param entry
+ * The entry whose object classes are required.
+ * @param schema
+ * The schema which should be used for decoding the object class
+ * attribute values.
+ * @return An unmodifiable set containing the object classes associated with
+ * the provided entry.
+ */
+ public static Set<ObjectClass> getObjectClasses(final Entry entry,
+ final Schema schema)
+ {
+ final Attribute objectClassAttribute = entry
+ .getAttribute(AttributeDescription.objectClass());
+ if (objectClassAttribute == null)
+ {
+ return Collections.emptySet();
+ }
+ else
+ {
+ final Set<ObjectClass> objectClasses = new HashSet<ObjectClass>(
+ objectClassAttribute.size());
+ for (final ByteString v : objectClassAttribute)
+ {
+ final String objectClassName = v.toString();
+ final ObjectClass objectClass;
+ try
+ {
+ objectClass = schema.getObjectClass(objectClassName);
+ objectClasses.add(objectClass);
+ }
+ catch (final UnknownSchemaElementException e)
+ {
+ // Ignore.
+ continue;
+ }
+ }
+ return Collections.unmodifiableSet(objectClasses);
+ }
+ }
+
+
+
+ /**
+ * Returns the structural object class associated with the provided entry, or
+ * {@code null} if none was found. If the entry contains multiple structural
+ * object classes then the first will be returned. This method will ignore
+ * unrecognized object classes.
+ * <p>
+ * This method uses the default schema for decoding the object class attribute
+ * values.
+ *
+ * @param entry
+ * The entry whose structural object class is required.
+ * @return The structural object class associated with the provided entry, or
+ * {@code null} if none was found.
+ */
+ public static ObjectClass getStructuralObjectClass(final Entry entry)
+ {
+ return getStructuralObjectClass(entry, Schema.getDefaultSchema());
+ }
+
+
+
+ /**
+ * Returns the structural object class associated with the provided entry, or
+ * {@code null} if none was found. If the entry contains multiple structural
+ * object classes then the first will be returned. This method will ignore
+ * unrecognized object classes.
+ *
+ * @param entry
+ * The entry whose structural object class is required.
+ * @param schema
+ * The schema which should be used for decoding the object class
+ * attribute values.
+ * @return The structural object class associated with the provided entry, or
+ * {@code null} if none was found.
+ */
+ public static ObjectClass getStructuralObjectClass(final Entry entry,
+ final Schema schema)
+ {
+ ObjectClass structuralObjectClass = null;
+ final Attribute objectClassAttribute = entry.getAttribute(objectClass());
+
+ if (objectClassAttribute == null)
+ {
+ return null;
+ }
+
+ for (final ByteString v : objectClassAttribute)
+ {
+ final String objectClassName = v.toString();
+ final ObjectClass objectClass;
+ try
+ {
+ objectClass = schema.getObjectClass(objectClassName);
+ }
+ catch (final UnknownSchemaElementException e)
+ {
+ // Ignore.
+ continue;
+ }
+
+ if (objectClass.getObjectClassType() == ObjectClassType.STRUCTURAL)
+ {
+ if (structuralObjectClass == null
+ || objectClass.isDescendantOf(structuralObjectClass))
+ {
+ structuralObjectClass = objectClass;
+ }
+ }
+ }
+
+ return structuralObjectClass;
+ }
+
+
+
+ /**
* Returns a read-only view of {@code entry} and its attributes. Query
* operations on the returned entry and its attributes "read-through" to the
* underlying entry or attribute, and attempts to modify the returned entry
@@ -500,7 +717,7 @@
* @throws NullPointerException
* If {@code entry} was {@code null}.
*/
- public static final Entry unmodifiableEntry(final Entry entry)
+ public static Entry unmodifiableEntry(final Entry entry)
throws NullPointerException
{
return new UnmodifiableEntry(entry);
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRule.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRule.java
index 63b3c08..bb898db 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRule.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRule.java
@@ -23,6 +23,7 @@
*
*
* Copyright 2009 Sun Microsystems, Inc.
+ * Portions copyright 2011 ForgeRock AS
*/
package org.forgerock.opendj.ldap.schema;
@@ -42,7 +43,7 @@
/**
* This class defines a DIT content rule, which defines the set of allowed,
* required, and prohibited attributes for entries with a given structural
- * objectclass, and also indicates which auxiliary classes that may be included
+ * objectclass, and also indicates which auxiliary classes may be included
* in the entry.
*/
public final class DITContentRule extends SchemaElement
@@ -287,6 +288,55 @@
/**
+ * Indicates whether the provided attribute type is included in the optional
+ * attribute list for this DIT content rule.
+ *
+ * @param attributeType
+ * The attribute type for which to make the determination.
+ * @return <code>true</code> if the provided attribute type is optional for
+ * this DIT content rule, or <code>false</code> if not.
+ */
+ public boolean isOptional(final AttributeType attributeType)
+ {
+ return optionalAttributes.contains(attributeType);
+ }
+
+
+
+ /**
+ * Indicates whether the provided attribute type is included in the required
+ * attribute list for this DIT content rule.
+ *
+ * @param attributeType
+ * The attribute type for which to make the determination.
+ * @return <code>true</code> if the provided attribute type is required by
+ * this DIT content rule, or <code>false</code> if not.
+ */
+ public boolean isRequired(final AttributeType attributeType)
+ {
+ return requiredAttributes.contains(attributeType);
+ }
+
+
+
+ /**
+ * Indicates whether the provided attribute type is in the list of required or
+ * optional attributes for this DIT content rule.
+ *
+ * @param attributeType
+ * The attribute type for which to make the determination.
+ * @return <code>true</code> if the provided attribute type is required or
+ * allowed for this DIT content rule, or <code>false</code> if it is
+ * not.
+ */
+ public boolean isRequiredOrOptional(final AttributeType attributeType)
+ {
+ return isRequired(attributeType) || isOptional(attributeType);
+ }
+
+
+
+ /**
* Returns the string representation of this schema definition in the form
* specified in RFC 2252.
*
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringSyntaxImpl.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringSyntaxImpl.java
index c1d3bff..a395e9e 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringSyntaxImpl.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringSyntaxImpl.java
@@ -109,9 +109,7 @@
public boolean valueIsAcceptable(final Schema schema,
final ByteSequence value, final LocalizableMessageBuilder invalidReason)
{
- if (value.length() > 0
- || schema.getSchemaCompatOptions()
- .allowZeroLengthDirectoryStrings())
+ if (value.length() > 0 || schema.allowZeroLengthDirectoryStrings())
{
return true;
}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java
index 5059b69..e876bf6 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java
@@ -23,6 +23,7 @@
*
*
* Copyright 2009 Sun Microsystems, Inc.
+ * Portions copyright 2011 ForgeRock AS
*/
package org.forgerock.opendj.ldap.schema;
@@ -250,6 +251,55 @@
/**
+ * Indicates whether the provided attribute type is included in the optional
+ * attribute list for this name form.
+ *
+ * @param attributeType
+ * The attribute type for which to make the determination.
+ * @return <code>true</code> if the provided attribute type is optional for
+ * this name form, or <code>false</code> if not.
+ */
+ public boolean isOptional(final AttributeType attributeType)
+ {
+ return optionalAttributes.contains(attributeType);
+ }
+
+
+
+ /**
+ * Indicates whether the provided attribute type is included in the required
+ * attribute list for this name form.
+ *
+ * @param attributeType
+ * The attribute type for which to make the determination.
+ * @return <code>true</code> if the provided attribute type is required by
+ * this name form, or <code>false</code> if not.
+ */
+ public boolean isRequired(final AttributeType attributeType)
+ {
+ return requiredAttributes.contains(attributeType);
+ }
+
+
+
+ /**
+ * Indicates whether the provided attribute type is in the list of required or
+ * optional attributes for this name form.
+ *
+ * @param attributeType
+ * The attribute type for which to make the determination.
+ * @return <code>true</code> if the provided attribute type is required or
+ * allowed for this name form, or <code>false</code> if it is
+ * not.
+ */
+ public boolean isRequiredOrOptional(final AttributeType attributeType)
+ {
+ return isRequired(attributeType) || isOptional(attributeType);
+ }
+
+
+
+ /**
* Returns the string representation of this schema definition in the form
* specified in RFC 2252.
*
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
index f64b02e..8f7e96e 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
@@ -29,12 +29,10 @@
+import static org.forgerock.opendj.ldap.AttributeDescription.objectClass;
import static org.forgerock.opendj.ldap.CoreMessages.*;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.ldap.*;
@@ -63,17 +61,36 @@
{
private static final class EmptyImpl implements Impl
{
- private final SchemaCompatOptions options;
-
-
private EmptyImpl()
{
- this.options = SchemaCompatOptions.defaultOptions();
+ // Nothing to do.
}
+ public boolean allowMalformedNamesAndOptions()
+ {
+ return true;
+ }
+
+
+
+ public boolean allowNonStandardTelephoneNumbers()
+ {
+ return true;
+ }
+
+
+
+ public boolean allowZeroLengthDirectoryStrings()
+ {
+ return false;
+ }
+
+
+
+ @Override
public AttributeType getAttributeType(final String name)
{
// Construct an placeholder attribute type with the given name,
@@ -91,6 +108,7 @@
+ @Override
public Collection<AttributeType> getAttributeTypes()
{
return Collections.emptyList();
@@ -98,13 +116,23 @@
- public List<AttributeType> getAttributeTypesByName(final String name)
+ @Override
+ public List<AttributeType> getAttributeTypesWithName(final String name)
{
return Collections.emptyList();
}
+ @Override
+ public DITContentRule getDITContentRule(final ObjectClass structuralClass)
+ {
+ return null;
+ }
+
+
+
+ @Override
public DITContentRule getDITContentRule(final String name)
throws UnknownSchemaElementException
{
@@ -113,6 +141,7 @@
+ @Override
public Collection<DITContentRule> getDITContentRules()
{
return Collections.emptyList();
@@ -120,13 +149,16 @@
- public Collection<DITContentRule> getDITContentRulesByName(final String name)
+ @Override
+ public Collection<DITContentRule> getDITContentRulesWithName(
+ final String name)
{
return Collections.emptyList();
}
+ @Override
public DITStructureRule getDITStructureRule(final int ruleID)
throws UnknownSchemaElementException
{
@@ -136,15 +168,8 @@
- public Collection<DITStructureRule> getDITStructureRulesByName(
- final String name)
- {
- return Collections.emptyList();
- }
-
-
-
- public Collection<DITStructureRule> getDITStructureRulesByNameForm(
+ @Override
+ public Collection<DITStructureRule> getDITStructureRules(
final NameForm nameForm)
{
return Collections.emptyList();
@@ -152,6 +177,16 @@
+ @Override
+ public Collection<DITStructureRule> getDITStructureRulesWithName(
+ final String name)
+ {
+ return Collections.emptyList();
+ }
+
+
+
+ @Override
public Collection<DITStructureRule> getDITStuctureRules()
{
return Collections.emptyList();
@@ -159,6 +194,7 @@
+ @Override
public MatchingRule getMatchingRule(final String name)
throws UnknownSchemaElementException
{
@@ -167,6 +203,7 @@
+ @Override
public Collection<MatchingRule> getMatchingRules()
{
return Collections.emptyList();
@@ -174,21 +211,23 @@
- public Collection<MatchingRule> getMatchingRulesByName(final String name)
+ @Override
+ public Collection<MatchingRule> getMatchingRulesWithName(final String name)
{
return Collections.emptyList();
}
+ @Override
public MatchingRuleUse getMatchingRuleUse(final MatchingRule matchingRule)
- throws UnknownSchemaElementException
{
- return getMatchingRuleUse(matchingRule.getOID());
+ return null;
}
+ @Override
public MatchingRuleUse getMatchingRuleUse(final String name)
throws UnknownSchemaElementException
{
@@ -197,6 +236,7 @@
+ @Override
public Collection<MatchingRuleUse> getMatchingRuleUses()
{
return Collections.emptyList();
@@ -204,7 +244,8 @@
- public Collection<MatchingRuleUse> getMatchingRuleUsesByName(
+ @Override
+ public Collection<MatchingRuleUse> getMatchingRuleUsesWithName(
final String name)
{
return Collections.emptyList();
@@ -212,6 +253,7 @@
+ @Override
public NameForm getNameForm(final String name)
throws UnknownSchemaElementException
{
@@ -220,14 +262,7 @@
- public Collection<NameForm> getNameFormByObjectClass(
- final ObjectClass structuralClass)
- {
- return Collections.emptyList();
- }
-
-
-
+ @Override
public Collection<NameForm> getNameForms()
{
return Collections.emptyList();
@@ -235,22 +270,33 @@
- public Collection<NameForm> getNameFormsByName(final String name)
+ @Override
+ public Collection<NameForm> getNameForms(final ObjectClass structuralClass)
{
return Collections.emptyList();
}
- public ObjectClass getObjectClass(final String name)
- throws UnknownSchemaElementException
+ @Override
+ public Collection<NameForm> getNameFormsWithName(final String name)
{
- throw new UnknownSchemaElementException(WARN_OBJECTCLASS_UNKNOWN
- .get(name));
+ return Collections.emptyList();
}
+ @Override
+ public ObjectClass getObjectClass(final String name)
+ throws UnknownSchemaElementException
+ {
+ throw new UnknownSchemaElementException(
+ WARN_OBJECTCLASS_UNKNOWN.get(name));
+ }
+
+
+
+ @Override
public Collection<ObjectClass> getObjectClasses()
{
return Collections.emptyList();
@@ -258,23 +304,18 @@
- public Collection<ObjectClass> getObjectClassesByName(final String name)
+ @Override
+ public Collection<ObjectClass> getObjectClassesWithName(final String name)
{
return Collections.emptyList();
}
- public SchemaCompatOptions getSchemaCompatOptions()
- {
- return options;
- }
-
-
-
/**
* {@inheritDoc}
*/
+ @Override
public String getSchemaName()
{
return "Empty Schema";
@@ -282,6 +323,7 @@
+ @Override
public Syntax getSyntax(final String numericOID)
{
// Fake up a syntax substituted by the default syntax.
@@ -290,6 +332,7 @@
+ @Override
public Collection<Syntax> getSyntaxes()
{
return Collections.emptyList();
@@ -297,6 +340,7 @@
+ @Override
public Collection<LocalizableMessage> getWarnings()
{
return Collections.emptyList();
@@ -304,6 +348,7 @@
+ @Override
public boolean hasAttributeType(final String name)
{
// In theory a non-strict schema always contains the requested
@@ -315,6 +360,7 @@
+ @Override
public boolean hasDITContentRule(final String name)
{
return false;
@@ -322,6 +368,7 @@
+ @Override
public boolean hasDITStructureRule(final int ruleID)
{
return false;
@@ -329,6 +376,7 @@
+ @Override
public boolean hasMatchingRule(final String name)
{
return false;
@@ -336,6 +384,7 @@
+ @Override
public boolean hasMatchingRuleUse(final String name)
{
return false;
@@ -343,6 +392,7 @@
+ @Override
public boolean hasNameForm(final String name)
{
return false;
@@ -350,6 +400,7 @@
+ @Override
public boolean hasObjectClass(final String name)
{
return false;
@@ -357,6 +408,7 @@
+ @Override
public boolean hasSyntax(final String numericOID)
{
return false;
@@ -364,6 +416,7 @@
+ @Override
public boolean isStrict()
{
return false;
@@ -383,7 +436,11 @@
- List<AttributeType> getAttributeTypesByName(String name);
+ List<AttributeType> getAttributeTypesWithName(String name);
+
+
+
+ DITContentRule getDITContentRule(ObjectClass structuralClass);
@@ -396,7 +453,7 @@
- Collection<DITContentRule> getDITContentRulesByName(String name);
+ Collection<DITContentRule> getDITContentRulesWithName(String name);
@@ -405,12 +462,11 @@
- Collection<DITStructureRule> getDITStructureRulesByName(String name);
+ Collection<DITStructureRule> getDITStructureRules(NameForm nameForm);
- Collection<DITStructureRule> getDITStructureRulesByNameForm(
- NameForm nameForm);
+ Collection<DITStructureRule> getDITStructureRulesWithName(String name);
@@ -427,12 +483,11 @@
- Collection<MatchingRule> getMatchingRulesByName(String name);
+ Collection<MatchingRule> getMatchingRulesWithName(String name);
- MatchingRuleUse getMatchingRuleUse(MatchingRule matchingRule)
- throws UnknownSchemaElementException;
+ MatchingRuleUse getMatchingRuleUse(MatchingRule matchingRule);
@@ -445,7 +500,7 @@
- Collection<MatchingRuleUse> getMatchingRuleUsesByName(String name);
+ Collection<MatchingRuleUse> getMatchingRuleUsesWithName(String name);
@@ -453,15 +508,15 @@
- Collection<NameForm> getNameFormByObjectClass(ObjectClass structuralClass);
-
-
-
Collection<NameForm> getNameForms();
- Collection<NameForm> getNameFormsByName(String name);
+ Collection<NameForm> getNameForms(ObjectClass structuralClass);
+
+
+
+ Collection<NameForm> getNameFormsWithName(String name);
@@ -474,11 +529,7 @@
- Collection<ObjectClass> getObjectClassesByName(String name);
-
-
-
- SchemaCompatOptions getSchemaCompatOptions();
+ Collection<ObjectClass> getObjectClassesWithName(String name);
@@ -531,6 +582,18 @@
boolean isStrict();
+
+
+
+ boolean allowMalformedNamesAndOptions();
+
+
+
+ boolean allowNonStandardTelephoneNumbers();
+
+
+
+ boolean allowZeroLengthDirectoryStrings();
}
@@ -548,6 +611,28 @@
+ public boolean allowMalformedNamesAndOptions()
+ {
+ return strictImpl.allowMalformedNamesAndOptions();
+ }
+
+
+
+ public boolean allowNonStandardTelephoneNumbers()
+ {
+ return strictImpl.allowNonStandardTelephoneNumbers();
+ }
+
+
+
+ public boolean allowZeroLengthDirectoryStrings()
+ {
+ return strictImpl.allowZeroLengthDirectoryStrings();
+ }
+
+
+
+ @Override
public AttributeType getAttributeType(final String name)
throws UnknownSchemaElementException
{
@@ -570,6 +655,7 @@
+ @Override
public Collection<AttributeType> getAttributeTypes()
{
return strictImpl.getAttributeTypes();
@@ -577,13 +663,23 @@
- public List<AttributeType> getAttributeTypesByName(final String name)
+ @Override
+ public List<AttributeType> getAttributeTypesWithName(final String name)
{
- return strictImpl.getAttributeTypesByName(name);
+ return strictImpl.getAttributeTypesWithName(name);
}
+ @Override
+ public DITContentRule getDITContentRule(final ObjectClass structuralClass)
+ {
+ return strictImpl.getDITContentRule(structuralClass);
+ }
+
+
+
+ @Override
public DITContentRule getDITContentRule(final String name)
throws UnknownSchemaElementException
{
@@ -592,6 +688,7 @@
+ @Override
public Collection<DITContentRule> getDITContentRules()
{
return strictImpl.getDITContentRules();
@@ -599,13 +696,16 @@
- public Collection<DITContentRule> getDITContentRulesByName(final String name)
+ @Override
+ public Collection<DITContentRule> getDITContentRulesWithName(
+ final String name)
{
- return strictImpl.getDITContentRulesByName(name);
+ return strictImpl.getDITContentRulesWithName(name);
}
+ @Override
public DITStructureRule getDITStructureRule(final int ruleID)
throws UnknownSchemaElementException
{
@@ -614,22 +714,25 @@
- public Collection<DITStructureRule> getDITStructureRulesByName(
- final String name)
- {
- return strictImpl.getDITStructureRulesByName(name);
- }
-
-
-
- public Collection<DITStructureRule> getDITStructureRulesByNameForm(
+ @Override
+ public Collection<DITStructureRule> getDITStructureRules(
final NameForm nameForm)
{
- return strictImpl.getDITStructureRulesByNameForm(nameForm);
+ return strictImpl.getDITStructureRules(nameForm);
}
+ @Override
+ public Collection<DITStructureRule> getDITStructureRulesWithName(
+ final String name)
+ {
+ return strictImpl.getDITStructureRulesWithName(name);
+ }
+
+
+
+ @Override
public Collection<DITStructureRule> getDITStuctureRules()
{
return strictImpl.getDITStuctureRules();
@@ -637,6 +740,7 @@
+ @Override
public MatchingRule getMatchingRule(final String name)
throws UnknownSchemaElementException
{
@@ -645,6 +749,7 @@
+ @Override
public Collection<MatchingRule> getMatchingRules()
{
return strictImpl.getMatchingRules();
@@ -652,21 +757,23 @@
- public Collection<MatchingRule> getMatchingRulesByName(final String name)
+ @Override
+ public Collection<MatchingRule> getMatchingRulesWithName(final String name)
{
- return strictImpl.getMatchingRulesByName(name);
+ return strictImpl.getMatchingRulesWithName(name);
}
+ @Override
public MatchingRuleUse getMatchingRuleUse(final MatchingRule matchingRule)
- throws UnknownSchemaElementException
{
return strictImpl.getMatchingRuleUse(matchingRule);
}
+ @Override
public MatchingRuleUse getMatchingRuleUse(final String name)
throws UnknownSchemaElementException
{
@@ -675,6 +782,7 @@
+ @Override
public Collection<MatchingRuleUse> getMatchingRuleUses()
{
return strictImpl.getMatchingRuleUses();
@@ -682,14 +790,16 @@
- public Collection<MatchingRuleUse> getMatchingRuleUsesByName(
+ @Override
+ public Collection<MatchingRuleUse> getMatchingRuleUsesWithName(
final String name)
{
- return strictImpl.getMatchingRuleUsesByName(name);
+ return strictImpl.getMatchingRuleUsesWithName(name);
}
+ @Override
public NameForm getNameForm(final String name)
throws UnknownSchemaElementException
{
@@ -698,14 +808,7 @@
- public Collection<NameForm> getNameFormByObjectClass(
- final ObjectClass structuralClass)
- {
- return strictImpl.getNameFormByObjectClass(structuralClass);
- }
-
-
-
+ @Override
public Collection<NameForm> getNameForms()
{
return strictImpl.getNameForms();
@@ -713,13 +816,23 @@
- public Collection<NameForm> getNameFormsByName(final String name)
+ @Override
+ public Collection<NameForm> getNameForms(final ObjectClass structuralClass)
{
- return strictImpl.getNameFormsByName(name);
+ return strictImpl.getNameForms(structuralClass);
}
+ @Override
+ public Collection<NameForm> getNameFormsWithName(final String name)
+ {
+ return strictImpl.getNameFormsWithName(name);
+ }
+
+
+
+ @Override
public ObjectClass getObjectClass(final String name)
throws UnknownSchemaElementException
{
@@ -728,6 +841,7 @@
+ @Override
public Collection<ObjectClass> getObjectClasses()
{
return strictImpl.getObjectClasses();
@@ -735,20 +849,15 @@
- public Collection<ObjectClass> getObjectClassesByName(final String name)
+ @Override
+ public Collection<ObjectClass> getObjectClassesWithName(final String name)
{
- return strictImpl.getObjectClassesByName(name);
+ return strictImpl.getObjectClassesWithName(name);
}
- public SchemaCompatOptions getSchemaCompatOptions()
- {
- return strictImpl.getSchemaCompatOptions();
- }
-
-
-
+ @Override
public String getSchemaName()
{
return strictImpl.getSchemaName();
@@ -756,6 +865,7 @@
+ @Override
public Syntax getSyntax(final String numericOID)
{
if (!strictImpl.hasSyntax(numericOID))
@@ -767,6 +877,7 @@
+ @Override
public Collection<Syntax> getSyntaxes()
{
return strictImpl.getSyntaxes();
@@ -774,6 +885,7 @@
+ @Override
public Collection<LocalizableMessage> getWarnings()
{
return strictImpl.getWarnings();
@@ -781,6 +893,7 @@
+ @Override
public boolean hasAttributeType(final String name)
{
// In theory a non-strict schema always contains the requested
@@ -792,6 +905,7 @@
+ @Override
public boolean hasDITContentRule(final String name)
{
return strictImpl.hasDITContentRule(name);
@@ -799,6 +913,7 @@
+ @Override
public boolean hasDITStructureRule(final int ruleID)
{
return strictImpl.hasDITStructureRule(ruleID);
@@ -806,6 +921,7 @@
+ @Override
public boolean hasMatchingRule(final String name)
{
return strictImpl.hasMatchingRule(name);
@@ -813,6 +929,7 @@
+ @Override
public boolean hasMatchingRuleUse(final String name)
{
return strictImpl.hasMatchingRuleUse(name);
@@ -820,6 +937,7 @@
+ @Override
public boolean hasNameForm(final String name)
{
return strictImpl.hasNameForm(name);
@@ -827,6 +945,7 @@
+ @Override
public boolean hasObjectClass(final String name)
{
return strictImpl.hasObjectClass(name);
@@ -834,6 +953,7 @@
+ @Override
public boolean hasSyntax(final String numericOID)
{
return strictImpl.hasSyntax(numericOID);
@@ -841,6 +961,7 @@
+ @Override
public boolean isStrict()
{
return false;
@@ -885,15 +1006,22 @@
private final Map<String, List<NameForm>> objectClass2NameForms;
- private final SchemaCompatOptions options;
-
private final List<LocalizableMessage> warnings;
private final String schemaName;
+ private final boolean allowNonStandardTelephoneNumbers;
+
+ private final boolean allowZeroLengthDirectoryStrings;
+
+ private final boolean allowMalformedNamesAndOptions;
- private StrictImpl(final String schemaName,
+
+ StrictImpl(final String schemaName,
+ final boolean allowMalformedNamesAndOptions,
+ final boolean allowNonStandardTelephoneNumbers,
+ final boolean allowZeroLengthDirectoryStrings,
final Map<String, Syntax> numericOID2Syntaxes,
final Map<String, MatchingRule> numericOID2MatchingRules,
final Map<String, MatchingRuleUse> numericOID2MatchingRuleUses,
@@ -911,10 +1039,12 @@
final Map<String, List<DITStructureRule>> name2StructureRules,
final Map<String, List<NameForm>> objectClass2NameForms,
final Map<String, List<DITStructureRule>> nameForm2StructureRules,
- final SchemaCompatOptions options,
final List<LocalizableMessage> warnings)
{
this.schemaName = schemaName;
+ this.allowMalformedNamesAndOptions = allowMalformedNamesAndOptions;
+ this.allowNonStandardTelephoneNumbers = allowNonStandardTelephoneNumbers;
+ this.allowZeroLengthDirectoryStrings = allowZeroLengthDirectoryStrings;
this.numericOID2Syntaxes = Collections
.unmodifiableMap(numericOID2Syntaxes);
this.numericOID2MatchingRules = Collections
@@ -944,12 +1074,33 @@
.unmodifiableMap(objectClass2NameForms);
this.nameForm2StructureRules = Collections
.unmodifiableMap(nameForm2StructureRules);
- this.options = options;
this.warnings = Collections.unmodifiableList(warnings);
}
+ public boolean allowMalformedNamesAndOptions()
+ {
+ return allowMalformedNamesAndOptions;
+ }
+
+
+
+ public boolean allowNonStandardTelephoneNumbers()
+ {
+ return allowNonStandardTelephoneNumbers;
+ }
+
+
+
+ public boolean allowZeroLengthDirectoryStrings()
+ {
+ return allowZeroLengthDirectoryStrings;
+ }
+
+
+
+ @Override
public AttributeType getAttributeType(final String name)
throws UnknownSchemaElementException
{
@@ -966,14 +1117,15 @@
{
return attributes.get(0);
}
- throw new UnknownSchemaElementException(WARN_ATTR_TYPE_AMBIGIOUS
- .get(name));
+ throw new UnknownSchemaElementException(
+ WARN_ATTR_TYPE_AMBIGIOUS.get(name));
}
throw new UnknownSchemaElementException(WARN_ATTR_TYPE_UNKNOWN.get(name));
}
+ @Override
public Collection<AttributeType> getAttributeTypes()
{
return numericOID2AttributeTypes.values();
@@ -981,7 +1133,8 @@
- public List<AttributeType> getAttributeTypesByName(final String name)
+ @Override
+ public List<AttributeType> getAttributeTypesWithName(final String name)
{
final List<AttributeType> attributes = name2AttributeTypes
.get(StaticUtils.toLowerCase(name));
@@ -997,6 +1150,15 @@
+ @Override
+ public DITContentRule getDITContentRule(final ObjectClass structuralClass)
+ {
+ return numericOID2ContentRules.get(structuralClass.getOID());
+ }
+
+
+
+ @Override
public DITContentRule getDITContentRule(final String name)
throws UnknownSchemaElementException
{
@@ -1020,6 +1182,7 @@
+ @Override
public Collection<DITContentRule> getDITContentRules()
{
return numericOID2ContentRules.values();
@@ -1027,7 +1190,9 @@
- public Collection<DITContentRule> getDITContentRulesByName(final String name)
+ @Override
+ public Collection<DITContentRule> getDITContentRulesWithName(
+ final String name)
{
final List<DITContentRule> rules = name2ContentRules.get(StaticUtils
.toLowerCase(name));
@@ -1043,6 +1208,7 @@
+ @Override
public DITStructureRule getDITStructureRule(final int ruleID)
throws UnknownSchemaElementException
{
@@ -1057,24 +1223,8 @@
- public Collection<DITStructureRule> getDITStructureRulesByName(
- final String name)
- {
- final List<DITStructureRule> rules = name2StructureRules.get(StaticUtils
- .toLowerCase(name));
- if (rules == null)
- {
- return Collections.emptyList();
- }
- else
- {
- return rules;
- }
- }
-
-
-
- public Collection<DITStructureRule> getDITStructureRulesByNameForm(
+ @Override
+ public Collection<DITStructureRule> getDITStructureRules(
final NameForm nameForm)
{
final List<DITStructureRule> rules = nameForm2StructureRules.get(nameForm
@@ -1091,6 +1241,25 @@
+ @Override
+ public Collection<DITStructureRule> getDITStructureRulesWithName(
+ final String name)
+ {
+ final List<DITStructureRule> rules = name2StructureRules.get(StaticUtils
+ .toLowerCase(name));
+ if (rules == null)
+ {
+ return Collections.emptyList();
+ }
+ else
+ {
+ return rules;
+ }
+ }
+
+
+
+ @Override
public Collection<DITStructureRule> getDITStuctureRules()
{
return id2StructureRules.values();
@@ -1098,6 +1267,7 @@
+ @Override
public MatchingRule getMatchingRule(final String name)
throws UnknownSchemaElementException
{
@@ -1121,6 +1291,7 @@
+ @Override
public Collection<MatchingRule> getMatchingRules()
{
return numericOID2MatchingRules.values();
@@ -1128,7 +1299,8 @@
- public Collection<MatchingRule> getMatchingRulesByName(final String name)
+ @Override
+ public Collection<MatchingRule> getMatchingRulesWithName(final String name)
{
final List<MatchingRule> rules = name2MatchingRules.get(StaticUtils
.toLowerCase(name));
@@ -1144,14 +1316,15 @@
+ @Override
public MatchingRuleUse getMatchingRuleUse(final MatchingRule matchingRule)
- throws UnknownSchemaElementException
{
- return getMatchingRuleUse(matchingRule.getOID());
+ return numericOID2MatchingRuleUses.get(matchingRule.getOID());
}
+ @Override
public MatchingRuleUse getMatchingRuleUse(final String name)
throws UnknownSchemaElementException
{
@@ -1175,6 +1348,7 @@
+ @Override
public Collection<MatchingRuleUse> getMatchingRuleUses()
{
return numericOID2MatchingRuleUses.values();
@@ -1182,7 +1356,8 @@
- public Collection<MatchingRuleUse> getMatchingRuleUsesByName(
+ @Override
+ public Collection<MatchingRuleUse> getMatchingRuleUsesWithName(
final String name)
{
final List<MatchingRuleUse> rules = name2MatchingRuleUses.get(StaticUtils
@@ -1199,6 +1374,7 @@
+ @Override
public NameForm getNameForm(final String name)
throws UnknownSchemaElementException
{
@@ -1215,16 +1391,24 @@
{
return forms.get(0);
}
- throw new UnknownSchemaElementException(WARN_NAMEFORM_AMBIGIOUS
- .get(name));
+ throw new UnknownSchemaElementException(
+ WARN_NAMEFORM_AMBIGIOUS.get(name));
}
throw new UnknownSchemaElementException(WARN_NAMEFORM_UNKNOWN.get(name));
}
- public Collection<NameForm> getNameFormByObjectClass(
- final ObjectClass structuralClass)
+ @Override
+ public Collection<NameForm> getNameForms()
+ {
+ return numericOID2NameForms.values();
+ }
+
+
+
+ @Override
+ public Collection<NameForm> getNameForms(final ObjectClass structuralClass)
{
final List<NameForm> forms = objectClass2NameForms.get(structuralClass
.getOID());
@@ -1240,14 +1424,8 @@
- public Collection<NameForm> getNameForms()
- {
- return numericOID2NameForms.values();
- }
-
-
-
- public Collection<NameForm> getNameFormsByName(final String name)
+ @Override
+ public Collection<NameForm> getNameFormsWithName(final String name)
{
final List<NameForm> forms = name2NameForms.get(StaticUtils
.toLowerCase(name));
@@ -1263,6 +1441,7 @@
+ @Override
public ObjectClass getObjectClass(final String name)
throws UnknownSchemaElementException
{
@@ -1279,15 +1458,16 @@
{
return classes.get(0);
}
- throw new UnknownSchemaElementException(WARN_OBJECTCLASS_AMBIGIOUS
- .get(name));
+ throw new UnknownSchemaElementException(
+ WARN_OBJECTCLASS_AMBIGIOUS.get(name));
}
- throw new UnknownSchemaElementException(WARN_OBJECTCLASS_UNKNOWN
- .get(name));
+ throw new UnknownSchemaElementException(
+ WARN_OBJECTCLASS_UNKNOWN.get(name));
}
+ @Override
public Collection<ObjectClass> getObjectClasses()
{
return numericOID2ObjectClasses.values();
@@ -1295,7 +1475,8 @@
- public Collection<ObjectClass> getObjectClassesByName(final String name)
+ @Override
+ public Collection<ObjectClass> getObjectClassesWithName(final String name)
{
final List<ObjectClass> classes = name2ObjectClasses.get(StaticUtils
.toLowerCase(name));
@@ -1311,13 +1492,7 @@
- public SchemaCompatOptions getSchemaCompatOptions()
- {
- return options;
- }
-
-
-
+ @Override
public String getSchemaName()
{
return schemaName;
@@ -1325,20 +1500,22 @@
+ @Override
public Syntax getSyntax(final String numericOID)
throws UnknownSchemaElementException
{
final Syntax syntax = numericOID2Syntaxes.get(numericOID);
if (syntax == null)
{
- throw new UnknownSchemaElementException(WARN_SYNTAX_UNKNOWN
- .get(numericOID));
+ throw new UnknownSchemaElementException(
+ WARN_SYNTAX_UNKNOWN.get(numericOID));
}
return syntax;
}
+ @Override
public Collection<Syntax> getSyntaxes()
{
return numericOID2Syntaxes.values();
@@ -1346,6 +1523,7 @@
+ @Override
public Collection<LocalizableMessage> getWarnings()
{
return warnings;
@@ -1353,6 +1531,7 @@
+ @Override
public boolean hasAttributeType(final String name)
{
if (numericOID2AttributeTypes.containsKey(name))
@@ -1366,6 +1545,7 @@
+ @Override
public boolean hasDITContentRule(final String name)
{
if (numericOID2ContentRules.containsKey(name))
@@ -1379,6 +1559,7 @@
+ @Override
public boolean hasDITStructureRule(final int ruleID)
{
return id2StructureRules.containsKey(ruleID);
@@ -1386,6 +1567,7 @@
+ @Override
public boolean hasMatchingRule(final String name)
{
if (numericOID2MatchingRules.containsKey(name))
@@ -1399,6 +1581,7 @@
+ @Override
public boolean hasMatchingRuleUse(final String name)
{
if (numericOID2MatchingRuleUses.containsKey(name))
@@ -1412,6 +1595,7 @@
+ @Override
public boolean hasNameForm(final String name)
{
if (numericOID2NameForms.containsKey(name))
@@ -1425,6 +1609,7 @@
+ @Override
public boolean hasObjectClass(final String name)
{
if (numericOID2ObjectClasses.containsKey(name))
@@ -1438,6 +1623,7 @@
+ @Override
public boolean hasSyntax(final String numericOID)
{
return numericOID2Syntaxes.containsKey(numericOID);
@@ -1445,6 +1631,7 @@
+ @Override
public boolean isStrict()
{
return true;
@@ -1452,6 +1639,7 @@
}
+
/*
* WARNING: do not reference the core schema in the following declarations.
*/
@@ -1600,8 +1788,8 @@
* @throws UnsupportedOperationException
* If the connection does not support search operations.
* @throws IllegalStateException
- * If the connection has already been closed, i.e. if {@code
- * connection.isClosed() == true}.
+ * If the connection has already been closed, i.e. if
+ * {@code connection.isClosed() == true}.
* @throws NullPointerException
* If the {@code connection} or {@code name} was {@code null}.
*/
@@ -1701,8 +1889,8 @@
* @throws UnsupportedOperationException
* If the connection does not support search operations.
* @throws IllegalStateException
- * If the connection has already been closed, i.e. if {@code
- * connection.isClosed() == true}.
+ * If the connection has already been closed, i.e. if
+ * {@code connection.isClosed() == true}.
* @throws NullPointerException
* If the {@code connection} or {@code name} was {@code null}.
*/
@@ -1767,6 +1955,9 @@
Schema(final String schemaName,
+ final boolean allowMalformedNamesAndOptions,
+ final boolean allowNonStandardTelephoneNumbers,
+ final boolean allowZeroLengthDirectoryStrings,
final Map<String, Syntax> numericOID2Syntaxes,
final Map<String, MatchingRule> numericOID2MatchingRules,
final Map<String, MatchingRuleUse> numericOID2MatchingRuleUses,
@@ -1784,16 +1975,17 @@
final Map<String, List<DITStructureRule>> name2StructureRules,
final Map<String, List<NameForm>> objectClass2NameForms,
final Map<String, List<DITStructureRule>> nameForm2StructureRules,
- final SchemaCompatOptions options, final List<LocalizableMessage> warnings)
+ final List<LocalizableMessage> warnings)
{
- impl = new StrictImpl(schemaName, numericOID2Syntaxes,
- numericOID2MatchingRules, numericOID2MatchingRuleUses,
- numericOID2AttributeTypes, numericOID2ObjectClasses,
- numericOID2NameForms, numericOID2ContentRules, id2StructureRules,
- name2MatchingRules, name2MatchingRuleUses, name2AttributeTypes,
- name2ObjectClasses, name2NameForms, name2ContentRules,
- name2StructureRules, objectClass2NameForms, nameForm2StructureRules,
- options, warnings);
+ impl = new StrictImpl(schemaName, allowMalformedNamesAndOptions,
+ allowNonStandardTelephoneNumbers, allowZeroLengthDirectoryStrings,
+ numericOID2Syntaxes, numericOID2MatchingRules,
+ numericOID2MatchingRuleUses, numericOID2AttributeTypes,
+ numericOID2ObjectClasses, numericOID2NameForms,
+ numericOID2ContentRules, id2StructureRules, name2MatchingRules,
+ name2MatchingRuleUses, name2AttributeTypes, name2ObjectClasses,
+ name2NameForms, name2ContentRules, name2StructureRules,
+ objectClass2NameForms, nameForm2StructureRules, warnings);
}
@@ -1806,8 +1998,8 @@
/**
- * Returns {@code true} if this schema allows certain illegal characters
- * in OIDs and attribute options. When this compatibility option is set to
+ * Returns {@code true} if this schema allows certain illegal characters in
+ * OIDs and attribute options. When this compatibility option is set to
* {@code true} the following illegal characters will be permitted in addition
* to those permitted in section 1.4 of RFC 4512:
*
@@ -1819,14 +2011,14 @@
* By default this compatibility option is set to {@code true} because these
* characters are often used for naming purposes (such as collation rules).
*
- * @return {@code true} if this schema allows certain illegal characters
- * in OIDs and attribute options.
+ * @return {@code true} if this schema allows certain illegal characters in
+ * OIDs and attribute options.
* @see <a href="http://tools.ietf.org/html/rfc4512">RFC 4512 - Lightweight
* Directory Access Protocol (LDAP): Directory Information Models </a>
*/
public boolean allowMalformedNamesAndOptions()
{
- return impl.getSchemaCompatOptions().allowMalformedNamesAndOptions();
+ return impl.allowMalformedNamesAndOptions();
}
@@ -1844,8 +2036,7 @@
*/
public boolean allowNonStandardTelephoneNumbers()
{
- return impl.getSchemaCompatOptions()
- .allowNonStandardTelephoneNumbers();
+ return impl.allowNonStandardTelephoneNumbers();
}
@@ -1864,8 +2055,51 @@
*/
public boolean allowZeroLengthDirectoryStrings()
{
- return impl.getSchemaCompatOptions()
- .allowZeroLengthDirectoryStrings();
+ return impl.allowZeroLengthDirectoryStrings();
+ }
+
+
+
+ /**
+ * 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 asNonStrictSchema()
+ {
+ if (impl.isStrict())
+ {
+ return new Schema(new NonStrictImpl(impl));
+ }
+ else
+ {
+ return this;
+ }
+ }
+
+
+
+ /**
+ * 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);
+ }
}
@@ -1911,9 +2145,25 @@
* @return An unmodifiable collection containing all of the attribute types
* having the specified name or numeric OID.
*/
- public List<AttributeType> getAttributeTypesByName(final String name)
+ public List<AttributeType> getAttributeTypesWithName(final String name)
{
- return impl.getAttributeTypesByName(name);
+ return impl.getAttributeTypesWithName(name);
+ }
+
+
+
+ /**
+ * Returns the DIT content rule associated with the provided structural object
+ * class, or {@code null} if no rule is defined.
+ *
+ * @param structuralClass
+ * The structural object class .
+ * @return The DIT content rule associated with the provided structural object
+ * class, or {@code null} if no rule is defined.
+ */
+ public DITContentRule getDITContentRule(final ObjectClass structuralClass)
+ {
+ return impl.getDITContentRule(structuralClass);
}
@@ -1959,9 +2209,9 @@
* @return An unmodifiable collection containing all of the DIT content rules
* having the specified name or numeric OID.
*/
- public Collection<DITContentRule> getDITContentRulesByName(final String name)
+ public Collection<DITContentRule> getDITContentRulesWithName(final String name)
{
- return impl.getDITContentRulesByName(name);
+ return impl.getDITContentRulesWithName(name);
}
@@ -1986,6 +2236,23 @@
/**
* Returns an unmodifiable collection containing all of the DIT structure
+ * rules associated with the provided name form.
+ *
+ * @param nameForm
+ * The name form.
+ * @return An unmodifiable collection containing all of the DIT structure
+ * rules associated with the provided name form.
+ */
+ public Collection<DITStructureRule> getDITStructureRules(
+ final NameForm nameForm)
+ {
+ return impl.getDITStructureRules(nameForm);
+ }
+
+
+
+ /**
+ * Returns an unmodifiable collection containing all of the DIT structure
* rules having the specified name or numeric OID.
*
* @param name
@@ -1993,25 +2260,10 @@
* @return An unmodifiable collection containing all of the DIT structure
* rules having the specified name or numeric OID.
*/
- public Collection<DITStructureRule> getDITStructureRulesByName(
+ public Collection<DITStructureRule> getDITStructureRulesWithName(
final String name)
{
- return impl.getDITStructureRulesByName(name);
- }
-
-
-
- /**
- * Retrieves the DIT structure rules for the provided name form.
- *
- * @param nameForm
- * The name form.
- * @return The requested DIT structure rules.
- */
- public Collection<DITStructureRule> getDITStructureRulesByNameForm(
- final NameForm nameForm)
- {
- return impl.getDITStructureRulesByNameForm(nameForm);
+ return impl.getDITStructureRulesWithName(name);
}
@@ -2071,25 +2323,23 @@
* @return An unmodifiable collection containing all of the matching rules
* having the specified name or numeric OID.
*/
- public Collection<MatchingRule> getMatchingRulesByName(final String name)
+ public Collection<MatchingRule> getMatchingRulesWithName(final String name)
{
- return impl.getMatchingRulesByName(name);
+ return impl.getMatchingRulesWithName(name);
}
/**
- * Returns the matching rule use associated with the provided matching rule.
+ * Returns the matching rule use associated with the provided matching rule,
+ * or {@code null} if no use is defined.
*
* @param matchingRule
* The matching rule whose matching rule use is to be retrieved.
- * @return The requested matching rule use.
- * @throws UnknownSchemaElementException
- * If this is a strict schema and the requested matching rule use
- * was not found or if the provided name is ambiguous.
+ * @return The matching rule use associated with the provided matching rule,
+ * or {@code null} if no use is defined.
*/
public MatchingRuleUse getMatchingRuleUse(final MatchingRule matchingRule)
- throws UnknownSchemaElementException
{
return getMatchingRuleUse(matchingRule.getOID());
}
@@ -2137,9 +2387,10 @@
* @return An unmodifiable collection containing all of the matching rule uses
* having the specified name or numeric OID.
*/
- public Collection<MatchingRuleUse> getMatchingRuleUsesByName(final String name)
+ public Collection<MatchingRuleUse> getMatchingRuleUsesWithName(
+ final String name)
{
- return impl.getMatchingRuleUsesByName(name);
+ return impl.getMatchingRuleUsesWithName(name);
}
@@ -2163,21 +2414,6 @@
/**
- * Retrieves the name forms for the specified structural objectclass.
- *
- * @param structuralClass
- * The structural objectclass for the name form to retrieve.
- * @return The requested name forms
- */
- public Collection<NameForm> getNameFormByObjectClass(
- final ObjectClass structuralClass)
- {
- return impl.getNameFormByObjectClass(structuralClass);
- }
-
-
-
- /**
* Returns an unmodifiable collection containing all of the name forms
* contained in this schema.
*
@@ -2192,6 +2428,22 @@
/**
+ * Returns an unmodifiable collection containing all of the name forms
+ * associated with the provided structural object class.
+ *
+ * @param structuralClass
+ * The structural object class whose name forms are to be retrieved.
+ * @return An unmodifiable collection containing all of the name forms
+ * associated with the provided structural object class.
+ */
+ public Collection<NameForm> getNameForms(final ObjectClass structuralClass)
+ {
+ return impl.getNameForms(structuralClass);
+ }
+
+
+
+ /**
* Returns an unmodifiable collection containing all of the name forms having
* the specified name or numeric OID.
*
@@ -2200,9 +2452,9 @@
* @return An unmodifiable collection containing all of the name forms having
* the specified name or numeric OID.
*/
- public Collection<NameForm> getNameFormsByName(final String name)
+ public Collection<NameForm> getNameFormsWithName(final String name)
{
- return impl.getNameFormsByName(name);
+ return impl.getNameFormsWithName(name);
}
@@ -2248,9 +2500,9 @@
* @return An unmodifiable collection containing all of the object classes
* having the specified name or numeric OID.
*/
- public Collection<ObjectClass> getObjectClassesByName(final String name)
+ public Collection<ObjectClass> getObjectClassesWithName(final String name)
{
- return impl.getObjectClassesByName(name);
+ return impl.getObjectClassesWithName(name);
}
@@ -2467,50 +2719,6 @@
/**
- * 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 asNonStrictSchema()
- {
- if (impl.isStrict())
- {
- return new Schema(new NonStrictImpl(impl));
- }
- else
- {
- return this;
- }
- }
-
-
-
- /**
- * 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.
@@ -2522,10 +2730,10 @@
* @throws NullPointerException
* If {@code entry} was {@code null}.
*/
- public Entry toEntry(Entry entry) throws NullPointerException
+ public Entry toEntry(final Entry entry) throws NullPointerException
{
Attribute attr = new LinkedAttribute(Schema.ATTR_LDAP_SYNTAXES);
- for (Syntax syntax : getSyntaxes())
+ for (final Syntax syntax : getSyntaxes())
{
attr.add(syntax.toString());
}
@@ -2535,7 +2743,7 @@
}
attr = new LinkedAttribute(Schema.ATTR_ATTRIBUTE_TYPES);
- for (AttributeType attributeType : getAttributeTypes())
+ for (final AttributeType attributeType : getAttributeTypes())
{
attr.add(attributeType.toString());
}
@@ -2545,7 +2753,7 @@
}
attr = new LinkedAttribute(Schema.ATTR_OBJECT_CLASSES);
- for (ObjectClass objectClass : getObjectClasses())
+ for (final ObjectClass objectClass : getObjectClasses())
{
attr.add(objectClass.toString());
}
@@ -2555,7 +2763,7 @@
}
attr = new LinkedAttribute(Schema.ATTR_MATCHING_RULE_USE);
- for (MatchingRuleUse matchingRuleUse : getMatchingRuleUses())
+ for (final MatchingRuleUse matchingRuleUse : getMatchingRuleUses())
{
attr.add(matchingRuleUse.toString());
}
@@ -2565,7 +2773,7 @@
}
attr = new LinkedAttribute(Schema.ATTR_MATCHING_RULES);
- for (MatchingRule matchingRule : getMatchingRules())
+ for (final MatchingRule matchingRule : getMatchingRules())
{
attr.add(matchingRule.toString());
}
@@ -2575,7 +2783,7 @@
}
attr = new LinkedAttribute(Schema.ATTR_DIT_CONTENT_RULES);
- for (DITContentRule ditContentRule : getDITContentRules())
+ for (final DITContentRule ditContentRule : getDITContentRules())
{
attr.add(ditContentRule.toString());
}
@@ -2585,7 +2793,7 @@
}
attr = new LinkedAttribute(Schema.ATTR_DIT_STRUCTURE_RULES);
- for (DITStructureRule ditStructureRule : getDITStuctureRules())
+ for (final DITStructureRule ditStructureRule : getDITStuctureRules())
{
attr.add(ditStructureRule.toString());
}
@@ -2595,7 +2803,7 @@
}
attr = new LinkedAttribute(Schema.ATTR_NAME_FORMS);
- for (NameForm nameForm : getNameForms())
+ for (final NameForm nameForm : getNameForms())
{
attr.add(nameForm.toString());
}
@@ -2609,8 +2817,631 @@
- SchemaCompatOptions getSchemaCompatOptions()
+ /**
+ * Returns {@code true} if the provided entry is valid according to this
+ * schema and the specified schema validation policy.
+ * <p>
+ * If attribute value validation is enabled then following checks will be
+ * performed:
+ * <ul>
+ * <li>checking that there is at least one value
+ * <li>checking that single-valued attributes contain only a single value
+ * </ul>
+ * In particular, attribute values will not be checked for conformance to
+ * their syntax since this is expected to have already been performed while
+ * adding the values to the entry.
+ *
+ * @param entry
+ * The entry to be validated.
+ * @param policy
+ * The schema validation policy.
+ * @param errorMessages
+ * A collection into which any schema validation warnings or error
+ * messages can be placed, or {@code null} if they should not be
+ * saved.
+ * @return {@code true} if an entry conforms to this schema based on the
+ * provided schema validation policy.
+ */
+ public boolean validateEntry(final Entry entry,
+ final SchemaValidationPolicy policy,
+ final Collection<LocalizableMessage> errorMessages)
{
- return impl.getSchemaCompatOptions();
+ // First check that the object classes are recognized and that there is one
+ // structural object class.
+ ObjectClass structuralObjectClass = null;
+ final Attribute objectClassAttribute = entry.getAttribute(objectClass());
+ final List<ObjectClass> objectClasses = new LinkedList<ObjectClass>();
+ if (objectClassAttribute != null)
+ {
+ for (final ByteString v : objectClassAttribute)
+ {
+ final String objectClassName = v.toString();
+ final ObjectClass objectClass;
+ try
+ {
+ objectClass = getObjectClass(objectClassName);
+ objectClasses.add(objectClass);
+ }
+ catch (final UnknownSchemaElementException e)
+ {
+ if (policy.checkAttributesAndObjectClasses().needsChecking())
+ {
+ if (errorMessages != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_UNKNOWN_OBJECT_CLASS
+ .get(entry.getName().toString(), objectClassName);
+ errorMessages.add(message);
+ }
+ if (policy.checkAttributesAndObjectClasses().isReject())
+ {
+ return false;
+ }
+ }
+ continue;
+ }
+
+ if (objectClass.getObjectClassType() == ObjectClassType.STRUCTURAL)
+ {
+ if (structuralObjectClass == null
+ || objectClass.isDescendantOf(structuralObjectClass))
+ {
+ structuralObjectClass = objectClass;
+ }
+ else if (!structuralObjectClass.isDescendantOf(objectClass))
+ {
+ if (policy.requireSingleStructuralObjectClass().needsChecking())
+ {
+ if (errorMessages != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_MULTIPLE_STRUCTURAL_CLASSES
+ .get(entry.getName().toString(),
+ structuralObjectClass.getNameOrOID(), objectClassName);
+ errorMessages.add(message);
+ }
+ if (policy.requireSingleStructuralObjectClass().isReject())
+ {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Collection<DITStructureRule> ditStructureRules = Collections.emptyList();
+ DITContentRule ditContentRule = null;
+
+ if (structuralObjectClass == null)
+ {
+ if (policy.requireSingleStructuralObjectClass().needsChecking())
+ {
+ if (errorMessages != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_NO_STRUCTURAL_CLASS
+ .get(entry.getName().toString());
+ errorMessages.add(message);
+ }
+ if (policy.requireSingleStructuralObjectClass().isReject())
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ ditContentRule = getDITContentRule(structuralObjectClass);
+ if (ditContentRule != null && ditContentRule.isObsolete())
+ {
+ ditContentRule = null;
+ }
+ }
+
+ // Check entry conforms to object classes and optional content rule.
+ if (!checkAttributesAndObjectClasses(entry, policy, errorMessages,
+ objectClasses, ditContentRule))
+ {
+ return false;
+ }
+
+ // Check that the name of the entry conforms to at least one applicable name
+ // form.
+ if (policy.checkNameForms().needsChecking()
+ && structuralObjectClass != null)
+ {
+ /**
+ * There may be multiple name forms registered with this structural object
+ * class. However, we need to select only one of the name forms and its
+ * corresponding DIT structure rule(s). We will iterate over all the name
+ * forms and see if at least one is acceptable before rejecting the entry.
+ * DIT structure rules corresponding to other non-acceptable name forms
+ * are not applied.
+ */
+ boolean foundMatchingNameForms = false;
+ NameForm nameForm = null;
+ final List<LocalizableMessage> nameFormWarnings =
+ (errorMessages != null) ? new LinkedList<LocalizableMessage>() : null;
+ for (final NameForm nf : getNameForms(structuralObjectClass))
+ {
+ if (nf.isObsolete())
+ {
+ continue;
+ }
+
+ // If there are any candidate name forms then at least one should be
+ // valid.
+ foundMatchingNameForms = true;
+
+ if (checkNameForm(entry, policy, nameFormWarnings, nf))
+ {
+ nameForm = nf;
+ break;
+ }
+ }
+
+ if (foundMatchingNameForms)
+ {
+ if (nameForm != null)
+ {
+ ditStructureRules = getDITStructureRules(nameForm);
+ }
+ else
+ {
+ // We couldn't match this entry against any of the name forms, so
+ // append the reasons why they didn't match and reject if required.
+ if (errorMessages != null)
+ {
+ errorMessages.addAll(nameFormWarnings);
+ }
+ if (policy.checkNameForms().isReject())
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ // Check DIT structure rules - this needs the parent entry.
+ if (policy.checkDITStructureRules().needsChecking()
+ && !entry.getName().isRootDN())
+ {
+ boolean foundMatchingRules = false;
+ boolean foundValidRule = false;
+ final List<LocalizableMessage> ruleWarnings =
+ (errorMessages != null) ? new LinkedList<LocalizableMessage>() : null;
+ ObjectClass parentStructuralObjectClass = null;
+ boolean parentEntryHasBeenRead = false;
+ for (final DITStructureRule rule : ditStructureRules)
+ {
+ if (rule.isObsolete())
+ {
+ continue;
+ }
+
+ foundMatchingRules = true;
+
+ // A DIT structure rule with no superiors is automatically valid, so
+ // avoid reading the parent.
+ if (rule.getSuperiorRules().isEmpty())
+ {
+ foundValidRule = true;
+ break;
+ }
+
+ if (!parentEntryHasBeenRead)
+ {
+ // Don't drop out immediately on failure because there may be some
+ // applicable rules which do not require the parent entry.
+ parentStructuralObjectClass = getParentStructuralObjectClass(entry,
+ policy, ruleWarnings);
+ parentEntryHasBeenRead = true;
+ }
+
+ if (parentStructuralObjectClass != null)
+ {
+ if (checkDITStructureRule(entry, policy, ruleWarnings, rule,
+ structuralObjectClass, parentStructuralObjectClass))
+ {
+ foundValidRule = true;
+ break;
+ }
+ }
+ }
+
+ if (foundMatchingRules)
+ {
+ if (!foundValidRule)
+ {
+ // We couldn't match this entry against any of the rules, so
+ // append the reasons why they didn't match and reject if required.
+ if (errorMessages != null)
+ {
+ errorMessages.addAll(ruleWarnings);
+ }
+ if (policy.checkDITStructureRules().isReject())
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // There is no DIT structure rule for this entry, but there may
+ // be one for the parent entry. If there is such a rule for the
+ // parent entry, then this entry will not be valid.
+
+ // The parent won't have been read yet.
+ parentStructuralObjectClass = getParentStructuralObjectClass(entry,
+ policy, ruleWarnings);
+ if (parentStructuralObjectClass == null)
+ {
+ if (errorMessages != null)
+ {
+ errorMessages.addAll(ruleWarnings);
+ }
+ if (policy.checkDITStructureRules().isReject())
+ {
+ return false;
+ }
+ }
+ else
+ {
+ for (final NameForm nf : getNameForms(parentStructuralObjectClass))
+ {
+ if (!nf.isObsolete())
+ {
+ for (final DITStructureRule rule : getDITStructureRules(nf))
+ {
+ if (!rule.isObsolete())
+ {
+ if (errorMessages != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_DSR_MISSING_DSR
+ .get(entry.getName().toString(), rule.getNameOrRuleID());
+ errorMessages.add(message);
+ }
+ if (policy.checkDITStructureRules().isReject())
+ {
+ return false;
+ }
+
+ // We could break out of the loop here in warn mode but
+ // continuing allows us to collect all conflicts.
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // If we've gotten here, then the entry is acceptable.
+ return true;
+ }
+
+
+
+ private boolean checkAttributesAndObjectClasses(final Entry entry,
+ final SchemaValidationPolicy policy,
+ final Collection<LocalizableMessage> errorMessages,
+ final List<ObjectClass> objectClasses, final DITContentRule ditContentRule)
+ {
+ // Check object classes.
+ final boolean checkDITContentRule = policy.checkDITContentRules()
+ .needsChecking() && ditContentRule != null;
+ final boolean checkObjectClasses = policy.checkAttributesAndObjectClasses()
+ .needsChecking();
+ final boolean checkAttributeValues = policy.checkAttributeValues()
+ .needsChecking();
+
+ if (checkObjectClasses || checkDITContentRule)
+ {
+ for (final ObjectClass objectClass : objectClasses)
+ {
+ // Make sure that any auxiliary object classes are permitted by the
+ // content rule.
+ if (checkDITContentRule)
+ {
+ if (objectClass.getObjectClassType() == ObjectClassType.AUXILIARY)
+ {
+ if (errorMessages != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_DCR_PROHIBITED_AUXILIARY_OC
+ .get(entry.getName().toString(), objectClass.getNameOrOID(),
+ ditContentRule.getNameOrOID());
+ errorMessages.add(message);
+ }
+ if (policy.checkDITContentRules().isReject())
+ {
+ return false;
+ }
+ }
+ }
+
+ // Make sure that all of the attributes required by the object class are
+ // present.
+ if (checkObjectClasses)
+ {
+ for (final AttributeType t : objectClass.getRequiredAttributes())
+ {
+ final Attribute a = Attributes.emptyAttribute(AttributeDescription
+ .create(t));
+ if (entry.containsAttribute(a, null))
+ {
+ if (errorMessages != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_OC_MISSING_MUST_ATTRIBUTES
+ .get(entry.getName().toString(), t.getNameOrOID(),
+ objectClass.getNameOrOID());
+ errorMessages.add(message);
+ }
+ if (policy.checkAttributesAndObjectClasses().isReject())
+ {
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ // Make sure that all of the attributes required by the content rule are
+ // present.
+ if (checkDITContentRule)
+ {
+ for (final AttributeType t : ditContentRule.getRequiredAttributes())
+ {
+ final Attribute a = Attributes.emptyAttribute(AttributeDescription
+ .create(t));
+ if (entry.containsAttribute(a, null))
+ {
+ if (errorMessages != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_DCR_MISSING_MUST_ATTRIBUTES
+ .get(entry.getName().toString(), t.getNameOrOID(),
+ ditContentRule.getNameOrOID());
+ errorMessages.add(message);
+ }
+ if (policy.checkDITContentRules().isReject())
+ {
+ return false;
+ }
+ }
+ }
+
+ // Make sure that attributes prohibited by the content rule are not
+ // present.
+ for (final AttributeType t : ditContentRule.getProhibitedAttributes())
+ {
+ final Attribute a = Attributes.emptyAttribute(AttributeDescription
+ .create(t));
+ if (entry.containsAttribute(a, null))
+ {
+ if (errorMessages != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_DCR_PROHIBITED_ATTRIBUTES
+ .get(entry.getName().toString(), t.getNameOrOID(),
+ ditContentRule.getNameOrOID());
+ errorMessages.add(message);
+ }
+ if (policy.checkDITContentRules().isReject())
+ {
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ // Check attributes.
+ if (checkObjectClasses || checkDITContentRule || checkAttributeValues)
+ {
+ for (final Attribute attribute : entry.getAllAttributes())
+ {
+ final AttributeType t = attribute.getAttributeDescription()
+ .getAttributeType();
+
+ if (!t.isOperational())
+ {
+ if (checkObjectClasses || checkDITContentRule)
+ {
+ boolean isAllowed = false;
+ for (final ObjectClass objectClass : objectClasses)
+ {
+ if (objectClass.isRequiredOrOptional(t))
+ {
+ isAllowed = true;
+ break;
+ }
+ }
+ if (!isAllowed && ditContentRule != null)
+ {
+ if (ditContentRule.isRequiredOrOptional(t))
+ {
+ isAllowed = true;
+ }
+ }
+ if (!isAllowed)
+ {
+ if (errorMessages != null)
+ {
+ final LocalizableMessage message;
+ if (ditContentRule == null)
+ {
+ message = ERR_ENTRY_SCHEMA_OC_DISALLOWED_ATTRIBUTES.get(entry
+ .getName().toString(), t.getNameOrOID());
+ }
+ else
+ {
+ message = ERR_ENTRY_SCHEMA_DCR_DISALLOWED_ATTRIBUTES.get(
+ entry.getName().toString(), t.getNameOrOID(),
+ ditContentRule.getNameOrOID());
+ }
+ errorMessages.add(message);
+ }
+ if (policy.checkAttributesAndObjectClasses().isReject()
+ || policy.checkDITContentRules().isReject())
+ {
+ return false;
+ }
+ }
+ }
+
+ // Check attributes contain an appropriate number of values.
+ if (checkAttributeValues)
+ {
+ final int sz = attribute.size();
+
+ if (sz == 0)
+ {
+ if (errorMessages != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_AT_EMPTY_ATTRIBUTE
+ .get(entry.getName().toString(), t.getNameOrOID());
+ errorMessages.add(message);
+ }
+ if (policy.checkAttributeValues().isReject())
+ {
+ return false;
+ }
+ }
+ else if (sz > 1 && t.isSingleValue())
+ {
+ if (errorMessages != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_AT_SINGLE_VALUED_ATTRIBUTE
+ .get(entry.getName().toString(), t.getNameOrOID());
+ errorMessages.add(message);
+ }
+ if (policy.checkAttributeValues().isReject())
+ {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // If we've gotten here, then things are OK.
+ return true;
+ }
+
+
+
+ private boolean checkDITStructureRule(final Entry entry,
+ final SchemaValidationPolicy policy,
+ final List<LocalizableMessage> ruleWarnings, final DITStructureRule rule,
+ final ObjectClass structuralObjectClass,
+ final ObjectClass parentStructuralObjectClass)
+ {
+ boolean matchFound = false;
+ for (final DITStructureRule parentRule : rule.getSuperiorRules())
+ {
+ if (parentRule.getNameForm().getStructuralClass()
+ .equals(parentStructuralObjectClass))
+ {
+ matchFound = true;
+ }
+ }
+
+ if (!matchFound)
+ {
+ if (ruleWarnings != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_DSR_ILLEGAL_OC.get(
+ entry.getName().toString(), rule.getNameOrRuleID(),
+ structuralObjectClass.getNameOrOID(),
+ parentStructuralObjectClass.getNameOrOID());
+ ruleWarnings.add(message);
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+
+
+ private boolean checkNameForm(final Entry entry,
+ final SchemaValidationPolicy policy,
+ final List<LocalizableMessage> nameFormWarnings, final NameForm nameForm)
+ {
+ final RDN rdn = entry.getName().rdn();
+ if (rdn != null)
+ {
+ // Make sure that all the required AVAs are present.
+ for (final AttributeType t : nameForm.getRequiredAttributes())
+ {
+ if (rdn.getAttributeValue(t) == null)
+ {
+ if (nameFormWarnings != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_NF_MISSING_MUST_ATTRIBUTES
+ .get(entry.getName().toString(), t.getNameOrOID(),
+ nameForm.getNameOrOID());
+ nameFormWarnings.add(message);
+ }
+ return false;
+ }
+ }
+
+ // Make sure that all AVAs in the RDN are allowed.
+ for (final AVA ava : rdn)
+ {
+ final AttributeType t = ava.getAttributeType();
+ if (nameForm.isRequiredOrOptional(t))
+ {
+ if (nameFormWarnings != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_NF_DISALLOWED_ATTRIBUTES
+ .get(entry.getName().toString(), t.getNameOrOID(),
+ nameForm.getNameOrOID());
+ nameFormWarnings.add(message);
+ }
+ return false;
+ }
+ }
+ }
+
+ // If we've gotten here, then things are OK.
+ return true;
+ }
+
+
+
+ private ObjectClass getParentStructuralObjectClass(final Entry entry,
+ final SchemaValidationPolicy policy,
+ final List<LocalizableMessage> ruleWarnings)
+ {
+ final Entry parentEntry;
+ try
+ {
+ parentEntry = policy.checkDITStructureRulesEntryResolver().getEntry(
+ entry.getName().parent());
+ }
+ catch (final ErrorResultException e)
+ {
+ if (ruleWarnings != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_DSR_PARENT_NOT_FOUND
+ .get(entry.getName().toString(), e.getResult()
+ .getDiagnosticMessage());
+ ruleWarnings.add(message);
+ }
+ return null;
+ }
+
+ final ObjectClass parentStructuralObjectClass = Entries
+ .getStructuralObjectClass(parentEntry, this);
+ if (parentStructuralObjectClass == null)
+ {
+ if (ruleWarnings != null)
+ {
+ final LocalizableMessage message = ERR_ENTRY_SCHEMA_DSR_NO_PARENT_OC
+ .get(entry.getName().toString());
+ ruleWarnings.add(message);
+ }
+ return null;
+ }
+ return parentStructuralObjectClass;
}
}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
index 11cbb23..3e4b81b 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -30,11 +30,17 @@
+import static com.forgerock.opendj.util.StaticUtils.toLowerCase;
import static org.forgerock.opendj.ldap.CoreMessages.*;
import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
import static org.forgerock.opendj.ldap.schema.Schema.*;
-import static org.forgerock.opendj.ldap.schema.SchemaConstants.*;
-import static org.forgerock.opendj.ldap.schema.SchemaUtils.*;
+import static org.forgerock.opendj.ldap.schema.SchemaConstants.EXTENSIBLE_OBJECT_OBJECTCLASS_OID;
+import static org.forgerock.opendj.ldap.schema.SchemaConstants.OMR_GENERIC_ENUM_NAME;
+import static org.forgerock.opendj.ldap.schema.SchemaConstants.SCHEMA_PROPERTY_APPROX_RULE;
+import static org.forgerock.opendj.ldap.schema.SchemaConstants.TOP_OBJECTCLASS_NAME;
+import static org.forgerock.opendj.ldap.schema.SchemaUtils.unmodifiableCopyOfExtraProperties;
+import static org.forgerock.opendj.ldap.schema.SchemaUtils.unmodifiableCopyOfList;
+import static org.forgerock.opendj.ldap.schema.SchemaUtils.unmodifiableCopyOfSet;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
@@ -67,18 +73,7 @@
private static final Filter SUBSCHEMA_FILTER = Filter
.valueOf("(objectClass=subschema)");
- private static final String[] SUBSCHEMA_SUBENTRY_ATTRS =
- new String[] { ATTR_SUBSCHEMA_SUBENTRY };
-
-
-
- // Constructs a search request for retrieving the named subschema
- // sub-entry.
- private static SearchRequest getReadSchemaSearchRequest(final DN dn)
- {
- return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT,
- SUBSCHEMA_FILTER, SUBSCHEMA_ATTRS);
- }
+ private static final String[] SUBSCHEMA_SUBENTRY_ATTRS = new String[] { ATTR_SUBSCHEMA_SUBENTRY };
@@ -92,6 +87,16 @@
+ // Constructs a search request for retrieving the named subschema
+ // sub-entry.
+ private static SearchRequest getReadSchemaSearchRequest(final DN dn)
+ {
+ return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT,
+ SUBSCHEMA_FILTER, SUBSCHEMA_ATTRS);
+ }
+
+
+
private static DN getSubschemaSubentryDN(final DN name, final Entry entry)
throws ErrorResultException
{
@@ -156,11 +161,15 @@
private Map<String, List<NameForm>> objectClass2NameForms;
- private SchemaCompatOptions options;
+ private String schemaName;
private List<LocalizableMessage> warnings;
- private Schema schema;
+ private boolean allowNonStandardTelephoneNumbers;
+
+ private boolean allowZeroLengthDirectoryStrings;
+
+ private boolean allowMalformedNamesAndOptions;
// A unique ID which can be used to uniquely identify schemas
// constructed without a name.
@@ -211,7 +220,6 @@
public SchemaBuilder(final Schema schema) throws NullPointerException
{
initBuilder(schema.getSchemaName());
- setSchemaCompatOptions(schema.getSchemaCompatOptions());
addSchema(schema, true);
}
@@ -287,7 +295,7 @@
// The next set of characters must be the OID.
final String oid = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
List<String> names = Collections.emptyList();
String description = "".intern();
@@ -324,7 +332,7 @@
else if (tokenName.equalsIgnoreCase("name"))
{
names = SchemaUtils.readNameDescriptors(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("desc"))
{
@@ -346,28 +354,28 @@
// type from which this attribute type should inherit its
// properties.
superiorType = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("equality"))
{
// This specifies the name or OID of the equality matching
// rule to use for this attribute type.
equalityMatchingRule = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("ordering"))
{
// This specifies the name or OID of the ordering matching
// rule to use for this attribute type.
orderingMatchingRule = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("substr"))
{
// This specifies the name or OID of the substring matching
// rule to use for this attribute type.
substringMatchingRule = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("syntax"))
{
@@ -379,8 +387,8 @@
// implementation will ignore any such length because it does
// not impose any practical limit on the length of attribute
// values.
- syntax = SchemaUtils.readOIDLen(reader,
- options.allowMalformedNamesAndOptions());
+ syntax = SchemaUtils
+ .readOIDLen(reader, allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("single-definition"))
{
@@ -494,8 +502,8 @@
}
catch (final DecodeException e)
{
- LocalizableMessage msg = ERR_ATTR_SYNTAX_ATTRTYPE_INVALID1.get(definition,
- e.getMessageObject());
+ final LocalizableMessage msg = ERR_ATTR_SYNTAX_ATTRTYPE_INVALID1.get(
+ definition, e.getMessageObject());
throw new LocalizedIllegalArgumentException(msg, e.getCause());
}
return this;
@@ -533,10 +541,10 @@
* be used or, if none is defined, the default matching rule
* associated with the syntax.
* @param approximateMatchingRule
- * The OID of the approximate matching rule, which may be {@code
- * null} indicating that the superior attribute type's matching rule
- * should be used or, if none is defined, the default matching rule
- * associated with the syntax.
+ * The OID of the approximate matching rule, which may be
+ * {@code null} indicating that the superior attribute type's
+ * matching rule should be used or, if none is defined, the default
+ * matching rule associated with the syntax.
* @param syntax
* The OID of the syntax definition.
* @param singleValue
@@ -638,7 +646,7 @@
// The next set of characters must be the OID.
final String structuralClass = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
List<String> names = Collections.emptyList();
String description = "".intern();
@@ -669,7 +677,7 @@
else if (tokenName.equalsIgnoreCase("name"))
{
names = SchemaUtils.readNameDescriptors(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("desc"))
{
@@ -688,22 +696,22 @@
else if (tokenName.equalsIgnoreCase("aux"))
{
auxiliaryClasses = SchemaUtils.readOIDs(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("must"))
{
requiredAttributes = SchemaUtils.readOIDs(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("may"))
{
optionalAttributes = SchemaUtils.readOIDs(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("not"))
{
prohibitedAttributes = SchemaUtils.readOIDs(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.matches("^X-[A-Za-z_-]+$"))
{
@@ -738,8 +746,8 @@
}
catch (final DecodeException e)
{
- LocalizableMessage msg = ERR_ATTR_SYNTAX_DCR_INVALID1.get(definition,
- e.getMessageObject());
+ final LocalizableMessage msg = ERR_ATTR_SYNTAX_DCR_INVALID1.get(
+ definition, e.getMessageObject());
throw new LocalizedIllegalArgumentException(msg, e.getCause());
}
return this;
@@ -933,7 +941,7 @@
else if (tokenName.equalsIgnoreCase("name"))
{
names = SchemaUtils.readNameDescriptors(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("desc"))
{
@@ -951,8 +959,7 @@
}
else if (tokenName.equalsIgnoreCase("form"))
{
- nameForm = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ nameForm = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("sup"))
{
@@ -998,8 +1005,8 @@
}
catch (final DecodeException e)
{
- LocalizableMessage msg = ERR_ATTR_SYNTAX_DSR_INVALID1.get(definition,
- e.getMessageObject());
+ final LocalizableMessage msg = ERR_ATTR_SYNTAX_DSR_INVALID1.get(
+ definition, e.getMessageObject());
throw new LocalizedIllegalArgumentException(msg, e.getCause());
}
return this;
@@ -1031,13 +1038,14 @@
{
Validator.ensureNotNull((Object) enumerations);
- final EnumSyntaxImpl enumImpl = new EnumSyntaxImpl(oid, Arrays
- .asList(enumerations));
- final Syntax enumSyntax = new Syntax(oid, description, Collections
- .singletonMap("X-ENUM", Arrays.asList(enumerations)), null, enumImpl);
- final MatchingRule enumOMR = new MatchingRule(enumImpl
- .getOrderingMatchingRule(), Collections
- .singletonList(OMR_GENERIC_ENUM_NAME + oid), "", false, oid,
+ final EnumSyntaxImpl enumImpl = new EnumSyntaxImpl(oid,
+ Arrays.asList(enumerations));
+ final Syntax enumSyntax = new Syntax(oid, description,
+ Collections.singletonMap("X-ENUM", Arrays.asList(enumerations)), null,
+ enumImpl);
+ final MatchingRule enumOMR = new MatchingRule(
+ enumImpl.getOrderingMatchingRule(),
+ Collections.singletonList(OMR_GENERIC_ENUM_NAME + oid), "", false, oid,
CoreSchemaImpl.OPENDS_ORIGIN, null, new EnumOrderingMatchingRule(
enumImpl));
@@ -1110,7 +1118,7 @@
// The next set of characters must be the OID.
final String oid = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
List<String> names = Collections.emptyList();
String description = "".intern();
@@ -1138,7 +1146,7 @@
else if (tokenName.equalsIgnoreCase("name"))
{
names = SchemaUtils.readNameDescriptors(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("desc"))
{
@@ -1156,8 +1164,7 @@
}
else if (tokenName.equalsIgnoreCase("syntax"))
{
- syntax = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ syntax = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
}
else if (tokenName.matches("^X-[A-Za-z_-]+$"))
{
@@ -1198,8 +1205,8 @@
}
catch (final DecodeException e)
{
- LocalizableMessage msg = ERR_ATTR_SYNTAX_MR_INVALID1.get(definition,
- e.getMessageObject());
+ final LocalizableMessage msg = ERR_ATTR_SYNTAX_MR_INVALID1.get(
+ definition, e.getMessageObject());
throw new LocalizedIllegalArgumentException(msg, e.getCause());
}
return this;
@@ -1307,7 +1314,7 @@
// The next set of characters must be the OID.
final String oid = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
List<String> names = Collections.emptyList();
String description = "".intern();
@@ -1335,7 +1342,7 @@
else if (tokenName.equalsIgnoreCase("name"))
{
names = SchemaUtils.readNameDescriptors(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("desc"))
{
@@ -1354,7 +1361,7 @@
else if (tokenName.equalsIgnoreCase("applies"))
{
attributes = SchemaUtils.readOIDs(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.matches("^X-[A-Za-z_-]+$"))
{
@@ -1396,8 +1403,8 @@
}
catch (final DecodeException e)
{
- LocalizableMessage msg = ERR_ATTR_SYNTAX_MRUSE_INVALID1.get(definition,
- e.getMessageObject());
+ final LocalizableMessage msg = ERR_ATTR_SYNTAX_MRUSE_INVALID1.get(
+ definition, e.getMessageObject());
throw new LocalizedIllegalArgumentException(msg, e.getCause());
}
return this;
@@ -1501,7 +1508,7 @@
// The next set of characters must be the OID.
final String oid = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
List<String> names = Collections.emptyList();
String description = "".intern();
@@ -1531,7 +1538,7 @@
else if (tokenName.equalsIgnoreCase("name"))
{
names = SchemaUtils.readNameDescriptors(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("desc"))
{
@@ -1550,17 +1557,17 @@
else if (tokenName.equalsIgnoreCase("oc"))
{
structuralClass = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("must"))
{
requiredAttributes = SchemaUtils.readOIDs(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("may"))
{
optionalAttributes = SchemaUtils.readOIDs(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.matches("^X-[A-Za-z_-]+$"))
{
@@ -1611,8 +1618,8 @@
}
catch (final DecodeException e)
{
- LocalizableMessage msg = ERR_ATTR_SYNTAX_NAME_FORM_INVALID1.get(definition,
- e.getMessageObject());
+ final LocalizableMessage msg = ERR_ATTR_SYNTAX_NAME_FORM_INVALID1.get(
+ definition, e.getMessageObject());
throw new LocalizedIllegalArgumentException(msg, e.getCause());
}
return this;
@@ -1724,7 +1731,7 @@
// The next set of characters must be the OID.
final String oid = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
List<String> names = Collections.emptyList();
String description = "".intern();
@@ -1755,7 +1762,7 @@
else if (tokenName.equalsIgnoreCase("name"))
{
names = SchemaUtils.readNameDescriptors(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("desc"))
{
@@ -1774,7 +1781,7 @@
else if (tokenName.equalsIgnoreCase("sup"))
{
superiorClasses = SchemaUtils.readOIDs(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("abstract"))
{
@@ -1799,12 +1806,12 @@
else if (tokenName.equalsIgnoreCase("must"))
{
requiredAttributes = SchemaUtils.readOIDs(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.equalsIgnoreCase("may"))
{
optionalAttributes = SchemaUtils.readOIDs(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
}
else if (tokenName.matches("^X-[A-Za-z_-]+$"))
{
@@ -1851,8 +1858,8 @@
}
catch (final DecodeException e)
{
- LocalizableMessage msg = ERR_ATTR_SYNTAX_OBJECTCLASS_INVALID1.get(definition,
- e.getMessageObject());
+ final LocalizableMessage msg = ERR_ATTR_SYNTAX_OBJECTCLASS_INVALID1.get(
+ definition, e.getMessageObject());
throw new LocalizedIllegalArgumentException(msg, e.getCause());
}
return this;
@@ -1958,6 +1965,102 @@
/**
+ * Reads the schema elements contained in the named subschema sub-entry and
+ * adds them to this schema builder.
+ * <p>
+ * If the requested schema is not returned by the Directory Server then the
+ * request will fail with an {@link EntryNotFoundException}.
+ *
+ * @param connection
+ * A connection to the Directory Server whose schema is to be read.
+ * @param name
+ * The distinguished name of the subschema sub-entry.
+ * @param handler
+ * A result handler which can be used to asynchronously process the
+ * operation result when it is received, may be {@code null}.
+ * @param overwrite
+ * {@code true} if existing schema elements with the same conflicting
+ * OIDs should be overwritten.
+ * @return A future representing the updated schema builder.
+ * @throws UnsupportedOperationException
+ * If the connection does not support search operations.
+ * @throws IllegalStateException
+ * If the connection has already been closed, i.e. if
+ * {@code connection.isClosed() == true}.
+ * @throws NullPointerException
+ * If the {@code connection} or {@code name} was {@code null}.
+ */
+ public FutureResult<SchemaBuilder> addSchema(
+ final AsynchronousConnection connection, final DN name,
+ final ResultHandler<? super SchemaBuilder> handler,
+ final boolean overwrite) throws UnsupportedOperationException,
+ IllegalStateException, NullPointerException
+ {
+ final SearchRequest request = getReadSchemaSearchRequest(name);
+
+ final FutureResultTransformer<SearchResultEntry, SchemaBuilder> future =
+ new FutureResultTransformer<SearchResultEntry, SchemaBuilder>(handler)
+ {
+
+ @Override
+ protected SchemaBuilder transformResult(final SearchResultEntry result)
+ throws ErrorResultException
+ {
+ addSchema(result, overwrite);
+ return SchemaBuilder.this;
+ }
+
+ };
+
+ final FutureResult<SearchResultEntry> innerFuture = connection
+ .searchSingleEntry(request, future);
+ future.setFutureResult(innerFuture);
+ return future;
+ }
+
+
+
+ /**
+ * Reads the schema elements contained in the named subschema sub-entry and
+ * adds them to this schema builder.
+ * <p>
+ * If the requested schema is not returned by the Directory Server then the
+ * request will fail with an {@link EntryNotFoundException}.
+ *
+ * @param connection
+ * A connection to the Directory Server whose schema is to be read.
+ * @param name
+ * The distinguished name of the subschema sub-entry.
+ * @param overwrite
+ * {@code true} if existing schema elements with the same conflicting
+ * OIDs should be overwritten.
+ * @return A reference to this schema builder.
+ * @throws ErrorResultException
+ * If the result code indicates that the request failed for some
+ * reason.
+ * @throws InterruptedException
+ * If the current thread was interrupted while waiting.
+ * @throws UnsupportedOperationException
+ * If the connection does not support search operations.
+ * @throws IllegalStateException
+ * If the connection has already been closed, i.e. if
+ * {@code isClosed() == true}.
+ * @throws NullPointerException
+ * If the {@code connection} or {@code name} was {@code null}.
+ */
+ public SchemaBuilder addSchema(final Connection connection, final DN name,
+ final boolean overwrite) throws ErrorResultException,
+ InterruptedException, UnsupportedOperationException,
+ IllegalStateException, NullPointerException
+ {
+ final SearchRequest request = getReadSchemaSearchRequest(name);
+ final Entry entry = connection.searchSingleEntry(request);
+ return addSchema(entry, overwrite);
+ }
+
+
+
+ /**
* Adds all of the schema elements contained in the provided subschema
* subentry to this schema builder. Any problems encountered while parsing the
* entry can be retrieved using the returned schema's
@@ -2176,102 +2279,6 @@
/**
- * Reads the schema elements contained in the named subschema sub-entry and
- * adds them to this schema builder.
- * <p>
- * If the requested schema is not returned by the Directory Server then the
- * request will fail with an {@link EntryNotFoundException}.
- *
- * @param connection
- * A connection to the Directory Server whose schema is to be read.
- * @param name
- * The distinguished name of the subschema sub-entry.
- * @param handler
- * A result handler which can be used to asynchronously process the
- * operation result when it is received, may be {@code null}.
- * @param overwrite
- * {@code true} if existing schema elements with the same conflicting
- * OIDs should be overwritten.
- * @return A future representing the updated schema builder.
- * @throws UnsupportedOperationException
- * If the connection does not support search operations.
- * @throws IllegalStateException
- * If the connection has already been closed, i.e. if
- * {@code connection.isClosed() == true}.
- * @throws NullPointerException
- * If the {@code connection} or {@code name} was {@code null}.
- */
- public FutureResult<SchemaBuilder> addSchema(
- final AsynchronousConnection connection, final DN name,
- final ResultHandler<? super SchemaBuilder> handler,
- final boolean overwrite) throws UnsupportedOperationException,
- IllegalStateException, NullPointerException
- {
- final SearchRequest request = getReadSchemaSearchRequest(name);
-
- final FutureResultTransformer<SearchResultEntry, SchemaBuilder> future =
- new FutureResultTransformer<SearchResultEntry, SchemaBuilder>(handler)
- {
-
- @Override
- protected SchemaBuilder transformResult(final SearchResultEntry result)
- throws ErrorResultException
- {
- addSchema(result, overwrite);
- return SchemaBuilder.this;
- }
-
- };
-
- final FutureResult<SearchResultEntry> innerFuture = connection
- .searchSingleEntry(request, future);
- future.setFutureResult(innerFuture);
- return future;
- }
-
-
-
- /**
- * Reads the schema elements contained in the named subschema sub-entry and
- * adds them to this schema builder.
- * <p>
- * If the requested schema is not returned by the Directory Server then the
- * request will fail with an {@link EntryNotFoundException}.
- *
- * @param connection
- * A connection to the Directory Server whose schema is to be read.
- * @param name
- * The distinguished name of the subschema sub-entry.
- * @param overwrite
- * {@code true} if existing schema elements with the same conflicting
- * OIDs should be overwritten.
- * @return A reference to this schema builder.
- * @throws ErrorResultException
- * If the result code indicates that the request failed for some
- * reason.
- * @throws InterruptedException
- * If the current thread was interrupted while waiting.
- * @throws UnsupportedOperationException
- * If the connection does not support search operations.
- * @throws IllegalStateException
- * If the connection has already been closed, i.e. if
- * {@code isClosed() == true}.
- * @throws NullPointerException
- * If the {@code connection} or {@code name} was {@code null}.
- */
- public SchemaBuilder addSchema(final Connection connection, final DN name,
- final boolean overwrite) throws ErrorResultException,
- InterruptedException, UnsupportedOperationException,
- IllegalStateException, NullPointerException
- {
- final SearchRequest request = getReadSchemaSearchRequest(name);
- final Entry entry = connection.searchSingleEntry(request);
- return addSchema(entry, overwrite);
- }
-
-
-
- /**
* Reads the schema elements contained in the subschema sub-entry which
* applies to the named entry and adds them to this schema builder.
* <p>
@@ -2403,8 +2410,10 @@
{
Validator.ensureNotNull(substituteSyntax);
- addSyntax(new Syntax(oid, description, Collections.singletonMap("X-SUBST",
- Collections.singletonList(substituteSyntax)), null, null), overwrite);
+ addSyntax(
+ new Syntax(oid, description, Collections.singletonMap("X-SUBST",
+ Collections.singletonList(substituteSyntax)), null, null),
+ overwrite);
return this;
}
@@ -2465,7 +2474,7 @@
// The next set of characters must be the OID.
final String oid = SchemaUtils.readOID(reader,
- options.allowMalformedNamesAndOptions());
+ allowMalformedNamesAndOptions);
String description = "".intern();
Map<String, List<String>> extraProperties = Collections.emptyMap();
@@ -2525,15 +2534,15 @@
{
if (property.getKey().equalsIgnoreCase("x-enum"))
{
- final EnumSyntaxImpl enumImpl = new EnumSyntaxImpl(oid, property
- .getValue());
+ final EnumSyntaxImpl enumImpl = new EnumSyntaxImpl(oid,
+ property.getValue());
final Syntax enumSyntax = new Syntax(oid, description,
extraProperties, definition, enumImpl);
- final MatchingRule enumOMR = new MatchingRule(enumImpl
- .getOrderingMatchingRule(), Collections
- .singletonList(OMR_GENERIC_ENUM_NAME + oid), "", false, oid,
- CoreSchemaImpl.OPENDS_ORIGIN, null, new EnumOrderingMatchingRule(
- enumImpl));
+ final MatchingRule enumOMR = new MatchingRule(
+ enumImpl.getOrderingMatchingRule(),
+ Collections.singletonList(OMR_GENERIC_ENUM_NAME + oid), "",
+ false, oid, CoreSchemaImpl.OPENDS_ORIGIN, null,
+ new EnumOrderingMatchingRule(enumImpl));
addSyntax(enumSyntax, overwrite);
addMatchingRule(enumOMR, overwrite);
@@ -2547,8 +2556,8 @@
}
catch (final DecodeException e)
{
- LocalizableMessage msg = ERR_ATTR_SYNTAX_ATTRSYNTAX_INVALID1.get(definition,
- e.getMessageObject());
+ final LocalizableMessage msg = ERR_ATTR_SYNTAX_ATTRSYNTAX_INVALID1.get(
+ definition, e.getMessageObject());
throw new LocalizedIllegalArgumentException(msg, e.getCause());
}
return this;
@@ -2592,6 +2601,80 @@
/**
+ * Specifies whether or not the schema should allow certain illegal characters
+ * in OIDs and attribute options. When this compatibility option is set to
+ * {@code true} the following illegal characters will be permitted in addition
+ * to those permitted in section 1.4 of RFC 4512:
+ *
+ * <pre>
+ * USCORE = %x5F ; underscore ("_")
+ * DOT = %x2E ; period (".")
+ * </pre>
+ *
+ * By default this compatibility option is set to {@code true} because these
+ * characters are often used for naming purposes (such as collation rules).
+ *
+ * @param allowMalformedNamesAndOptions
+ * {@code true} if the schema should allow certain illegal characters
+ * in OIDs and attribute options.
+ * @return A reference to this {@code SchemaBuilder}.
+ * @see <a href="http://tools.ietf.org/html/rfc4512">RFC 4512 - Lightweight
+ * Directory Access Protocol (LDAP): Directory Information Models </a>
+ */
+ public SchemaBuilder allowMalformedNamesAndOptions(
+ final boolean allowMalformedNamesAndOptions)
+ {
+ this.allowMalformedNamesAndOptions = allowMalformedNamesAndOptions;
+ return this;
+ }
+
+
+
+ /**
+ * Specifies whether or not the Telephone Number syntax should allow values
+ * which do not conform to the E.123 international telephone number format.
+ * <p>
+ * By default this compatibility option is set to {@code true}.
+ *
+ * @param allowNonStandardTelephoneNumbers
+ * {@code true} if the Telephone Number syntax should allow values
+ * which do not conform to the E.123 international telephone number
+ * format.
+ * @return A reference to this {@code SchemaBuilder}.
+ */
+ public SchemaBuilder allowNonStandardTelephoneNumbers(
+ final boolean allowNonStandardTelephoneNumbers)
+ {
+ this.allowNonStandardTelephoneNumbers = allowNonStandardTelephoneNumbers;
+ return this;
+ }
+
+
+
+ /**
+ * Specifies whether or not zero-length values will be allowed by the
+ * Directory String syntax. This is technically forbidden by the LDAP
+ * specification, but it was allowed in earlier versions of the server, and
+ * the discussion of the directory string syntax in RFC 2252 does not
+ * explicitly state that they are not allowed.
+ * <p>
+ * By default this compatibility option is set to {@code false}.
+ *
+ * @param allowZeroLengthDirectoryStrings
+ * {@code true} if zero-length values will be allowed by the
+ * Directory String syntax, or {@code false} if not.
+ * @return A reference to this {@code SchemaBuilder}.
+ */
+ public SchemaBuilder allowZeroLengthDirectoryStrings(
+ final boolean allowZeroLengthDirectoryStrings)
+ {
+ this.allowZeroLengthDirectoryStrings = allowZeroLengthDirectoryStrings;
+ return this;
+ }
+
+
+
+ /**
* Removes the named attribute type from this schema builder.
*
* @param name
@@ -2600,9 +2683,20 @@
*/
public boolean removeAttributeType(final String name)
{
- if (schema.hasAttributeType(name))
+ final AttributeType element = numericOID2AttributeTypes.get(name);
+ if (element != null)
{
- removeAttributeType(schema.getAttributeType(name));
+ removeAttributeType(element);
+ return true;
+ }
+ final List<AttributeType> elements = name2AttributeTypes
+ .get(toLowerCase(name));
+ if (elements != null)
+ {
+ for (final AttributeType e : elements)
+ {
+ removeAttributeType(e);
+ }
return true;
}
return false;
@@ -2619,9 +2713,20 @@
*/
public boolean removeDITContentRule(final String name)
{
- if (schema.hasDITContentRule(name))
+ final DITContentRule element = numericOID2ContentRules.get(name);
+ if (element != null)
{
- removeDITContentRule(schema.getDITContentRule(name));
+ removeDITContentRule(element);
+ return true;
+ }
+ final List<DITContentRule> elements = name2ContentRules
+ .get(toLowerCase(name));
+ if (elements != null)
+ {
+ for (final DITContentRule e : elements)
+ {
+ removeDITContentRule(e);
+ }
return true;
}
return false;
@@ -2636,11 +2741,12 @@
* The ID of the DIT structure rule to be removed.
* @return {@code true} if the DIT structure rule was found.
*/
- public boolean removeDITStructureRule(final Integer ruleID)
+ public boolean removeDITStructureRule(final int ruleID)
{
- if (schema.hasDITStructureRule(ruleID))
+ final DITStructureRule element = id2StructureRules.get(ruleID);
+ if (element != null)
{
- removeDITStructureRule(schema.getDITStructureRule(ruleID));
+ removeDITStructureRule(element);
return true;
}
return false;
@@ -2657,9 +2763,20 @@
*/
public boolean removeMatchingRule(final String name)
{
- if (schema.hasMatchingRule(name))
+ final MatchingRule element = numericOID2MatchingRules.get(name);
+ if (element != null)
{
- removeMatchingRule(schema.getMatchingRule(name));
+ removeMatchingRule(element);
+ return true;
+ }
+ final List<MatchingRule> elements = name2MatchingRules
+ .get(toLowerCase(name));
+ if (elements != null)
+ {
+ for (final MatchingRule e : elements)
+ {
+ removeMatchingRule(e);
+ }
return true;
}
return false;
@@ -2676,9 +2793,20 @@
*/
public boolean removeMatchingRuleUse(final String name)
{
- if (schema.hasMatchingRuleUse(name))
+ final MatchingRuleUse element = numericOID2MatchingRuleUses.get(name);
+ if (element != null)
{
- removeMatchingRuleUse(schema.getMatchingRuleUse(name));
+ removeMatchingRuleUse(element);
+ return true;
+ }
+ final List<MatchingRuleUse> elements = name2MatchingRuleUses
+ .get(toLowerCase(name));
+ if (elements != null)
+ {
+ for (final MatchingRuleUse e : elements)
+ {
+ removeMatchingRuleUse(e);
+ }
return true;
}
return false;
@@ -2695,9 +2823,19 @@
*/
public boolean removeNameForm(final String name)
{
- if (schema.hasNameForm(name))
+ final NameForm element = numericOID2NameForms.get(name);
+ if (element != null)
{
- removeNameForm(schema.getNameForm(name));
+ removeNameForm(element);
+ return true;
+ }
+ final List<NameForm> elements = name2NameForms.get(toLowerCase(name));
+ if (elements != null)
+ {
+ for (final NameForm e : elements)
+ {
+ removeNameForm(e);
+ }
return true;
}
return false;
@@ -2714,9 +2852,20 @@
*/
public boolean removeObjectClass(final String name)
{
- if (schema.hasObjectClass(name))
+ final ObjectClass element = numericOID2ObjectClasses.get(name);
+ if (element != null)
{
- removeObjectClass(schema.getObjectClass(name));
+ removeObjectClass(element);
+ return true;
+ }
+ final List<ObjectClass> elements = name2ObjectClasses
+ .get(toLowerCase(name));
+ if (elements != null)
+ {
+ for (final ObjectClass e : elements)
+ {
+ removeObjectClass(e);
+ }
return true;
}
return false;
@@ -2733,9 +2882,10 @@
*/
public boolean removeSyntax(final String numericOID)
{
- if (schema.hasSyntax(numericOID))
+ final Syntax element = numericOID2Syntaxes.get(numericOID);
+ if (element != null)
{
- removeSyntax(schema.getSyntax(numericOID));
+ removeSyntax(element);
return true;
}
return false;
@@ -2744,28 +2894,6 @@
/**
- * Sets the schema compatibility options for this schema builder. The schema
- * builder maintains its own set of compatibility options, so subsequent
- * changes to the provided set of options will not impact this schema builder.
- *
- * @param options
- * The set of schema compatibility options that this schema builder
- * should use.
- * @return A reference to this schema builder.
- * @throws NullPointerException
- * If {@code options} was {@code null}.
- */
- public SchemaBuilder setSchemaCompatOptions(final SchemaCompatOptions options)
- throws NullPointerException
- {
- Validator.ensureNotNull(options);
- this.options.assign(options);
- return this;
- }
-
-
-
- /**
* Returns a strict {@code Schema} containing all of the schema elements
* contained in this schema builder as well as the same set of schema
* compatibility options.
@@ -2779,10 +2907,19 @@
*/
public Schema toSchema()
{
- validate();
- final Schema builtSchema = schema;
+ final Schema schema = new Schema(schemaName, allowMalformedNamesAndOptions,
+ allowNonStandardTelephoneNumbers, allowZeroLengthDirectoryStrings,
+ numericOID2Syntaxes, numericOID2MatchingRules,
+ numericOID2MatchingRuleUses, numericOID2AttributeTypes,
+ numericOID2ObjectClasses, numericOID2NameForms,
+ numericOID2ContentRules, id2StructureRules, name2MatchingRules,
+ name2MatchingRuleUses, name2AttributeTypes, name2ObjectClasses,
+ name2NameForms, name2ContentRules, name2StructureRules,
+ objectClass2NameForms, nameForm2StructureRules, warnings);
+
+ validate(schema);
initBuilder(null);
- return builtSchema;
+ return schema;
}
@@ -2881,8 +3018,8 @@
if (!overwrite)
{
final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_DIT_STRUCTURE_RULE_ID
- .get(rule.getNameOrRuleID(), rule.getRuleID(), conflictingRule
- .getNameOrRuleID());
+ .get(rule.getNameOrRuleID(), rule.getRuleID(),
+ conflictingRule.getNameOrRuleID());
throw new ConflictingSchemaElementException(message);
}
removeDITStructureRule(conflictingRule);
@@ -2963,8 +3100,8 @@
if (!overwrite)
{
final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_MATCHING_RULE_USE
- .get(use.getNameOrOID(), use.getMatchingRuleOID(), conflictingUse
- .getNameOrOID());
+ .get(use.getNameOrOID(), use.getMatchingRuleOID(),
+ conflictingUse.getNameOrOID());
throw new ConflictingSchemaElementException(message);
}
removeMatchingRuleUse(conflictingUse);
@@ -3004,8 +3141,8 @@
if (!overwrite)
{
final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_NAME_FORM_OID
- .get(form.getNameOrOID(), form.getOID(), conflictingForm
- .getNameOrOID());
+ .get(form.getNameOrOID(), form.getOID(),
+ conflictingForm.getNameOrOID());
throw new ConflictingSchemaElementException(message);
}
removeNameForm(conflictingForm);
@@ -3097,6 +3234,15 @@
private void initBuilder(String schemaName)
{
+ if (schemaName == null)
+ {
+ schemaName = String.format("Schema#%d", nextSchemaID.getAndIncrement());
+ }
+ this.schemaName = schemaName;
+
+ allowMalformedNamesAndOptions = true;
+ allowNonStandardTelephoneNumbers = true;
+ allowZeroLengthDirectoryStrings = false;
numericOID2Syntaxes = new LinkedHashMap<String, Syntax>();
numericOID2MatchingRules = new LinkedHashMap<String, MatchingRule>();
numericOID2MatchingRuleUses = new LinkedHashMap<String, MatchingRuleUse>();
@@ -3116,22 +3262,7 @@
objectClass2NameForms = new HashMap<String, List<NameForm>>();
nameForm2StructureRules = new HashMap<String, List<DITStructureRule>>();
- options = SchemaCompatOptions.defaultOptions();
warnings = new LinkedList<LocalizableMessage>();
-
- if (schemaName == null)
- {
- schemaName = String.format("Schema#%d", nextSchemaID.getAndIncrement());
- }
-
- schema = new Schema(schemaName, numericOID2Syntaxes,
- numericOID2MatchingRules, numericOID2MatchingRuleUses,
- numericOID2AttributeTypes, numericOID2ObjectClasses,
- numericOID2NameForms, numericOID2ContentRules, id2StructureRules,
- name2MatchingRules, name2MatchingRuleUses, name2AttributeTypes,
- name2ObjectClasses, name2NameForms, name2ContentRules,
- name2StructureRules, objectClass2NameForms, nameForm2StructureRules,
- options, warnings);
}
@@ -3306,7 +3437,7 @@
- private void validate()
+ private void validate(final Schema schema)
{
// Verify all references in all elements
for (final Syntax syntax : numericOID2Syntaxes.values().toArray(
@@ -3319,8 +3450,8 @@
catch (final SchemaException e)
{
removeSyntax(syntax);
- warnings.add(ERR_SYNTAX_VALIDATION_FAIL.get(
- syntax.toString(), e.getMessageObject()));
+ warnings.add(ERR_SYNTAX_VALIDATION_FAIL.get(syntax.toString(),
+ e.getMessageObject()));
}
}
@@ -3349,8 +3480,8 @@
catch (final SchemaException e)
{
removeAttributeType(attribute);
- warnings.add(ERR_ATTR_TYPE_VALIDATION_FAIL.get(attribute.toString(), e
- .getMessageObject()));
+ warnings.add(ERR_ATTR_TYPE_VALIDATION_FAIL.get(attribute.toString(),
+ e.getMessageObject()));
}
}
@@ -3413,8 +3544,8 @@
catch (final SchemaException e)
{
removeNameForm(form);
- warnings.add(ERR_NAMEFORM_VALIDATION_FAIL.get(form.toString(), e
- .getMessageObject()));
+ warnings.add(ERR_NAMEFORM_VALIDATION_FAIL.get(form.toString(),
+ e.getMessageObject()));
}
}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptions.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptions.java
deleted file mode 100644
index 1d30f9b..0000000
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptions.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * 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 2009 Sun Microsystems, Inc.
- * Portions copyright 2011 ForgeRock AS
- */
-
-package org.forgerock.opendj.ldap.schema;
-
-
-
-/**
- * This class provides various schema compatibility options which may be used to
- * facilitate interoperability with legacy LDAP applications.
- */
-public final class SchemaCompatOptions
-{
- /**
- * Creates a copy of the provided schema compatibility options.
- *
- * @param options
- * The options to be copied.
- * @return The copy of the provided schema compatibility options.
- */
- public static SchemaCompatOptions copyOf(
- final SchemaCompatOptions options)
- {
- return defaultOptions().assign(options);
- }
-
-
-
- /**
- * Creates a new set of schema compatibility options with default settings.
- *
- * @return The new schema compatibility options.
- */
- public static SchemaCompatOptions defaultOptions()
- {
- return new SchemaCompatOptions();
- }
-
-
-
- private boolean allowNonStandardTelephoneNumbers = true;
-
- private boolean allowZeroLengthDirectoryStrings = false;
-
- private boolean allowMalformedNamesAndOptions = true;
-
-
-
- // Prevent direct instantiation.
- private SchemaCompatOptions()
- {
- // Nothing to do.
- }
-
-
-
- /**
- * Returns {@code true} if the schema should allow certain illegal characters
- * in OIDs and attribute options. When this compatibility option is set to
- * {@code true} the following illegal characters will be permitted in addition
- * to those permitted in section 1.4 of RFC 4512:
- *
- * <pre>
- * USCORE = %x5F ; underscore ("_")
- * DOT = %x2E ; period (".")
- * </pre>
- *
- * By default this compatibility option is set to {@code true} because these
- * characters are often used for naming purposes (such as collation rules).
- *
- * @return {@code true} if the schema should allow certain illegal characters
- * in OIDs and attribute options.
- * @see <a href="http://tools.ietf.org/html/rfc4512">RFC 4512 - Lightweight
- * Directory Access Protocol (LDAP): Directory Information Models </a>
- */
- public boolean allowMalformedNamesAndOptions()
- {
- return allowMalformedNamesAndOptions;
- }
-
-
-
- /**
- * Specifies whether or not the schema should allow certain illegal characters
- * in OIDs and attribute options. When this compatibility option is set to
- * {@code true} the following illegal characters will be permitted in addition
- * to those permitted in section 1.4 of RFC 4512:
- *
- * <pre>
- * USCORE = %x5F ; underscore ("_")
- * DOT = %x2E ; period (".")
- * </pre>
- *
- * By default this compatibility option is set to {@code true} because these
- * characters are often used for naming purposes (such as collation rules).
- *
- * @param allowMalformedNamesAndOptions
- * {@code true} if the schema should allow certain illegal characters
- * in OIDs and attribute options.
- * @return A reference to this {@code SchemaCompatOptions}.
- * @see <a href="http://tools.ietf.org/html/rfc4512">RFC 4512 - Lightweight
- * Directory Access Protocol (LDAP): Directory Information Models </a>
- */
- public SchemaCompatOptions allowMalformedNamesAndOptions(
- final boolean allowMalformedNamesAndOptions)
- {
- this.allowMalformedNamesAndOptions = allowMalformedNamesAndOptions;
- return this;
- }
-
-
-
- /**
- * Returns {@code true} if the Telephone Number syntax should allow values
- * which do not conform to the E.123 international telephone number format.
- * <p>
- * By default this compatibility option is set to {@code true}.
- *
- * @return {@code true} if the Telephone Number syntax should allow values
- * which do not conform to the E.123 international telephone number
- * format.
- */
- public boolean allowNonStandardTelephoneNumbers()
- {
- return allowNonStandardTelephoneNumbers;
- }
-
-
-
- /**
- * Specifies whether or not the Telephone Number syntax should allow values
- * which do not conform to the E.123 international telephone number format.
- * <p>
- * By default this compatibility option is set to {@code true}.
- *
- * @param allowNonStandardTelephoneNumbers
- * {@code true} if the Telephone Number syntax should allow values
- * which do not conform to the E.123 international telephone number
- * format.
- * @return A reference to this {@code SchemaCompatOptions}.
- */
- public SchemaCompatOptions allowNonStandardTelephoneNumbers(
- final boolean allowNonStandardTelephoneNumbers)
- {
- this.allowNonStandardTelephoneNumbers = allowNonStandardTelephoneNumbers;
- return this;
- }
-
-
-
- /**
- * Returns {@code true} if zero-length values will be allowed by the Directory
- * String syntax. This is technically forbidden by the LDAP specification, but
- * it was allowed in earlier versions of the server, and the discussion of the
- * directory string syntax in RFC 2252 does not explicitly state that they are
- * not allowed.
- * <p>
- * By default this compatibility option is set to {@code false}.
- *
- * @return {@code true} if zero-length values will be allowed by the Directory
- * String syntax, or {@code false} if not.
- */
- public boolean allowZeroLengthDirectoryStrings()
- {
- return allowZeroLengthDirectoryStrings;
- }
-
-
-
- /**
- * Specifies whether or not zero-length values will be allowed by the
- * Directory String syntax. This is technically forbidden by the LDAP
- * specification, but it was allowed in earlier versions of the server, and
- * the discussion of the directory string syntax in RFC 2252 does not
- * explicitly state that they are not allowed.
- * <p>
- * By default this compatibility option is set to {@code false}.
- *
- * @param allowZeroLengthDirectoryStrings
- * {@code true} if zero-length values will be allowed by the
- * Directory String syntax, or {@code false} if not.
- * @return A reference to this {@code SchemaCompatOptions}.
- */
- public SchemaCompatOptions allowZeroLengthDirectoryStrings(
- final boolean allowZeroLengthDirectoryStrings)
- {
- this.allowZeroLengthDirectoryStrings = allowZeroLengthDirectoryStrings;
- return this;
- }
-
-
-
- // Assigns the provided options to this set of options.
- SchemaCompatOptions assign(final SchemaCompatOptions options)
- {
- this.allowMalformedNamesAndOptions = options.allowMalformedNamesAndOptions;
- this.allowNonStandardTelephoneNumbers =options.allowNonStandardTelephoneNumbers;
- this.allowZeroLengthDirectoryStrings = options.allowZeroLengthDirectoryStrings;
- return this;
- }
-
-}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaValidationPolicy.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaValidationPolicy.java
new file mode 100644
index 0000000..1c52df7
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaValidationPolicy.java
@@ -0,0 +1,505 @@
+/*
+ * 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.ldap.schema;
+
+
+
+import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.Entry;
+import org.forgerock.opendj.ldap.ErrorResultException;
+
+
+
+/**
+ * This class provides various schema validation policy options for controlling
+ * how entries should be validated against the directory schema.
+ */
+public final class SchemaValidationPolicy
+{
+ /**
+ * A call-back which will be called during DIT structure rule schema
+ * validation in order to retrieve the parent of the entry being validated.
+ */
+ public interface EntryResolver
+ {
+ /**
+ * Returns the named entry in order to enforce DIT structure rules.
+ *
+ * @param dn
+ * The name of the entry to be returned.
+ * @return The named entry.
+ * @throws ErrorResultException
+ * If the entry could not be retrieved.
+ */
+ Entry getEntry(DN dn) throws ErrorResultException;
+ }
+
+
+
+ /**
+ * The schema validation policy.
+ */
+ public static enum Policy
+ {
+ /**
+ * Schema validation will not be performed.
+ */
+ IGNORE,
+
+ /**
+ * Schema validation will be performed, but failures will not cause the
+ * overall validation to fail. Error messages will be returned.
+ */
+ WARN,
+
+ /**
+ * Schema validation will be performed and failures will cause the overall
+ * validation to fail. Error messages will be returned.
+ */
+ REJECT;
+
+ private Policy()
+ {
+ // Nothing to do.
+ }
+
+
+
+ /**
+ * Returns {@code true} if this policy is {@code IGNORE}.
+ *
+ * @return {@code true} if this policy is {@code IGNORE}.
+ */
+ public boolean isIgnore()
+ {
+ return this == IGNORE;
+ }
+
+
+
+ /**
+ * Returns {@code true} if this policy is {@code REJECT}.
+ *
+ * @return {@code true} if this policy is {@code REJECT}.
+ */
+ public boolean isReject()
+ {
+ return this == REJECT;
+ }
+
+
+
+ /**
+ * Returns {@code true} if this policy is {@code WARN}.
+ *
+ * @return {@code true} if this policy is {@code WARN}.
+ */
+ public boolean isWarn()
+ {
+ return this == WARN;
+ }
+
+
+
+ /**
+ * Returns {@code true} if this policy is {@code WARN} or {@code REJECT}.
+ *
+ * @return {@code true} if this policy is {@code WARN} or {@code REJECT}.
+ */
+ public boolean needsChecking()
+ {
+ return this != IGNORE;
+ }
+ }
+
+
+
+ /**
+ * Creates a copy of the provided schema validation policy.
+ *
+ * @param policy
+ * The policy to be copied.
+ * @return The copy of the provided schema validation policy.
+ */
+ public static SchemaValidationPolicy copyOf(
+ final SchemaValidationPolicy policy)
+ {
+ return defaultPolicy().assign(policy);
+ }
+
+
+
+ /**
+ * Creates a new schema validation policy with default settings. More
+ * specifically:
+ * <ul>
+ * <li>Entries not having a single structural object class will be rejected
+ * <li>Entries having attributes which are not permitted by its object classes
+ * or DIT content rule (if present) will be rejected
+ * <li>Entries not conforming to name forms will be rejected
+ * <li>DIT structure rules will not be ignored
+ * </ul>
+ *
+ * @return The new schema validation policy.
+ */
+ public static SchemaValidationPolicy defaultPolicy()
+ {
+ return new SchemaValidationPolicy();
+ }
+
+
+
+ /**
+ * Creates a new schema validation policy which will not perform any schema
+ * validation.
+ *
+ * @return The new schema validation policy.
+ */
+ public static SchemaValidationPolicy ignoreAll()
+ {
+ return new SchemaValidationPolicy()
+ .checkAttributesAndObjectClasses(Policy.IGNORE)
+ .checkAttributeValues(Policy.IGNORE)
+ .checkDITContentRules(Policy.IGNORE)
+ .checkNameForms(Policy.IGNORE)
+ .requireSingleStructuralObjectClass(Policy.IGNORE);
+ }
+
+
+
+ private Policy checkNameForms = Policy.REJECT;
+
+ private Policy checkDITStructureRules = Policy.IGNORE;
+
+ private Policy checkDITContentRules = Policy.REJECT;
+
+ private Policy requireSingleStructuralObjectClass = Policy.REJECT;
+
+ private Policy checkAttributesAndObjectClasses = Policy.REJECT;
+
+ private Policy checkAttributeValues = Policy.REJECT;
+
+ private EntryResolver checkDITStructureRulesEntryResolver = null;
+
+
+
+ // Prevent direct instantiation.
+ private SchemaValidationPolicy()
+ {
+ // Nothing to do.
+ }
+
+
+
+ /**
+ * Returns the policy for verifying that the user attributes in an entry
+ * conform to its object classes. More specifically, an entry must contain all
+ * required user attributes, and must not contain any user attributes which
+ * are not declared as required or optional by its object classes.
+ * <p>
+ * By default entries which have missing or additional user attributes will be
+ * rejected.
+ *
+ * @return The policy for verifying that the user attributes in an entry
+ * conform to its object classes.
+ */
+ public Policy checkAttributesAndObjectClasses()
+ {
+ return checkAttributesAndObjectClasses;
+ }
+
+
+
+ /**
+ * Specifies the policy for verifying that the user attributes in an entry
+ * conform to its object classes. More specifically, an entry must contain all
+ * required user attributes, and must not contain any user attributes which
+ * are not declared as required or optional by its object classes.
+ * <p>
+ * By default entries which have missing or additional user attributes will be
+ * rejected.
+ *
+ * @param policy
+ * The policy for verifying that the user attributes in an entry
+ * conform to its object classes.
+ * @return A reference to this {@code SchemaValidationPolicy}.
+ */
+ public SchemaValidationPolicy checkAttributesAndObjectClasses(
+ final Policy policy)
+ {
+ this.checkAttributesAndObjectClasses = policy;
+ return this;
+ }
+
+
+
+ /**
+ * Returns the policy for verifying that the user attributes in an entry
+ * conform to their associated attribute type descriptions. This may include:
+ * <ul>
+ * <li>checking that there is at least one value
+ * <li>checking that single-valued attributes contain only a single value
+ * <li>checking that there are no duplicate values according to the
+ * attribute's default equality matching rule
+ * <li>checking that attributes which require BER encoding specify the
+ * {@code ;binary} attribute option
+ * <li>checking that the values are valid according to the attribute's syntax.
+ * </ul>
+ * Schema validation implementations specify exactly which of the above checks
+ * will be performed.
+ * <p>
+ * By default entries which have invalid attribute values will be rejected.
+ *
+ * @return The policy for verifying that the user attributes in an entry
+ * conform to their associated attribute type descriptions.
+ */
+ public Policy checkAttributeValues()
+ {
+ return checkAttributeValues;
+ }
+
+
+
+ /**
+ * Specifies the policy for verifying that the user attributes in an entry
+ * conform to their associated attribute type descriptions. This may include:
+ * <ul>
+ * <li>checking that there is at least one value
+ * <li>checking that single-valued attributes contain only a single value
+ * <li>checking that there are no duplicate values according to the
+ * attribute's default equality matching rule
+ * <li>checking that attributes which require BER encoding specify the
+ * {@code ;binary} attribute option
+ * <li>checking that the values are valid according to the attribute's syntax.
+ * </ul>
+ * Schema validation implementations specify exactly which of the above checks
+ * will be performed.
+ * <p>
+ * By default entries which have invalid attribute values will be rejected.
+ *
+ * @param policy
+ * The policy for verifying that the user attributes in an entry
+ * conform to their associated attribute type descriptions.
+ * @return A reference to this {@code SchemaValidationPolicy}.
+ */
+ public SchemaValidationPolicy checkAttributeValues(final Policy policy)
+ {
+ this.checkAttributeValues = policy;
+ return this;
+ }
+
+
+
+ /**
+ * Returns the policy for validating entries against content rules defined in
+ * the schema.
+ * <p>
+ * By default content rules will be ignored during validation.
+ *
+ * @return The policy for validating entries against content rules defined in
+ * the schema.
+ */
+ public Policy checkDITContentRules()
+ {
+ return checkDITContentRules;
+ }
+
+
+
+ /**
+ * Specifies the policy for validating entries against content rules defined
+ * in the schema.
+ * <p>
+ * By default content rules will be ignored during validation.
+ *
+ * @param policy
+ * The policy for validating entries against content rules defined in
+ * the schema.
+ * @return A reference to this {@code SchemaValidationPolicy}.
+ */
+ public SchemaValidationPolicy checkDITContentRules(final Policy policy)
+ {
+ this.checkDITContentRules = policy;
+ return this;
+ }
+
+
+
+ /**
+ * Returns the policy for validating entries against structure rules defined
+ * in the schema.
+ * <p>
+ * By default structure rules will be ignored during validation.
+ *
+ * @return The policy for validating entries against structure rules defined
+ * in the schema.
+ */
+ public Policy checkDITStructureRules()
+ {
+ return checkDITStructureRules;
+ }
+
+
+
+ /**
+ * Specifies the policy for validating entries against structure rules defined
+ * in the schema.
+ * <p>
+ * By default structure rules will be ignored during validation.
+ *
+ * @param policy
+ * The policy for validating entries against structure rules defined
+ * in the schema.
+ * @param resolver
+ * The parent entry resolver which should be used for retrieving the
+ * parent entry during DIT structure rule validation.
+ * @return A reference to this {@code SchemaValidationPolicy}.
+ * @throws IllegalArgumentException
+ * If {@code resolver} was {@code null} and
+ * {@code checkDITStructureRules} is either {@code WARN} or
+ * {@code REJECT}.
+ */
+ public SchemaValidationPolicy checkDITStructureRules(final Policy policy,
+ final EntryResolver resolver) throws IllegalArgumentException
+ {
+ if (checkDITStructureRules.needsChecking() && resolver == null)
+ {
+ throw new IllegalArgumentException(
+ "Validation of structure rules enabled by resolver was null");
+ }
+ this.checkDITStructureRules = policy;
+ this.checkDITStructureRulesEntryResolver = resolver;
+ return this;
+ }
+
+
+
+ /**
+ * Returns parent entry resolver which should be used for retrieving the
+ * parent entry during DIT structure rule validation.
+ * <p>
+ * By default no resolver is defined because structure rules will be ignored
+ * during validation.
+ *
+ * @return The parent entry resolver which should be used for retrieving the
+ * parent entry during DIT structure rule validation.
+ */
+ public EntryResolver checkDITStructureRulesEntryResolver()
+ {
+ return checkDITStructureRulesEntryResolver;
+ }
+
+
+
+ /**
+ * Returns the policy for validating entries against name forms defined in the
+ * schema.
+ * <p>
+ * By default name forms will be ignored during validation.
+ *
+ * @return The policy for validating entries against name forms defined in the
+ * schema.
+ */
+ public Policy checkNameForms()
+ {
+ return checkNameForms;
+ }
+
+
+
+ /**
+ * Specifies the policy for validating entries against name forms defined in
+ * the schema.
+ * <p>
+ * By default name forms will be ignored during validation.
+ *
+ * @param policy
+ * The policy for validating entries against name forms defined in
+ * the schema.
+ * @return A reference to this {@code SchemaValidationPolicy}.
+ */
+ public SchemaValidationPolicy checkNameForms(final Policy policy)
+ {
+ this.checkNameForms = policy;
+ return this;
+ }
+
+
+
+ /**
+ * Returns the policy for verifying that entries have only a single structural
+ * object class.
+ * <p>
+ * By default entries which do not have a structural object class or which
+ * have more than one structural object class will be rejected.
+ *
+ * @return The policy for checking that entries have one and only one
+ * structural object class.
+ */
+ public Policy requireSingleStructuralObjectClass()
+ {
+ return requireSingleStructuralObjectClass;
+ }
+
+
+
+ /**
+ * Specifies the policy for verifying that entries have only a single
+ * structural object class.
+ * <p>
+ * By default entries which do not have a structural object class or which
+ * have more than one structural object class will be rejected.
+ *
+ * @param policy
+ * The policy for checking that entries have one and only one
+ * structural object class.
+ * @return A reference to this {@code SchemaValidationPolicy}.
+ */
+ public SchemaValidationPolicy requireSingleStructuralObjectClass(
+ final Policy policy)
+ {
+ this.requireSingleStructuralObjectClass = policy;
+ return this;
+ }
+
+
+
+ // Assigns the provided options to this set of options.
+ SchemaValidationPolicy assign(final SchemaValidationPolicy policy)
+ {
+ this.checkAttributeValues = policy.checkAttributeValues;
+ this.checkNameForms = policy.checkNameForms;
+ this.checkAttributesAndObjectClasses = policy.checkAttributesAndObjectClasses;
+ this.checkDITContentRules = policy.checkDITContentRules;
+ this.checkDITStructureRules = policy.checkDITStructureRules;
+ this.checkDITStructureRulesEntryResolver = policy.checkDITStructureRulesEntryResolver;
+ this.requireSingleStructuralObjectClass = policy.requireSingleStructuralObjectClass;
+ return this;
+ }
+
+}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/TelephoneNumberSyntaxImpl.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/TelephoneNumberSyntaxImpl.java
index 9543f95..99c2dbf 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/TelephoneNumberSyntaxImpl.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/TelephoneNumberSyntaxImpl.java
@@ -113,7 +113,7 @@
final int length = valueStr.length();
- if (!schema.getSchemaCompatOptions().allowNonStandardTelephoneNumbers())
+ if (!schema.allowNonStandardTelephoneNumbers())
{
// If the value does not start with a plus sign, then that's not
// acceptable.
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java
index 4230d08..7b8b0e7 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java
@@ -47,6 +47,8 @@
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.*;
import org.forgerock.opendj.ldap.schema.Schema;
+import org.forgerock.opendj.ldap.schema.SchemaValidationPolicy;
+import org.forgerock.opendj.ldap.schema.Syntax;
import org.forgerock.opendj.ldap.schema.UnknownSchemaElementException;
import com.forgerock.opendj.util.Base64;
@@ -232,7 +234,7 @@
Schema schema = Schema.getDefaultSchema().asNonStrictSchema();
- boolean validateSchema = false;
+ SchemaValidationPolicy schemaValidationPolicy = SchemaValidationPolicy.ignoreAll();
private final LDIFReaderImpl impl;
@@ -589,7 +591,7 @@
- final void readLDIFRecordAttributeValue(final LDIFRecord record,
+ final boolean readLDIFRecordAttributeValue(final LDIFRecord record,
final String ldifLine, final Entry entry,
final List<LocalizableMessage> schemaErrors) throws DecodeException
{
@@ -606,14 +608,19 @@
{
final LocalizableMessage message = ERR_LDIF_UNKNOWN_ATTRIBUTE_TYPE.get(
record.lineNumber, entry.getName().toString(), attrDescr);
- if (validateSchema)
+ switch (schemaValidationPolicy.checkAttributesAndObjectClasses())
{
+ case REJECT:
schemaErrors.add(message);
- return;
- }
- else
- {
- throw DecodeException.error(message);
+ return false;
+ case WARN:
+ schemaErrors.add(message);
+ return true;
+ default: // Ignore
+ // This should not happen: we should be using a non-strict schema for
+ // this policy.
+ throw new IllegalStateException("Schema is not consistent with policy",
+ e);
}
}
catch (final LocalizedIllegalArgumentException e)
@@ -632,19 +639,29 @@
// known to violate the schema.
if (isAttributeExcluded(attributeDescription))
{
- return;
+ return true;
}
+ final Syntax syntax = attributeDescription.getAttributeType().getSyntax();
+
// Ensure that the binary option is present if required.
- if (!attributeDescription.getAttributeType().getSyntax()
- .isBEREncodingRequired())
+ if (!syntax.isBEREncodingRequired())
{
- if (validateSchema && attributeDescription.containsOption("binary"))
+ if (schemaValidationPolicy.checkAttributeValues().needsChecking()
+ && attributeDescription.containsOption("binary"))
{
final LocalizableMessage message = ERR_LDIF_UNEXPECTED_BINARY_OPTION
.get(record.lineNumber, entry.getName().toString(), attrDescr);
schemaErrors.add(message);
- return;
+ if (schemaValidationPolicy.checkAttributeValues().isReject())
+ {
+ return false;
+ }
+ else
+ {
+ // Skip to next attribute value.
+ return true;
+ }
}
}
else
@@ -652,64 +669,57 @@
attributeDescription = attributeDescription.withOption("binary");
}
+ final boolean checkAttributeValues = schemaValidationPolicy
+ .checkAttributeValues().needsChecking();
+ if (checkAttributeValues)
+ {
+ LocalizableMessageBuilder builder = new LocalizableMessageBuilder();
+ if (!syntax.valueIsAcceptable(value, builder))
+ {
+ schemaErrors.add(builder.toMessage());
+ if (schemaValidationPolicy.checkAttributeValues().isReject())
+ {
+ return false;
+ }
+ }
+ }
+
Attribute attribute = entry.getAttribute(attributeDescription);
if (attribute == null)
{
- if (validateSchema)
- {
- final LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
- if (!attributeDescription.getAttributeType().getSyntax()
- .valueIsAcceptable(value, invalidReason))
- {
- final LocalizableMessage message = WARN_LDIF_MALFORMED_ATTRIBUTE_VALUE
- .get(record.lineNumber, entry.getName().toString(),
- value.toString(), attrDescr, invalidReason);
- schemaErrors.add(message);
- return;
- }
- }
-
attribute = new LinkedAttribute(attributeDescription, value);
entry.addAttribute(attribute);
}
- else
+ else if (checkAttributeValues)
{
- if (validateSchema)
+ if (!attribute.add(value))
{
- final LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
- if (!attributeDescription.getAttributeType().getSyntax()
- .valueIsAcceptable(value, invalidReason))
+ final LocalizableMessage message = WARN_LDIF_DUPLICATE_ATTRIBUTE_VALUE
+ .get(record.lineNumber, entry.getName().toString(), attrDescr,
+ value.toString());
+ schemaErrors.add(message);
+ if (schemaValidationPolicy.checkAttributeValues().isReject())
{
- 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) && validateSchema)
- {
- final LocalizableMessage message = WARN_LDIF_DUPLICATE_ATTRIBUTE_VALUE
- .get(record.lineNumber, entry.getName().toString(), attrDescr,
- value.toString());
- schemaErrors.add(message);
- return;
- }
-
- if (validateSchema
- && attributeDescription.getAttributeType().isSingleValue())
- {
- final LocalizableMessage message = ERR_LDIF_MULTI_VALUED_SINGLE_VALUED_ATTRIBUTE
- .get(record.lineNumber, entry.getName().toString(), attrDescr);
- schemaErrors.add(message);
- return;
+ return false;
}
}
- else
+ else if (attributeDescription.getAttributeType().isSingleValue())
{
- attribute.add(value);
+ final LocalizableMessage message = ERR_LDIF_MULTI_VALUED_SINGLE_VALUED_ATTRIBUTE
+ .get(record.lineNumber, entry.getName().toString(), attrDescr);
+ schemaErrors.add(message);
+ if (schemaValidationPolicy.checkAttributeValues().isReject())
+ {
+ return false;
+ }
}
}
+ else
+ {
+ attribute.add(value);
+ }
+
+ return true;
}
@@ -893,6 +903,15 @@
+ final void handleSchemaValidationWarning(final LDIFRecord record,
+ final List<LocalizableMessage> messages) throws DecodeException
+ {
+ rejectedRecordListener.handleSchemaValidationWarning(record.lineNumber,
+ record.ldifLines, messages);
+ }
+
+
+
final void handleSkippedRecord(final LDIFRecord record,
final LocalizableMessage message) throws DecodeException
{
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java
index df050fa..c8498ad 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java
@@ -38,12 +38,15 @@
import java.util.*;
import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.*;
import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
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.SchemaValidationPolicy;
+import org.forgerock.opendj.ldap.schema.Syntax;
import org.forgerock.opendj.ldap.schema.UnknownSchemaElementException;
import com.forgerock.opendj.util.Validator;
@@ -363,32 +366,34 @@
public LDIFChangeRecordReader setSchema(final Schema schema)
{
Validator.ensureNotNull(schema);
- this.schema = validateSchema ? schema.asStrictSchema() : schema
- .asNonStrictSchema();
+ this.schema = schemaValidationPolicy.checkAttributesAndObjectClasses()
+ .needsChecking() ? schema.asStrictSchema() : schema.asNonStrictSchema();
return this;
}
/**
- * Specifies whether or not schema validation should be performed for change
- * 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.
+ * Specifies the schema validation which should be used when reading LDIF
+ * change records. If attribute value validation is enabled then all checks
+ * will be performed.
* <p>
* Schema validation is disabled by default.
+ * <p>
+ * <b>NOTE:</b> this method copies the provided policy so changes made to it
+ * after this method has been called will have no effect.
*
- * @param validateSchema
- * {@code true} if schema validation should be performed, or
- * {@code false} otherwise.
+ * @param policy
+ * The schema validation which should be used when reading LDIF
+ * change records.
* @return A reference to this {@code LDIFChangeRecordReader}.
*/
- public LDIFChangeRecordReader setValidateSchema(final boolean validateSchema)
+ public LDIFChangeRecordReader setSchemaValidationPolicy(
+ final SchemaValidationPolicy policy)
{
- this.validateSchema = validateSchema;
- this.schema = validateSchema ? schema.asStrictSchema() : schema
- .asNonStrictSchema();
+ this.schemaValidationPolicy = SchemaValidationPolicy.copyOf(policy);
+ this.schema = schemaValidationPolicy.checkAttributesAndObjectClasses()
+ .needsChecking() ? schema.asStrictSchema() : schema.asNonStrictSchema();
return this;
}
@@ -497,24 +502,42 @@
{
// Use an Entry for the AttributeSequence.
final Entry entry = new LinkedHashMapEntry(entryDN);
+ boolean schemaValidationFailure = false;
final List<LocalizableMessage> schemaErrors = new LinkedList<LocalizableMessage>();
if (lastLDIFLine != null)
{
// This line was read when looking for the change type.
- readLDIFRecordAttributeValue(record, lastLDIFLine, entry, schemaErrors);
+ if (!readLDIFRecordAttributeValue(record, lastLDIFLine, entry,
+ schemaErrors))
+ {
+ schemaValidationFailure = true;
+ }
}
while (record.iterator.hasNext())
{
final String ldifLine = record.iterator.next();
- readLDIFRecordAttributeValue(record, ldifLine, entry, schemaErrors);
+ if (!readLDIFRecordAttributeValue(record, ldifLine, entry, schemaErrors))
+ {
+ schemaValidationFailure = true;
+ }
+ }
+
+ if (!schema.validateEntry(entry, schemaValidationPolicy, schemaErrors))
+ {
+ schemaValidationFailure = true;
+ }
+
+ if (schemaValidationFailure)
+ {
+ handleSchemaValidationFailure(record, schemaErrors);
+ return null;
}
if (!schemaErrors.isEmpty())
{
- handleSchemaValidationFailure(record, schemaErrors);
- return null;
+ handleSchemaValidationWarning(record, schemaErrors);
}
return Requests.newAddRequest(entry);
@@ -541,9 +564,9 @@
final LDIFRecord record) throws DecodeException
{
final ModifyRequest modifyRequest = Requests.newModifyRequest(entryDN);
-
final KeyValuePair pair = new KeyValuePair();
final List<ByteString> attributeValues = new ArrayList<ByteString>();
+ boolean schemaValidationFailure = false;
final List<LocalizableMessage> schemaErrors = new LinkedList<LocalizableMessage>();
while (record.iterator.hasNext())
@@ -591,14 +614,20 @@
{
final LocalizableMessage message = ERR_LDIF_UNKNOWN_ATTRIBUTE_TYPE.get(
record.lineNumber, entryDN.toString(), pair.value);
- if (validateSchema)
+ switch (schemaValidationPolicy.checkAttributesAndObjectClasses())
{
+ case REJECT:
+ schemaValidationFailure = true;
schemaErrors.add(message);
continue;
- }
- else
- {
- throw DecodeException.error(message);
+ case WARN:
+ schemaErrors.add(message);
+ continue;
+ default: //Ignore
+ // This should not happen: we should be using a non-strict schema for
+ // this policy.
+ throw new IllegalStateException(
+ "Schema is not consistent with policy", e);
}
}
catch (final LocalizedIllegalArgumentException e)
@@ -616,14 +645,20 @@
continue;
}
+ final Syntax syntax = attributeDescription.getAttributeType().getSyntax();
+
// Ensure that the binary option is present if required.
- if (!attributeDescription.getAttributeType().getSyntax()
- .isBEREncodingRequired())
+ if (!syntax.isBEREncodingRequired())
{
- if (validateSchema && attributeDescription.containsOption("binary"))
+ if (schemaValidationPolicy.checkAttributeValues().needsChecking()
+ && attributeDescription.containsOption("binary"))
{
final LocalizableMessage message = ERR_LDIF_UNEXPECTED_BINARY_OPTION
.get(record.lineNumber, entryDN.toString(), pair.value);
+ if (schemaValidationPolicy.checkAttributeValues().isReject())
+ {
+ schemaValidationFailure = true;
+ }
schemaErrors.add(message);
continue;
}
@@ -657,7 +692,7 @@
catch (final LocalizedIllegalArgumentException e)
{
// No need to catch schema exception here because it implies that the
- // attribute name is wrong.
+ // attribute name is wrong and the record is malformed.
final LocalizableMessage message = ERR_LDIF_MALFORMED_ATTRIBUTE_NAME
.get(record.lineNumber, entryDN.toString(), attrDescr);
throw DecodeException.error(message);
@@ -672,6 +707,7 @@
if (!attributeDescription2.equals(attributeDescription))
{
+ // Malformed record.
final LocalizableMessage message = ERR_LDIF_ATTRIBUTE_NAME_MISMATCH
.get(record.lineNumber, entryDN.toString(),
attributeDescription2.toString(),
@@ -679,9 +715,26 @@
throw DecodeException.error(message);
}
- // Now parse the attribute value.
- attributeValues.add(parseSingleValue(record, ldifLine, entryDN,
- colonPos, attrDescr));
+ // Parse the attribute value and check it if needed.
+ final ByteString value = parseSingleValue(record, ldifLine, entryDN,
+ colonPos, attrDescr);
+ if (schemaValidationPolicy.checkAttributeValues().needsChecking())
+ {
+ LocalizableMessageBuilder builder = new LocalizableMessageBuilder();
+ if (!syntax.valueIsAcceptable(value, builder))
+ {
+ // Just log a message, but don't skip the value since this could
+ // change the semantics of the modification (e.g. if all values in a
+ // delete are skipped then this implies that the whole attribute
+ // should be removed).
+ if (schemaValidationPolicy.checkAttributeValues().isReject())
+ {
+ schemaValidationFailure = true;
+ }
+ schemaErrors.add(builder.toMessage());
+ }
+ }
+ attributeValues.add(value);
}
final Modification change = new Modification(modType,
@@ -689,12 +742,17 @@
modifyRequest.addModification(change);
}
- if (!schemaErrors.isEmpty())
+ if (schemaValidationFailure)
{
handleSchemaValidationFailure(record, schemaErrors);
return null;
}
+ if (!schemaErrors.isEmpty())
+ {
+ handleSchemaValidationWarning(record, schemaErrors);
+ }
+
return modifyRequest;
}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryReader.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryReader.java
index 5f13925..5e15fb0 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryReader.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryReader.java
@@ -43,6 +43,7 @@
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.*;
import org.forgerock.opendj.ldap.schema.Schema;
+import org.forgerock.opendj.ldap.schema.SchemaValidationPolicy;
import com.forgerock.opendj.util.Validator;
@@ -393,32 +394,34 @@
public LDIFEntryReader setSchema(final Schema schema)
{
Validator.ensureNotNull(schema);
- this.schema = validateSchema ? schema.asStrictSchema() : schema
- .asNonStrictSchema();
+ this.schema = schemaValidationPolicy.checkAttributesAndObjectClasses()
+ .needsChecking() ? schema.asStrictSchema() : schema.asNonStrictSchema();
return this;
}
/**
- * Specifies whether or not schema validation should be performed for entries
- * 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.
+ * Specifies the schema validation which should be used when reading LDIF
+ * entry records. If attribute value validation is enabled then all checks
+ * will be performed.
* <p>
* Schema validation is disabled by default.
+ * <p>
+ * <b>NOTE:</b> this method copies the provided policy so changes made to it
+ * after this method has been called will have no effect.
*
- * @param validateSchema
- * {@code true} if schema validation should be performed, or
- * {@code false} otherwise.
+ * @param policy
+ * The schema validation which should be used when reading LDIF entry
+ * records.
* @return A reference to this {@code LDIFEntryReader}.
*/
- public LDIFEntryReader setValidateSchema(final boolean validateSchema)
+ public LDIFEntryReader setSchemaValidationPolicy(
+ final SchemaValidationPolicy policy)
{
- this.validateSchema = validateSchema;
- this.schema = validateSchema ? schema.asStrictSchema() : schema
- .asNonStrictSchema();
+ this.schemaValidationPolicy = SchemaValidationPolicy.copyOf(policy);
+ this.schema = schemaValidationPolicy.checkAttributesAndObjectClasses()
+ .needsChecking() ? schema.asStrictSchema() : schema.asNonStrictSchema();
return this;
}
@@ -458,11 +461,16 @@
// Use an Entry for the AttributeSequence.
final Entry entry = new LinkedHashMapEntry(entryDN);
+ boolean schemaValidationFailure = false;
final List<LocalizableMessage> schemaErrors = new LinkedList<LocalizableMessage>();
while (record.iterator.hasNext())
{
final String ldifLine = record.iterator.next();
- readLDIFRecordAttributeValue(record, ldifLine, entry, schemaErrors);
+ if (!readLDIFRecordAttributeValue(record, ldifLine, entry,
+ schemaErrors))
+ {
+ schemaValidationFailure = true;
+ }
}
// Skip if the entry is excluded by any filters.
@@ -474,12 +482,22 @@
continue;
}
- if (!schemaErrors.isEmpty())
+ if (!schema.validateEntry(entry, schemaValidationPolicy, schemaErrors))
+ {
+ schemaValidationFailure = true;
+ }
+
+ if (schemaValidationFailure)
{
handleSchemaValidationFailure(record, schemaErrors);
continue;
}
+ if (!schemaErrors.isEmpty())
+ {
+ handleSchemaValidationWarning(record, schemaErrors);
+ }
+
nextEntry = entry;
}
catch (final DecodeException e)
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/RejectedRecordListener.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/RejectedRecordListener.java
index 79e167e..07517b7 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/RejectedRecordListener.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/RejectedRecordListener.java
@@ -78,6 +78,15 @@
{
// Ignore skipped records.
}
+
+
+
+ public void handleSchemaValidationWarning(long lineNumber,
+ List<String> ldifRecord, List<LocalizableMessage> reasons)
+ throws DecodeException
+ {
+ // Ignore schema validation warnings.
+ }
};
@@ -122,6 +131,25 @@
/**
+ * Invoked when a record was not rejected but contained one or more schema validation warnings.
+ *
+ * @param lineNumber
+ * The line number within the source location in which the
+ * record is located, if known, otherwise {@code -1}.
+ * @param ldifRecord
+ * An LDIF representation of the record which contained schema
+ * validation warnings.
+ * @param reasons
+ * The schema validation warnings.
+ * @throws DecodeException
+ * If processing should terminate.
+ */
+ void handleSchemaValidationWarning(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.
*
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 6c6c410..5a6cc2f 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
@@ -1328,4 +1328,47 @@
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"
-
+ERR_ENTRY_SCHEMA_MULTIPLE_STRUCTURAL_CLASSES=Entry "%s" violates the schema \
+ because it contains multiple conflicting structural object classes "%s" and \
+ "%s". Only a single structural object class is allowed in an entry
+ERR_ENTRY_SCHEMA_UNKNOWN_OBJECT_CLASS=Entry "%s" violates the schema \
+ because it contains an unrecognized object class "%s"
+ERR_ENTRY_SCHEMA_NO_STRUCTURAL_CLASS=Entry "%s" violates the schema because \
+ it does not include a structural object class. All entries must contain a \
+ structural object class
+ERR_ENTRY_SCHEMA_DCR_MISSING_MUST_ATTRIBUTES=Entry "%s" violates the schema \
+ because it does not contain attribute "%s" which is required by DIT content rule "%s"
+ERR_ENTRY_SCHEMA_DCR_PROHIBITED_ATTRIBUTES=Entry "%s" violates the schema \
+ because it contains attribute "%s" which is prohibited by DIT content rule "%s"
+ERR_ENTRY_SCHEMA_DCR_PROHIBITED_AUXILIARY_OC=Entry "%s" violates the schema because \
+ it contains auxiliary object class "%s" which is not allowed by DIT content rule "%s"
+ERR_ENTRY_SCHEMA_OC_MISSING_MUST_ATTRIBUTES=Entry "%s" violates the schema \
+ because it does not contain attribute "%s" which is required by object class "%s"
+ERR_ENTRY_SCHEMA_OC_DISALLOWED_ATTRIBUTES=Entry "%s" violates the schema \
+ because it contains attribute "%s" which is not allowed by any of the object \
+ classes in the entry
+ERR_ENTRY_SCHEMA_DCR_DISALLOWED_ATTRIBUTES=Entry "%s" violates the schema \
+ because it contains attribute "%s" which is not allowed by any of the object \
+ classes in the entry nor its DIT content rule "%s"
+ERR_ENTRY_SCHEMA_AT_EMPTY_ATTRIBUTE=Entry "%s" violates the schema \
+ because it contains an empty attribute "%s"
+ERR_ENTRY_SCHEMA_AT_SINGLE_VALUED_ATTRIBUTE=Entry "%s" violates the schema \
+ because it contains multiple values for the single-valued attribute "%s"
+ERR_ENTRY_SCHEMA_NF_MISSING_MUST_ATTRIBUTES=Entry "%s" violates the schema \
+ because its RDN does not contain the attribute "%s" which is required by \
+ name form "%s"
+ERR_ENTRY_SCHEMA_NF_DISALLOWED_ATTRIBUTES=Entry "%s" violates the schema \
+ because its RDN contains attribute "%s" which is not allowed by any the name \
+ form "%s"
+ERR_ENTRY_SCHEMA_DSR_NO_PARENT_OC=Entry "%s" could not be validated against \
+ any DIT structure rules because its parent entry does not appear to \
+ contain a valid structural object class
+ERR_ENTRY_SCHEMA_DSR_PARENT_NOT_FOUND=Entry "%s" could not be validated against \
+ any DIT structure rules because its parent entry could not be retrieved \
+ for the following reason: %s
+ERR_ENTRY_SCHEMA_DSR_ILLEGAL_OC=Entry "%s" violates the schema because DIT \
+ structure rule "%s" does not allow entries of type "%s" to be placed \
+ immediately below entries of type "%s"
+ERR_ENTRY_SCHEMA_DSR_MISSING_DSR=Entry "%s" violates the schema because \
+ there is no DIT structure rule that applies to the entry, but there is a DIT \
+ structure rule "%s" which applies to the parent entry
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptionsTest.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatTest.java
similarity index 94%
rename from opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptionsTest.java
rename to opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatTest.java
index 69d9e7d..17297c0 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptionsTest.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatTest.java
@@ -36,9 +36,9 @@
/**
- * Test SchemaCompatOptions.
+ * Tests schema compatibility options.
*/
-public class SchemaCompatOptionsTest extends SchemaTestCase
+public class SchemaCompatTest extends SchemaTestCase
{
/**
* Returns test data for valid attribute descriptions.
@@ -85,8 +85,7 @@
boolean allowIllegalCharacters)
{
SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema())
- .setSchemaCompatOptions(SchemaCompatOptions.defaultOptions()
- .allowMalformedNamesAndOptions(allowIllegalCharacters));
+ .allowMalformedNamesAndOptions(allowIllegalCharacters);
Schema schema = builder.toSchema().asNonStrictSchema();
AttributeDescription.valueOf(atd, schema);
}
@@ -134,8 +133,7 @@
boolean allowIllegalCharacters)
{
SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema())
- .setSchemaCompatOptions(SchemaCompatOptions.defaultOptions()
- .allowMalformedNamesAndOptions(allowIllegalCharacters));
+ .allowMalformedNamesAndOptions(allowIllegalCharacters);
Schema schema = builder.toSchema().asNonStrictSchema();
AttributeDescription.valueOf(atd, schema);
}
@@ -237,8 +235,7 @@
Syntax syntax, boolean allowIllegalCharacters)
{
SchemaBuilder builder = new SchemaBuilder()
- .setSchemaCompatOptions(SchemaCompatOptions.defaultOptions()
- .allowMalformedNamesAndOptions(allowIllegalCharacters));
+ .allowMalformedNamesAndOptions(allowIllegalCharacters);
if (syntax == ATD_SYNTAX)
{
@@ -340,8 +337,7 @@
Syntax syntax, boolean allowIllegalCharacters)
{
SchemaBuilder builder = new SchemaBuilder()
- .setSchemaCompatOptions(SchemaCompatOptions.defaultOptions()
- .allowMalformedNamesAndOptions(allowIllegalCharacters));
+ .allowMalformedNamesAndOptions(allowIllegalCharacters);
if (syntax == ATD_SYNTAX)
{
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFChangeRecordReaderTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFChangeRecordReaderTestCase.java
index cfbce2f..99a99c4 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFChangeRecordReaderTestCase.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFChangeRecordReaderTestCase.java
@@ -42,6 +42,8 @@
import org.forgerock.opendj.ldap.requests.DeleteRequest;
import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
+import org.forgerock.opendj.ldap.schema.SchemaValidationPolicy;
+import org.forgerock.opendj.ldap.schema.SchemaValidationPolicy.Policy;
import org.testng.annotations.Test;
@@ -457,7 +459,10 @@
"objectClass: domainComponent",
"dc: example",
"xxx: unknown attribute"
- ).setRejectedRecordListener(listener).setValidateSchema(true);
+ ).setRejectedRecordListener(listener)
+ .setSchemaValidationPolicy(
+ SchemaValidationPolicy.ignoreAll()
+ .checkAttributesAndObjectClasses(Policy.REJECT));
// @formatter:on
assertThat(reader.hasNext()).isFalse();
@@ -468,4 +473,53 @@
"objectClass: top", "objectClass: domainComponent", "dc: example",
"xxx: unknown attribute")), anyListOf(LocalizableMessage.class));
}
+
+
+
+ /**
+ * Tests reading a record which does not conform to the schema invokes the
+ * warning record listener.
+ *
+ * @throws Exception
+ * if an unexpected error occurred.
+ */
+ @Test
+ public void testRejectedRecordListenerWarnsBadSchemaRecord()
+ 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)
+ .setSchemaValidationPolicy(
+ SchemaValidationPolicy.ignoreAll()
+ .checkAttributesAndObjectClasses(Policy.WARN));
+ // @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);
+
+ verify(listener).handleSchemaValidationWarning(
+ eq(1L),
+ eq(Arrays.asList("dn: dc=example,dc=com", "changetype: add",
+ "objectClass: top", "objectClass: domainComponent", "dc: example",
+ "xxx: unknown attribute")), anyListOf(LocalizableMessage.class));
+ }
}
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFEntryReaderTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFEntryReaderTestCase.java
index fc636de..281850c 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFEntryReaderTestCase.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFEntryReaderTestCase.java
@@ -63,8 +63,6 @@
final LDIFEntryReader reader = new LDIFEntryReader(in);
try
{
- reader.setValidateSchema(false);
-
Assert.assertFalse(reader.hasNext());
Assert.assertFalse(reader.hasNext());
try
@@ -126,8 +124,6 @@
final LDIFEntryReader reader = new LDIFEntryReader(in);
try
{
- reader.setValidateSchema(false);
-
Assert.assertTrue(reader.hasNext());
final Entry entry = reader.readEntry();
assertNotNull(entry);
--
Gitblit v1.10.0