From e5fa1d9b9f1f3ea5e7066089cabf52d1c6395adb Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Mon, 30 May 2016 10:43:11 +0000
Subject: [PATCH] OPENDJ-2987 Add placeholder feature to ObjectClass

---
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClass.java |   47 +++++++++++++++++++++++
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java      |   19 ++++++++-
 2 files changed, 63 insertions(+), 3 deletions(-)

diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClass.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClass.java
index 8bedae3..93c2d57 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClass.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClass.java
@@ -14,7 +14,6 @@
  * Copyright 2009 Sun Microsystems, Inc.
  * Portions copyright 2015-2016 ForgeRock AS.
  */
-
 package org.forgerock.opendj.ldap.schema;
 
 import java.util.Collection;
@@ -29,6 +28,8 @@
 
 import org.forgerock.i18n.LocalizableMessage;
 
+import com.forgerock.opendj.util.StaticUtils;
+
 import static java.util.Arrays.*;
 import static java.util.Collections.*;
 
@@ -400,6 +401,8 @@
     /** Indicates whether validation failed. */
     private boolean isValid;
 
+    private boolean isPlaceHolder;
+
     /** Indicates whether this object class is the extensibleObject class. */
     private final boolean isExtensibleObject;
 
@@ -439,6 +442,34 @@
         this.requiredAttributeOIDs = unmodifiableCopyOfSet(builder.requiredAttributes);
         this.optionalAttributeOIDs = unmodifiableCopyOfSet(builder.optionalAttributes);
         this.isExtensibleObject = oid.equals(EXTENSIBLE_OBJECT_OBJECTCLASS_OID);
+        this.isPlaceHolder = false;
+    }
+
+    /**
+     * Creates a new place-holder object class having the specified name.
+     * The OID of the place-holder object class will be the normalized object class name
+     * followed by the suffix "-oid".
+     *
+     * @param name
+     *            The name of the place-holder object class.
+     */
+    ObjectClass(final String name) {
+        this.oid = toOID(name);
+        this.names = Collections.singletonList(name);
+        this.isObsolete = false;
+        this.superiorClassOIDs = Collections.singleton(TOP_OBJECTCLASS_NAME);
+        this.objectClassType = ObjectClassType.ABSTRACT;
+        this.requiredAttributeOIDs = Collections.emptySet();
+        this.optionalAttributeOIDs = Collections.emptySet();
+        this.isExtensibleObject = oid.equals(EXTENSIBLE_OBJECT_OBJECTCLASS_OID);
+        this.isPlaceHolder = true;
+    }
+
+    private static String toOID(final String name) {
+        final StringBuilder builder = new StringBuilder(name.length() + 4);
+        StaticUtils.toLowerCase(name, builder);
+        builder.append("-oid");
+        return builder.toString();
     }
 
     /**
@@ -645,6 +676,20 @@
     }
 
     /**
+     * Returns whether this object class is a placeholder,
+     * i.e. a dummy object class that does not exist in the schema.
+     *
+     * @return {@code true} if this object class is a placeholder,
+     *         {@code false} otherwise
+     * @deprecated This method may be removed at any time
+     * @since OPENDJ-2987 Migrate ObjectClass
+     */
+    @Deprecated
+    public boolean isPlaceHolder() {
+        return isPlaceHolder;
+    }
+
+    /**
      * Indicates whether the provided attribute type is included in the optional
      * attribute list for this or any of its superior objectclasses.
      *
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
index cff4a05..11b2fc0 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
@@ -316,7 +316,8 @@
 
         @Override
         public ObjectClass getObjectClass(final String nameOrOid) {
-            return strictImpl.getObjectClass(nameOrOid);
+            ObjectClass result = strictImpl.getObjectClass0(nameOrOid);
+            return result != null ? result : new ObjectClass(nameOrOid);
         }
 
         @Override
@@ -736,6 +737,14 @@
 
         @Override
         public ObjectClass getObjectClass(final String nameOrOid) {
+            ObjectClass result = getObjectClass0(nameOrOid);
+            if (result != null) {
+                return result;
+            }
+            throw new UnknownSchemaElementException(WARN_OBJECTCLASS_UNKNOWN.get(nameOrOid));
+        }
+
+        private ObjectClass getObjectClass0(final String nameOrOid) {
             final ObjectClass oc = numericOID2ObjectClasses.get(nameOrOid);
             if (oc != null) {
                 return oc;
@@ -747,7 +756,7 @@
                 }
                 throw new UnknownSchemaElementException(WARN_OBJECTCLASS_AMBIGUOUS.get(nameOrOid));
             }
-            throw new UnknownSchemaElementException(WARN_OBJECTCLASS_UNKNOWN.get(nameOrOid));
+            return null;
         }
 
         @Override
@@ -1456,6 +1465,11 @@
 
     /**
      * Returns the object class with the specified name or numeric OID.
+     * <p>
+     * If the requested object class is not registered in this schema and this
+     * schema is non-strict then a temporary "place-holder" object class will
+     * be created and returned. Place holder object classes have an OID which
+     * is the normalized name with the string {@code -oid} appended.
      *
      * @param nameOrOid
      *            The name or OID of the object class to retrieve.
@@ -1463,6 +1477,7 @@
      * @throws UnknownSchemaElementException
      *             If this is a strict schema and the requested object class was
      *             not found or if the provided name is ambiguous.
+     * @see ObjectClass#isPlaceHolder()
      */
     public ObjectClass getObjectClass(final String nameOrOid) {
         return impl.getObjectClass(nameOrOid);

--
Gitblit v1.10.0