From c68958711a12eaf193fdb9d3770ec2bb6015b73c Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Thu, 07 Apr 2016 10:35:09 +0000
Subject: [PATCH] OPENDJSDK-96 Add schema option for tolerating attribute type definitions without a SUP or SYNTAX

---
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java         |    2 
 opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java |   20 ++++++++--
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java         |   24 +++++------
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaOptions.java         |   12 +++++
 opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/AttributeTypeTest.java     |   59 +++++++++++++++--------------
 5 files changed, 70 insertions(+), 47 deletions(-)

diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java
index 8cfa824..601cc52 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java
@@ -19,6 +19,7 @@
 import static java.util.Arrays.*;
 
 import static org.forgerock.opendj.ldap.schema.SchemaConstants.*;
+import static org.forgerock.opendj.ldap.schema.SchemaOptions.ALLOW_ATTRIBUTE_TYPES_WITH_NO_SUP_OR_SYNTAX;
 import static org.forgerock.opendj.ldap.schema.SchemaUtils.*;
 
 import static com.forgerock.opendj.ldap.CoreMessages.*;
@@ -97,7 +98,7 @@
          *             numeric OID.
          */
         public SchemaBuilder addToSchema() {
-            return getSchemaBuilder().addAttributeType(new AttributeType(this), false);
+            return addToSchema(false);
         }
 
         /**
@@ -107,19 +108,11 @@
          * @return The parent schema builder.
          */
         public SchemaBuilder addToSchemaOverwrite() {
-            return getSchemaBuilder().addAttributeType(new AttributeType(this), true);
+            return addToSchema(true);
         }
 
-        /**
-         * Adds this attribute type to the schema, overwriting any existing attribute type
-         * with the same numeric OID if the overwrite parameter is set to {@code true}.
-         *
-         * @param overwrite
-         *            {@code true} if any attribute type with the same OID should be overwritten.
-         * @return The parent schema builder.
-         */
         SchemaBuilder addToSchema(final boolean overwrite) {
-            return overwrite ? addToSchemaOverwrite() : addToSchema();
+            return getSchemaBuilder().addAttributeType(new AttributeType(this), overwrite);
         }
 
         /**
@@ -424,8 +417,11 @@
     private AttributeType(Builder builder) {
         super(builder);
         Reject.ifTrue(builder.oid == null || builder.oid.isEmpty(), "An OID must be specified.");
-        Reject.ifTrue(builder.superiorTypeOID == null && builder.syntaxOID == null,
-                "Superior type and/or Syntax must not be null");
+
+        if (builder.superiorTypeOID == null && builder.syntaxOID == null
+                && !builder.getSchemaBuilder().getOptions().get(ALLOW_ATTRIBUTE_TYPES_WITH_NO_SUP_OR_SYNTAX)) {
+            throw new IllegalArgumentException("Superior type and/or Syntax must not be null");
+        }
 
         oid = builder.oid;
         names = unmodifiableCopyOfList(builder.names);
@@ -989,6 +985,8 @@
         } else if (getSuperiorType() != null && getSuperiorType().getSyntax() != null) {
             // Try to inherit the syntax from the superior type if possible
             syntax = getSuperiorType().getSyntax();
+        } else {
+            syntax = schema.getDefaultSyntax();
         }
 
         if (equalityMatchingRuleOID != null) {
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
index 75de661..f5d7301 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -364,7 +364,7 @@
                 atBuilder.approximateMatchingRule(approxRules.get(0));
             }
 
-            if (superiorType == null && syntax == null) {
+            if (superiorType == null && syntax == null && !options.get(ALLOW_ATTRIBUTE_TYPES_WITH_NO_SUP_OR_SYNTAX)) {
                 throw new LocalizedIllegalArgumentException(
                     WARN_ATTR_SYNTAX_ATTRTYPE_MISSING_SYNTAX_AND_SUPERIOR.get(definition));
             }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaOptions.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaOptions.java
index 81710c9..4df915f 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaOptions.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaOptions.java
@@ -11,7 +11,7 @@
  * Header, with the fields enclosed by brackets [] replaced by your own identifying
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
- * Copyright 2014-2015 ForgeRock AS.
+ * Copyright 2014-2016 ForgeRock AS.
  */
 package org.forgerock.opendj.ldap.schema;
 
@@ -51,6 +51,16 @@
     public static final Option<Boolean> ALLOW_MALFORMED_NAMES_AND_OPTIONS = Option.withDefault(true);
 
     /**
+     * Specifies whether the schema should allow attribute type definitions that do not declare a superior attribute
+     * type or syntax. When this compatibility option is set to {@code true} invalid attribute type definitions will
+     * use the default syntax specifed by the {@link #DEFAULT_SYNTAX_OID} option.
+     * <p>
+     * By default this compatibility option is set to {@code true} in order to remain compatible with previous
+     * versions of OpenDJ.
+     */
+    public static final Option<Boolean> ALLOW_ATTRIBUTE_TYPES_WITH_NO_SUP_OR_SYNTAX = Option.withDefault(true);
+
+    /**
      * Specifies whether the JPEG Photo syntax should allow values which
      * do not conform to the JFIF or Exif specifications.
      * <p>
diff --git a/opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/AttributeTypeTest.java b/opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/AttributeTypeTest.java
index 2d285c2..c261aa0 100644
--- a/opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/AttributeTypeTest.java
+++ b/opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/AttributeTypeTest.java
@@ -16,6 +16,7 @@
  */
 package org.forgerock.opendj.ldap.schema;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.forgerock.opendj.ldap.schema.SchemaConstants.*;
 
 import java.util.Iterator;
@@ -481,37 +482,39 @@
         Assert.assertFalse(type.isSingleValue());
     }
 
-    /**
-     * Check that the simple constructor throws an NPE when mandatory parameters
-     * are not specified.
-     *
-     * @throws Exception
-     *             If the test failed unexpectedly.
-     */
-    @Test(expectedExceptions = IllegalArgumentException.class)
-    public void testNoSupNorSyntax1() throws Exception {
-        final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
-        builder.buildAttributeType("1.2.1")
-               .names(EMPTY_NAMES)
-               .obsolete(true)
-               .usage(AttributeUsage.DSA_OPERATION)
-               .addToSchema();
-
-        builder.addAttributeType("( 1.2.2 OBSOLETE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )", false);
-
+    @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
+    public void attributeTypeDefinitionsRequireSyntaxOrSuperiorWhenStrict1() throws Exception {
+        new SchemaBuilder(Schema.getCoreSchema())
+                .setOption(SchemaOptions.ALLOW_ATTRIBUTE_TYPES_WITH_NO_SUP_OR_SYNTAX, false)
+                .addAttributeType("(1.2.1)", true);
     }
 
-    /**
-     * Check that the simple constructor throws an NPE when mandatory parameters
-     * are not specified.
-     *
-     * @throws Exception
-     *             If the test failed unexpectedly.
-     */
     @Test(expectedExceptions = IllegalArgumentException.class)
-    public void testNoSupNorSyntax2() throws Exception {
-        final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
-        builder.addAttributeType("( 1.2.2 OBSOLETE SINGLE-VALUE )", false);
+    public void attributeTypeDefinitionsRequireSyntaxOrSuperiorWhenStrict2() throws Exception {
+        new SchemaBuilder(Schema.getCoreSchema())
+                .setOption(SchemaOptions.ALLOW_ATTRIBUTE_TYPES_WITH_NO_SUP_OR_SYNTAX, false)
+                .buildAttributeType("1.2.1")
+                .addToSchema();
+    }
+
+    @Test
+    public void attributeTypeDefinitionsDoNotRequireSyntaxOrSuperiorWhenTolerant1() throws Exception {
+        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
+                .addAttributeType("(1.2.1)", true).toSchema();
+        assertThat(schema.getWarnings()).isEmpty();
+        assertThat(schema.getAttributeType("1.2.1").getSuperiorType()).isNull();
+        assertThat(schema.getAttributeType("1.2.1").getSyntax()).isSameAs(schema.getDefaultSyntax());
+    }
+
+    @Test
+    public void attributeTypeDefinitionsDoNotRequireSyntaxOrSuperiorWhenTolerant2() throws Exception {
+        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
+                .buildAttributeType("1.2.1")
+                .addToSchema()
+                .toSchema();
+        assertThat(schema.getWarnings()).isEmpty();
+        assertThat(schema.getAttributeType("1.2.1").getSuperiorType()).isNull();
+        assertThat(schema.getAttributeType("1.2.1").getSyntax()).isSameAs(schema.getDefaultSyntax());
     }
 
     @Test
diff --git a/opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java b/opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java
index f097bf2..953c591 100644
--- a/opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java
+++ b/opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java
@@ -84,11 +84,23 @@
                 "1.3.6.1.4.1.1466.115.121.1.15");
     }
 
-    /** Tests that attribute types must have a syntax or a superior. */
+    /** Tests that attribute types must have a syntax or a superior when strict. */
     @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
-    public void attributeTypeNoSuperiorNoSyntax() {
-        new SchemaBuilder(Schema.getCoreSchema()).addAttributeType(
-                "( parenttype-oid NAME 'parenttype' )", false);
+    public void attributeTypeNoSuperiorNoSyntaxWhenStrict() {
+        new SchemaBuilder(Schema.getCoreSchema())
+                .setOption(ALLOW_ATTRIBUTE_TYPES_WITH_NO_SUP_OR_SYNTAX, false)
+                .addAttributeType("( parenttype-oid NAME 'parenttype' )", false);
+    }
+
+    /** Tests that attribute types do not have to have a syntax or a superior when leniant. */
+    @Test
+    public void attributeTypeNoSuperiorNoSyntaxWhenLeniant() {
+        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
+                .addAttributeType("( parenttype-oid NAME 'parenttype' )", false)
+                .toSchema();
+        assertThat(schema.getAttributeType("parenttype").getSyntax()).isNotNull();
+        assertThat(schema.getAttributeType("parenttype").getSyntax().getOID())
+                .isEqualTo("1.3.6.1.4.1.1466.115.121.1.40");
     }
 
     /**

--
Gitblit v1.10.0