From 79cb3d38939c48e71eb1d83592f61765d3983cf0 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Thu, 12 Jul 2007 22:46:42 +0000
Subject: [PATCH] Fix issues 1558 and 1919.

---
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgClient.java                           |  126 +
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgClient.java                          |  305 +++-
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ListenerTest.java                          |  547 ++++++++
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DNBuilderTest.java                         |  105 
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfg.java                                |  211 +++
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentConfiguration.xml                       |  134 ++
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfg.java                                 |   83 +
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.java                            |  626 +++++++--
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java                              |  115 +
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildConfiguration.xml                        |  143 ++
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java |   10 
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java                                      |   75 +
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.java                             |  342 ++++-
 opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java                   |  831 ++++++++-----
 14 files changed, 2,878 insertions(+), 775 deletions(-)

diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java
index cbc3d33..a46b778 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java
@@ -28,23 +28,10 @@
 
 
 
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.opends.server.admin.AbstractManagedObjectDefinition;
-import org.opends.server.admin.InstantiableRelationDefinition;
-import org.opends.server.admin.LDAPProfile;
-import org.opends.server.admin.ManagedObjectDefinition;
-import org.opends.server.admin.PropertyDefinition;
-import org.opends.server.admin.RelationDefinition;
-
-
-
 /**
- * A mock LDAP profile for testing purposes.
+ * A mock LDAP profile wrapper for testing purposes.
  */
-public final class MockLDAPProfile extends LDAPProfile {
+public final class MockLDAPProfile extends LDAPProfile.Wrapper {
 
   /**
    * Creates a new mock LDAP profile.
@@ -61,7 +48,44 @@
   @Override
   public String getAttributeName(ManagedObjectDefinition<?, ?> d,
       PropertyDefinition<?> pd) {
-    return "ds-cfg-" + pd.getName();
+    if (d == TestParentCfgDefn.getInstance()) {
+      TestParentCfgDefn td = TestParentCfgDefn.getInstance();
+
+      if (pd == td.getMandatoryBooleanPropertyPropertyDefinition()) {
+        return "ds-cfg-virtual-attribute-enabled";
+      } else if (pd == td.getMandatoryClassPropertyPropertyDefinition()) {
+        return "ds-cfg-virtual-attribute-class";
+      } else if (pd == td
+          .getMandatoryReadOnlyAttributeTypePropertyPropertyDefinition()) {
+        return "ds-cfg-virtual-attribute-type";
+      } else if (pd == td.getOptionalMultiValuedDNPropertyPropertyDefinition()) {
+        return "ds-cfg-virtual-attribute-base-dn";
+      } else {
+        throw new RuntimeException("Unexpected test-parent property"
+            + pd.getName());
+      }
+    } else if (d == TestChildCfgDefn.getInstance()) {
+      TestChildCfgDefn td = TestChildCfgDefn.getInstance();
+
+      if (pd == td.getMandatoryBooleanPropertyPropertyDefinition()) {
+        return "ds-cfg-virtual-attribute-enabled";
+      } else if (pd == td.getMandatoryClassPropertyPropertyDefinition()) {
+        return "ds-cfg-virtual-attribute-class";
+      } else if (pd == td
+          .getMandatoryReadOnlyAttributeTypePropertyPropertyDefinition()) {
+        return "ds-cfg-virtual-attribute-type";
+      } else if (pd == td.getOptionalMultiValuedDNProperty1PropertyDefinition()) {
+        return "ds-cfg-virtual-attribute-base-dn";
+      } else if (pd == td.getOptionalMultiValuedDNProperty2PropertyDefinition()) {
+        return "ds-cfg-virtual-attribute-group-dn";
+      } else {
+        throw new RuntimeException("Unexpected test-child property"
+            + pd.getName());
+      }
+    }
+
+    // Not known.
+    return null;
   }
 
 
@@ -72,18 +96,13 @@
   @Override
   public String getInstantiableRelationChildRDNType(
       InstantiableRelationDefinition<?, ?> r) {
-    return "cn";
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public List<String> getInstantiableRelationObjectClasses(
-      InstantiableRelationDefinition<?, ?> r) {
-    return Arrays.asList(new String[] { "top", "ds-cfg-branch" });
+    if (r == TestCfg.RD_TEST_ONE_TO_MANY_PARENT
+        || r == TestParentCfgDefn.getInstance()
+            .getTestChildrenRelationDefinition()) {
+      return "cn";
+    } else {
+      return null;
+    }
   }
 
 
@@ -93,25 +112,14 @@
    */
   @Override
   public String getObjectClass(AbstractManagedObjectDefinition<?, ?> d) {
-    return "ds-cfg-" + d.getName();
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public List<String> getObjectClasses(AbstractManagedObjectDefinition<?, ?> d) {
-    LinkedList<String> objectClasses = new LinkedList<String>();
-    for (AbstractManagedObjectDefinition<?, ?> i = d; i != null; i = i
-        .getParent()) {
-      objectClasses.addFirst(getObjectClass(i));
+    if (d == TestParentCfgDefn.getInstance()) {
+      return "ds-cfg-virtual-attribute";
+    } else if (d == TestChildCfgDefn.getInstance()) {
+      return "ds-cfg-virtual-attribute";
+    } else {
+      // Not known.
+      return null;
     }
-
-    // Make sure that we have top.
-    objectClasses.addFirst("top");
-    return objectClasses;
   }
 
 
@@ -121,11 +129,18 @@
    */
   @Override
   public String getRelationRDNSequence(RelationDefinition<?, ?> r) {
-    if (r instanceof InstantiableRelationDefinition) {
-      InstantiableRelationDefinition<?, ?> i = (InstantiableRelationDefinition<?, ?>) r;
-      return "cn=" + i.getPluralName();
+    if (r == TestCfg.RD_TEST_ONE_TO_MANY_PARENT) {
+      return "cn=test parents,cn=config";
+    } else if (r == TestCfg.RD_TEST_ONE_TO_ZERO_OR_ONE_PARENT) {
+      return "cn=optional test parent,cn=config";
+    } else if (r == TestParentCfgDefn.getInstance()
+        .getTestChildrenRelationDefinition()) {
+      return "cn=test children";
+    } else if (r == TestParentCfgDefn.getInstance()
+        .getOptionalTestChildRelationDefinition()) {
+      return "cn=optional test child";
     } else {
-      return "cn=" + r.getName();
+      return null;
     }
   }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java
index 6ce2f52..833ff44 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java
@@ -46,7 +46,7 @@
 
   private static final TestParentCfgDefn d;
 
-  private RelativeInheritedDefaultBehaviorProvider<Integer> ridbp = null;
+  private RelativeInheritedDefaultBehaviorProvider<Boolean> ridbp = null;
 
   static
   {
@@ -63,8 +63,8 @@
    */
   @BeforeClass
   public void setUp() {
-    this.ridbp = new RelativeInheritedDefaultBehaviorProvider<Integer>(d, d
-        .getMaximumLengthPropertyDefinition().getName(), OFFSET);
+    this.ridbp = new RelativeInheritedDefaultBehaviorProvider<Boolean>(d, d
+        .getMandatoryBooleanPropertyPropertyDefinition().getName(), OFFSET);
   }
 
 
@@ -74,7 +74,7 @@
    */
   @Test
   public void testAccept() {
-    ridbp.accept(new DefaultBehaviorProviderVisitor<Integer, Object, Object>() {
+    ridbp.accept(new DefaultBehaviorProviderVisitor<Boolean, Object, Object>() {
 
       public Object visitAbsoluteInherited(
           AbsoluteInheritedDefaultBehaviorProvider d, Object o) {
@@ -127,7 +127,7 @@
   @Test
   public void testGetPropertyDefinition() {
     assertEquals(ridbp.getPropertyName(), d
-        .getMaximumLengthPropertyDefinition().getName());
+        .getMandatoryBooleanPropertyPropertyDefinition().getName());
   }
 
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java
new file mode 100644
index 0000000..b4226f9
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java
@@ -0,0 +1,75 @@
+/*
+ * 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/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * 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/opends/resource/legal-notices/OpenDS.LICENSE.  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
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.admin;
+
+
+
+import org.opends.server.admin.std.meta.RootCfgDefn;
+
+
+
+/**
+ * Common methods for hooking in the test components.
+ */
+public final class TestCfg {
+
+  // Prevent instantiation.
+  private TestCfg() {
+    // No implementation required.
+  }
+
+  /**
+   * A one-to-many relation between the root and test-parent
+   * components.
+   */
+  public static final InstantiableRelationDefinition<TestParentCfgClient, TestParentCfg> RD_TEST_ONE_TO_MANY_PARENT;
+
+  /**
+   * A one-to-zero-or-one relation between the root and a test-parent
+   * component.
+   */
+  public static final OptionalRelationDefinition<TestParentCfgClient, TestParentCfg> RD_TEST_ONE_TO_ZERO_OR_ONE_PARENT;
+
+  // Create a one-to-many relation for test-parent components.
+  static {
+    RD_TEST_ONE_TO_MANY_PARENT = new InstantiableRelationDefinition<TestParentCfgClient, TestParentCfg>(
+        RootCfgDefn.getInstance(), "test-one-to-many-parent",
+        "test-one-to-many-parents", TestParentCfgDefn.getInstance());
+    RootCfgDefn.getInstance().registerRelationDefinition(
+        RD_TEST_ONE_TO_MANY_PARENT);
+  }
+
+  // Create a one-to-many relation for test-parent components.
+  static {
+    RD_TEST_ONE_TO_ZERO_OR_ONE_PARENT = new OptionalRelationDefinition<TestParentCfgClient, TestParentCfg>(
+        RootCfgDefn.getInstance(), "test-one-to-zero-or-one-parent",
+        TestParentCfgDefn.getInstance());
+    RootCfgDefn.getInstance().registerRelationDefinition(
+        RD_TEST_ONE_TO_ZERO_OR_ONE_PARENT);
+  }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfg.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfg.java
index 03648f2..3d391a2 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfg.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfg.java
@@ -28,45 +28,106 @@
 
 
 
+import java.util.SortedSet;
 import org.opends.server.admin.Configuration;
 import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.DN;
 
 
 
 /**
- * A sample server-side configuration interface for testing.
+ * A server-side interface for querying Test Child settings.
+ * <p>
+ * A configuration for testing components that are subordinate to a
+ * parent component. It re-uses the virtual-attribute configuration
+ * LDAP profile.
  */
 public interface TestChildCfg extends Configuration {
 
   /**
-   * {@inheritDoc}
+   * Get the configuration definition associated with this Test Child.
+   *
+   * @return Returns the configuration definition associated with this Test Child.
    */
   ManagedObjectDefinition<? extends TestChildCfgClient, ? extends TestChildCfg> definition();
 
 
 
   /**
-   * Get the "heartbeat-interval" property.
+   * Register to be notified when this Test Child is changed.
    *
-   * @return Returns the value of the "heartbeat-interval" property.
+   * @param listener
+   *          The Test Child configuration change listener.
    */
-  long getHeartbeatInterval();
+  void addChangeListener(ConfigurationChangeListener<TestChildCfg> listener);
 
 
 
   /**
-   * Get the "maximum-length" property.
+   * Deregister an existing Test Child configuration change listener.
    *
-   * @return Returns the value of the "maximum-length" property.
+   * @param listener
+   *          The Test Child configuration change listener.
    */
-  int getMaximumLength();
+  void removeChangeListener(ConfigurationChangeListener<TestChildCfg> listener);
 
 
 
   /**
-   * Get the "minimum-length" property.
+   * Get the "mandatory-boolean-property" property.
+   * <p>
+   * A mandatory boolean property.
    *
-   * @return Returns the value of the "minimum-length" property.
+   * @return Returns the value of the "mandatory-boolean-property" property.
    */
-  int getMinimumLength();
+  boolean isMandatoryBooleanProperty();
+
+
+
+  /**
+   * Get the "mandatory-class-property" property.
+   * <p>
+   * A mandatory Java-class property requiring a component restart.
+   *
+   * @return Returns the value of the "mandatory-class-property" property.
+   */
+  String getMandatoryClassProperty();
+
+
+
+  /**
+   * Get the "mandatory-read-only-attribute-type-property" property.
+   * <p>
+   * A mandatory read-only attribute type property.
+   *
+   * @return Returns the value of the "mandatory-read-only-attribute-type-property" property.
+   */
+  AttributeType getMandatoryReadOnlyAttributeTypeProperty();
+
+
+
+  /**
+   * Get the "optional-multi-valued-dn-property1" property.
+   * <p>
+   * An optional multi-valued DN property which inherits its values
+   * from optional-multi-valued-dn-property in the parent.
+   *
+   * @return Returns the values of the "optional-multi-valued-dn-property1" property.
+   */
+  SortedSet<DN> getOptionalMultiValuedDNProperty1();
+
+
+
+  /**
+   * Get the "optional-multi-valued-dn-property2" property.
+   * <p>
+   * An optional multi-valued DN property which inherits its values
+   * from optional-multi-valued-dn-property1.
+   *
+   * @return Returns the values of the "optional-multi-valued-dn-property2" property.
+   */
+  SortedSet<DN> getOptionalMultiValuedDNProperty2();
+
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgClient.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgClient.java
index 816dea1..b1a025a 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgClient.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgClient.java
@@ -28,81 +28,161 @@
 
 
 
+import java.util.Collection;
+import java.util.SortedSet;
 import org.opends.server.admin.ConfigurationClient;
+import org.opends.server.admin.IllegalPropertyValueException;
 import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.PropertyIsReadOnlyException;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.DN;
 
 
 
 /**
- * A sample client-side configuration interface for testing.
+ * A client-side interface for reading and modifying Test Child
+ * settings.
+ * <p>
+ * A configuration for testing components that are subordinate to a
+ * parent component. It re-uses the virtual-attribute configuration
+ * LDAP profile.
  */
 public interface TestChildCfgClient extends ConfigurationClient {
 
   /**
-   * {@inheritDoc}
+   * Get the configuration definition associated with this Test Child.
+   *
+   * @return Returns the configuration definition associated with this Test Child.
    */
   ManagedObjectDefinition<? extends TestChildCfgClient, ? extends TestChildCfg> definition();
 
 
 
   /**
-   * Get the "heartbeat-interval" property.
+   * Get the "mandatory-boolean-property" property.
+   * <p>
+   * A mandatory boolean property.
    *
-   * @return Returns the value of the "heartbeat-interval" property.
+   * @return Returns the value of the "mandatory-boolean-property" property.
    */
-  long getHeartbeatInterval();
+  Boolean isMandatoryBooleanProperty();
 
 
 
   /**
-   * Set the "heartbeat-interval" property.
+   * Set the "mandatory-boolean-property" property.
+   * <p>
+   * A mandatory boolean property.
    *
-   * @param value
-   *          The value of the "heartbeat-interval" property.
+   * @param value The value of the "mandatory-boolean-property" property.
    * @throws IllegalPropertyValueException
    *           If the new value is invalid.
    */
-  void setHeartbeatInterval(Long value) throws IllegalPropertyValueException;
+  void setMandatoryBooleanProperty(boolean value) throws IllegalPropertyValueException;
 
 
 
   /**
-   * Get the "maximum-length" property.
+   * Get the "mandatory-class-property" property.
+   * <p>
+   * A mandatory Java-class property requiring a component restart.
    *
-   * @return Returns the value of the "maximum-length" property.
+   * @return Returns the value of the "mandatory-class-property" property.
    */
-  int getMaximumLength();
+  String getMandatoryClassProperty();
 
 
 
   /**
-   * Set the "maximum-length" property.
+   * Set the "mandatory-class-property" property.
+   * <p>
+   * A mandatory Java-class property requiring a component restart.
    *
-   * @param value
-   *          The value of the "maximum-length" property.
+   * @param value The value of the "mandatory-class-property" property.
    * @throws IllegalPropertyValueException
    *           If the new value is invalid.
    */
-  void setMaximumLength(Integer value) throws IllegalPropertyValueException;
+  void setMandatoryClassProperty(String value) throws IllegalPropertyValueException;
 
 
 
   /**
-   * Get the "minimum-length" property.
+   * Get the "mandatory-read-only-attribute-type-property" property.
+   * <p>
+   * A mandatory read-only attribute type property.
    *
-   * @return Returns the value of the "minimum-length" property.
+   * @return Returns the value of the "mandatory-read-only-attribute-type-property" property.
    */
-  int getMinimumLength();
+  AttributeType getMandatoryReadOnlyAttributeTypeProperty();
 
 
 
   /**
-   * Set the "minimum-length" property.
+   * Set the "mandatory-read-only-attribute-type-property" property.
+   * <p>
+   * A mandatory read-only attribute type property.
+   * <p>
+   * This property is read-only and can only be modified during
+   * creation of a Test Child.
    *
-   * @param value
-   *          The value of the "minimum-length" property.
+   * @param value The value of the "mandatory-read-only-attribute-type-property" property.
    * @throws IllegalPropertyValueException
    *           If the new value is invalid.
+   * @throws PropertyIsReadOnlyException
+   *           If this Test Child is not being initialized.
    */
-  void setMinimumLength(Integer value) throws IllegalPropertyValueException;
+  void setMandatoryReadOnlyAttributeTypeProperty(AttributeType value) throws IllegalPropertyValueException, PropertyIsReadOnlyException;
+
+
+
+  /**
+   * Get the "optional-multi-valued-dn-property1" property.
+   * <p>
+   * An optional multi-valued DN property which inherits its values
+   * from optional-multi-valued-dn-property in the parent.
+   *
+   * @return Returns the values of the "optional-multi-valued-dn-property1" property.
+   */
+  SortedSet<DN> getOptionalMultiValuedDNProperty1();
+
+
+
+  /**
+   * Set the "optional-multi-valued-dn-property1" property.
+   * <p>
+   * An optional multi-valued DN property which inherits its values
+   * from optional-multi-valued-dn-property in the parent.
+   *
+   * @param values The values of the "optional-multi-valued-dn-property1" property.
+   * @throws IllegalPropertyValueException
+   *           If one or more of the new values are invalid.
+   */
+  void setOptionalMultiValuedDNProperty1(Collection<DN> values) throws IllegalPropertyValueException;
+
+
+
+  /**
+   * Get the "optional-multi-valued-dn-property2" property.
+   * <p>
+   * An optional multi-valued DN property which inherits its values
+   * from optional-multi-valued-dn-property1.
+   *
+   * @return Returns the values of the "optional-multi-valued-dn-property2" property.
+   */
+  SortedSet<DN> getOptionalMultiValuedDNProperty2();
+
+
+
+  /**
+   * Set the "optional-multi-valued-dn-property2" property.
+   * <p>
+   * An optional multi-valued DN property which inherits its values
+   * from optional-multi-valued-dn-property1.
+   *
+   * @param values The values of the "optional-multi-valued-dn-property2" property.
+   * @throws IllegalPropertyValueException
+   *           If one or more of the new values are invalid.
+   */
+  void setOptionalMultiValuedDNProperty2(Collection<DN> values) throws IllegalPropertyValueException;
+
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.java
index 84c16f0..781ed0f 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.java
@@ -28,80 +28,145 @@
 
 
 
+import java.util.Collection;
+import java.util.SortedSet;
+import org.opends.server.admin.AdministratorAction;
+import org.opends.server.admin.AttributeTypePropertyDefinition;
+import org.opends.server.admin.BooleanPropertyDefinition;
+import org.opends.server.admin.ClassPropertyDefinition;
 import org.opends.server.admin.client.AuthorizationException;
 import org.opends.server.admin.client.CommunicationException;
 import org.opends.server.admin.client.ConcurrentModificationException;
 import org.opends.server.admin.client.ManagedObject;
 import org.opends.server.admin.client.MissingMandatoryPropertiesException;
 import org.opends.server.admin.client.OperationRejectedException;
+import org.opends.server.admin.DefaultBehaviorProvider;
+import org.opends.server.admin.DefinedDefaultBehaviorProvider;
+import org.opends.server.admin.DNPropertyDefinition;
+import org.opends.server.admin.ManagedObjectAlreadyExistsException;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.PropertyIsReadOnlyException;
+import org.opends.server.admin.PropertyOption;
+import org.opends.server.admin.PropertyProvider;
+import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider;
+import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.server.ServerManagedObject;
+import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
+import org.opends.server.types.AttributeType;
 import org.opends.server.types.DN;
 
 
 
 /**
- * A sample configuration definition class for testing.
+ * An interface for querying the Test Child managed object definition
+ * meta information.
+ * <p>
+ * A configuration for testing components that are subordinate to a
+ * parent component. It re-uses the virtual-attribute configuration
+ * LDAP profile.
  */
-public final class TestChildCfgDefn extends
-    ManagedObjectDefinition<TestChildCfgClient, TestChildCfg> {
+public final class TestChildCfgDefn extends ManagedObjectDefinition<TestChildCfgClient, TestChildCfg> {
 
   // The singleton configuration definition instance.
   private static final TestChildCfgDefn INSTANCE = new TestChildCfgDefn();
 
-  // The "maximum-length" property definition.
-  private static final IntegerPropertyDefinition PD_MAXIMUM_LENGTH;
 
-  // The "minimum-length" property definition.
-  private static final IntegerPropertyDefinition PD_MINIMUM_LENGTH;
 
-  // The "heartbeat-interval" property definition.
-  private static final DurationPropertyDefinition PD_HEARTBEAT_INTERVAL;
+  // The "mandatory-boolean-property" property definition.
+  private static final BooleanPropertyDefinition PD_MANDATORY_BOOLEAN_PROPERTY;
 
-  // Build the "maximum-length" property definition.
+
+
+  // The "mandatory-class-property" property definition.
+  private static final ClassPropertyDefinition PD_MANDATORY_CLASS_PROPERTY;
+
+
+
+  // The "mandatory-read-only-attribute-type-property" property definition.
+  private static final AttributeTypePropertyDefinition PD_MANDATORY_READ_ONLY_ATTRIBUTE_TYPE_PROPERTY;
+
+
+
+  // The "optional-multi-valued-dn-property1" property definition.
+  private static final DNPropertyDefinition PD_OPTIONAL_MULTI_VALUED_DN_PROPERTY1;
+
+
+
+  // The "optional-multi-valued-dn-property2" property definition.
+  private static final DNPropertyDefinition PD_OPTIONAL_MULTI_VALUED_DN_PROPERTY2;
+
+
+
+  // Build the "mandatory-boolean-property" property definition.
   static {
-    IntegerPropertyDefinition.Builder builder = IntegerPropertyDefinition
-        .createBuilder(INSTANCE, "maximum-length");
-    DefaultBehaviorProvider<Integer> provider = new RelativeInheritedDefaultBehaviorProvider<Integer>(
-        TestParentCfgDefn.getInstance(), "maximum-length", 1);
-    builder.setDefaultBehaviorProvider(provider);
-    builder.setLowerLimit(0);
-    PD_MAXIMUM_LENGTH = builder.getInstance();
-    INSTANCE.registerPropertyDefinition(PD_MAXIMUM_LENGTH);
+      BooleanPropertyDefinition.Builder builder = BooleanPropertyDefinition.createBuilder(INSTANCE, "mandatory-boolean-property");
+      builder.setOption(PropertyOption.MANDATORY);
+      builder.setAdministratorAction(new AdministratorAction(AdministratorAction.Type.NONE, INSTANCE, "mandatory-boolean-property"));
+      builder.setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<Boolean>());
+      PD_MANDATORY_BOOLEAN_PROPERTY = builder.getInstance();
+      INSTANCE.registerPropertyDefinition(PD_MANDATORY_BOOLEAN_PROPERTY);
   }
 
-  // Build the "minimum-length" property definition.
+
+
+  // Build the "mandatory-class-property" property definition.
   static {
-    IntegerPropertyDefinition.Builder builder = IntegerPropertyDefinition
-        .createBuilder(INSTANCE, "minimum-length");
-    DefaultBehaviorProvider<Integer> provider = new AbsoluteInheritedDefaultBehaviorProvider<Integer>(
-        ManagedObjectPath.valueOf("/relation=test-parent+name=test parent 2"),
-        "minimum-length");
-    builder.setDefaultBehaviorProvider(provider);
-    builder.setLowerLimit(0);
-    PD_MINIMUM_LENGTH = builder.getInstance();
-    INSTANCE.registerPropertyDefinition(PD_MINIMUM_LENGTH);
+      ClassPropertyDefinition.Builder builder = ClassPropertyDefinition.createBuilder(INSTANCE, "mandatory-class-property");
+      builder.setOption(PropertyOption.MANDATORY);
+      builder.setAdministratorAction(new AdministratorAction(AdministratorAction.Type.COMPONENT_RESTART, INSTANCE, "mandatory-class-property"));
+      DefaultBehaviorProvider<String> provider = new DefinedDefaultBehaviorProvider<String>("org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+      builder.setDefaultBehaviorProvider(provider);
+      builder.addInstanceOf("org.opends.server.api.VirtualAttributeProvider");
+      PD_MANDATORY_CLASS_PROPERTY = builder.getInstance();
+      INSTANCE.registerPropertyDefinition(PD_MANDATORY_CLASS_PROPERTY);
   }
 
-  // Build the "heartbeat-interval" property definition.
+
+
+  // Build the "mandatory-read-only-attribute-type-property" property definition.
   static {
-    DurationPropertyDefinition.Builder builder = DurationPropertyDefinition
-        .createBuilder(INSTANCE, "heartbeat-interval");
-    DefaultBehaviorProvider<Long> provider = new DefinedDefaultBehaviorProvider<Long>(
-        "1000ms");
-    builder.setDefaultBehaviorProvider(provider);
-    builder.setAllowUnlimited(false);
-    builder.setBaseUnit("ms");
-    builder.setLowerLimit("100");
-    PD_HEARTBEAT_INTERVAL = builder.getInstance();
-    INSTANCE.registerPropertyDefinition(PD_HEARTBEAT_INTERVAL);
+      AttributeTypePropertyDefinition.Builder builder = AttributeTypePropertyDefinition.createBuilder(INSTANCE, "mandatory-read-only-attribute-type-property");
+      builder.setOption(PropertyOption.READ_ONLY);
+      builder.setOption(PropertyOption.MANDATORY);
+      builder.setAdministratorAction(new AdministratorAction(AdministratorAction.Type.NONE, INSTANCE, "mandatory-read-only-attribute-type-property"));
+      builder.setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<AttributeType>());
+      PD_MANDATORY_READ_ONLY_ATTRIBUTE_TYPE_PROPERTY = builder.getInstance();
+      INSTANCE.registerPropertyDefinition(PD_MANDATORY_READ_ONLY_ATTRIBUTE_TYPE_PROPERTY);
+  }
+
+
+
+  // Build the "optional-multi-valued-dn-property1" property definition.
+  static {
+      DNPropertyDefinition.Builder builder = DNPropertyDefinition.createBuilder(INSTANCE, "optional-multi-valued-dn-property1");
+      builder.setOption(PropertyOption.MULTI_VALUED);
+      builder.setAdministratorAction(new AdministratorAction(AdministratorAction.Type.NONE, INSTANCE, "optional-multi-valued-dn-property1"));
+      DefaultBehaviorProvider<DN> provider = new RelativeInheritedDefaultBehaviorProvider<DN>(TestParentCfgDefn.getInstance(), "optional-multi-valued-dn-property", 1);
+      builder.setDefaultBehaviorProvider(provider);
+      PD_OPTIONAL_MULTI_VALUED_DN_PROPERTY1 = builder.getInstance();
+      INSTANCE.registerPropertyDefinition(PD_OPTIONAL_MULTI_VALUED_DN_PROPERTY1);
+  }
+
+
+
+  // Build the "optional-multi-valued-dn-property2" property definition.
+  static {
+      DNPropertyDefinition.Builder builder = DNPropertyDefinition.createBuilder(INSTANCE, "optional-multi-valued-dn-property2");
+      builder.setOption(PropertyOption.MULTI_VALUED);
+      builder.setAdministratorAction(new AdministratorAction(AdministratorAction.Type.NONE, INSTANCE, "optional-multi-valued-dn-property2"));
+      DefaultBehaviorProvider<DN> provider = new RelativeInheritedDefaultBehaviorProvider<DN>(TestChildCfgDefn.getInstance(), "optional-multi-valued-dn-property1", 0);
+      builder.setDefaultBehaviorProvider(provider);
+      PD_OPTIONAL_MULTI_VALUED_DN_PROPERTY2 = builder.getInstance();
+      INSTANCE.registerPropertyDefinition(PD_OPTIONAL_MULTI_VALUED_DN_PROPERTY2);
   }
 
 
 
   /**
-   * Get the definition singleton.
+   * Get the Test Child configuration definition singleton.
    *
-   * @return Returns the definition singleton.
+   * @return Returns the Test Child configuration definition
+   *         singleton.
    */
   public static TestChildCfgDefn getInstance() {
     return INSTANCE;
@@ -148,34 +213,68 @@
 
 
   /**
-   * Get the "heartbeat-interval" property definition.
+   * Get the "mandatory-boolean-property" property definition.
+   * <p>
+   * A mandatory boolean property.
    *
-   * @return Returns the "heartbeat-interval" property definition.
+   * @return Returns the "mandatory-boolean-property" property definition.
    */
-  public DurationPropertyDefinition getHeartbeatIntervalPropertyDefinition() {
-    return PD_HEARTBEAT_INTERVAL;
+  public BooleanPropertyDefinition getMandatoryBooleanPropertyPropertyDefinition() {
+    return PD_MANDATORY_BOOLEAN_PROPERTY;
   }
 
 
 
   /**
-   * Get the "maximum-length" property definition.
+   * Get the "mandatory-class-property" property definition.
+   * <p>
+   * A mandatory Java-class property requiring a component restart.
    *
-   * @return Returns the "maximum-length" property definition.
+   * @return Returns the "mandatory-class-property" property definition.
    */
-  public IntegerPropertyDefinition getMaximumLengthPropertyDefinition() {
-    return PD_MAXIMUM_LENGTH;
+  public ClassPropertyDefinition getMandatoryClassPropertyPropertyDefinition() {
+    return PD_MANDATORY_CLASS_PROPERTY;
   }
 
 
 
   /**
-   * Get the "minimum-length" property definition.
+   * Get the "mandatory-read-only-attribute-type-property" property definition.
+   * <p>
+   * A mandatory read-only attribute type property.
    *
-   * @return Returns the "minimum-length" property definition.
+   * @return Returns the "mandatory-read-only-attribute-type-property" property definition.
    */
-  public IntegerPropertyDefinition getMinimumLengthPropertyDefinition() {
-    return PD_MINIMUM_LENGTH;
+  public AttributeTypePropertyDefinition getMandatoryReadOnlyAttributeTypePropertyPropertyDefinition() {
+    return PD_MANDATORY_READ_ONLY_ATTRIBUTE_TYPE_PROPERTY;
+  }
+
+
+
+  /**
+   * Get the "optional-multi-valued-dn-property1" property definition.
+   * <p>
+   * An optional multi-valued DN property which inherits its values
+   * from optional-multi-valued-dn-property in the parent.
+   *
+   * @return Returns the "optional-multi-valued-dn-property1" property definition.
+   */
+  public DNPropertyDefinition getOptionalMultiValuedDNProperty1PropertyDefinition() {
+    return PD_OPTIONAL_MULTI_VALUED_DN_PROPERTY1;
+  }
+
+
+
+  /**
+   * Get the "optional-multi-valued-dn-property2" property definition.
+   * <p>
+   * An optional multi-valued DN property which inherits its values
+   * from optional-multi-valued-dn-property1.
+   *
+   * @return Returns the "optional-multi-valued-dn-property2" property definition.
+   */
+  public DNPropertyDefinition getOptionalMultiValuedDNProperty2PropertyDefinition() {
+    return PD_OPTIONAL_MULTI_VALUED_DN_PROPERTY2;
   }
 
 
@@ -183,7 +282,8 @@
   /**
    * Managed object client implementation.
    */
-  private static class TestChildCfgClientImpl implements TestChildCfgClient {
+  private static class TestChildCfgClientImpl implements
+    TestChildCfgClient {
 
     // Private implementation.
     private ManagedObject<? extends TestChildCfgClient> impl;
@@ -201,9 +301,8 @@
     /**
      * {@inheritDoc}
      */
-    public long getHeartbeatInterval() {
-      return impl.getPropertyValue(INSTANCE
-          .getHeartbeatIntervalPropertyDefinition());
+    public Boolean isMandatoryBooleanProperty() {
+      return impl.getPropertyValue(INSTANCE.getMandatoryBooleanPropertyPropertyDefinition());
     }
 
 
@@ -211,9 +310,8 @@
     /**
      * {@inheritDoc}
      */
-    public void setHeartbeatInterval(Long value) {
-      impl.setPropertyValue(INSTANCE.getHeartbeatIntervalPropertyDefinition(),
-          value);
+    public void setMandatoryBooleanProperty(boolean value) {
+      impl.setPropertyValue(INSTANCE.getMandatoryBooleanPropertyPropertyDefinition(), value);
     }
 
 
@@ -221,9 +319,8 @@
     /**
      * {@inheritDoc}
      */
-    public int getMaximumLength() {
-      return impl.getPropertyValue(INSTANCE
-          .getMaximumLengthPropertyDefinition());
+    public String getMandatoryClassProperty() {
+      return impl.getPropertyValue(INSTANCE.getMandatoryClassPropertyPropertyDefinition());
     }
 
 
@@ -231,9 +328,8 @@
     /**
      * {@inheritDoc}
      */
-    public void setMaximumLength(Integer value) {
-      impl.setPropertyValue(INSTANCE.getMaximumLengthPropertyDefinition(),
-          value);
+    public void setMandatoryClassProperty(String value) {
+      impl.setPropertyValue(INSTANCE.getMandatoryClassPropertyPropertyDefinition(), value);
     }
 
 
@@ -241,9 +337,8 @@
     /**
      * {@inheritDoc}
      */
-    public int getMinimumLength() {
-      return impl.getPropertyValue(INSTANCE
-          .getMinimumLengthPropertyDefinition());
+    public AttributeType getMandatoryReadOnlyAttributeTypeProperty() {
+      return impl.getPropertyValue(INSTANCE.getMandatoryReadOnlyAttributeTypePropertyPropertyDefinition());
     }
 
 
@@ -251,9 +346,44 @@
     /**
      * {@inheritDoc}
      */
-    public void setMinimumLength(Integer value) {
-      impl.setPropertyValue(INSTANCE.getMinimumLengthPropertyDefinition(),
-          value);
+    public void setMandatoryReadOnlyAttributeTypeProperty(AttributeType value) throws PropertyIsReadOnlyException {
+      impl.setPropertyValue(INSTANCE.getMandatoryReadOnlyAttributeTypePropertyPropertyDefinition(), value);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SortedSet<DN> getOptionalMultiValuedDNProperty1() {
+      return impl.getPropertyValues(INSTANCE.getOptionalMultiValuedDNProperty1PropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setOptionalMultiValuedDNProperty1(Collection<DN> values) {
+      impl.setPropertyValues(INSTANCE.getOptionalMultiValuedDNProperty1PropertyDefinition(), values);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SortedSet<DN> getOptionalMultiValuedDNProperty2() {
+      return impl.getPropertyValues(INSTANCE.getOptionalMultiValuedDNProperty2PropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setOptionalMultiValuedDNProperty2(Collection<DN> values) {
+      impl.setPropertyValues(INSTANCE.getOptionalMultiValuedDNProperty2PropertyDefinition(), values);
     }
 
 
@@ -279,12 +409,13 @@
     /**
      * {@inheritDoc}
      */
-    public void commit() throws ConcurrentModificationException,
+    public void commit() throws ManagedObjectAlreadyExistsException,
+        MissingMandatoryPropertiesException, ConcurrentModificationException,
         OperationRejectedException, AuthorizationException,
-        CommunicationException, ManagedObjectAlreadyExistsException,
-        MissingMandatoryPropertiesException {
+        CommunicationException {
       impl.commit();
     }
+
   }
 
 
@@ -292,7 +423,8 @@
   /**
    * Managed object server implementation.
    */
-  private static class TestChildCfgServerImpl implements TestChildCfg {
+  private static class TestChildCfgServerImpl implements
+    TestChildCfg {
 
     // Private implementation.
     private ServerManagedObject<? extends TestChildCfg> impl;
@@ -300,8 +432,7 @@
 
 
     // Private constructor.
-    private TestChildCfgServerImpl(
-        ServerManagedObject<? extends TestChildCfg> impl) {
+    private TestChildCfgServerImpl(ServerManagedObject<? extends TestChildCfg> impl) {
       this.impl = impl;
     }
 
@@ -310,9 +441,9 @@
     /**
      * {@inheritDoc}
      */
-    public long getHeartbeatInterval() {
-      return impl.getPropertyValue(INSTANCE
-          .getHeartbeatIntervalPropertyDefinition());
+    public void addChangeListener(
+        ConfigurationChangeListener<TestChildCfg> listener) {
+      impl.registerChangeListener(listener);
     }
 
 
@@ -320,9 +451,9 @@
     /**
      * {@inheritDoc}
      */
-    public int getMaximumLength() {
-      return impl.getPropertyValue(INSTANCE
-          .getMaximumLengthPropertyDefinition());
+    public void removeChangeListener(
+        ConfigurationChangeListener<TestChildCfg> listener) {
+      impl.deregisterChangeListener(listener);
     }
 
 
@@ -330,9 +461,44 @@
     /**
      * {@inheritDoc}
      */
-    public int getMinimumLength() {
-      return impl.getPropertyValue(INSTANCE
-          .getMinimumLengthPropertyDefinition());
+    public boolean isMandatoryBooleanProperty() {
+      return impl.getPropertyValue(INSTANCE.getMandatoryBooleanPropertyPropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getMandatoryClassProperty() {
+      return impl.getPropertyValue(INSTANCE.getMandatoryClassPropertyPropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType getMandatoryReadOnlyAttributeTypeProperty() {
+      return impl.getPropertyValue(INSTANCE.getMandatoryReadOnlyAttributeTypePropertyPropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SortedSet<DN> getOptionalMultiValuedDNProperty1() {
+      return impl.getPropertyValues(INSTANCE.getOptionalMultiValuedDNProperty1PropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SortedSet<DN> getOptionalMultiValuedDNProperty2() {
+      return impl.getPropertyValues(INSTANCE.getOptionalMultiValuedDNProperty2PropertyDefinition());
     }
 
 
@@ -361,6 +527,6 @@
     public DN dn() {
       return impl.getDN();
     }
-  }
 
+  }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildConfiguration.xml b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildConfiguration.xml
new file mode 100644
index 0000000..48bcef1
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildConfiguration.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ! 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/opends/resource/legal-notices/OpenDS.LICENSE
+  ! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+  ! 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/opends/resource/legal-notices/OpenDS.LICENSE.  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
+  !
+  !
+  !      Portions Copyright 2007 Sun Microsystems, Inc.
+  ! -->
+<adm:managed-object name="test-child" plural-name="test-children"
+  package="org.opends.server.admin.std"
+  xmlns:adm="http://www.opends.org/admin"
+  xmlns:ldap="http://www.opends.org/admin-ldap">
+  <adm:synopsis>
+    A configuration for testing components that are subordinate to a
+    parent component. It re-uses the virtual-attribute configuration
+    LDAP profile.
+  </adm:synopsis>
+  <adm:profile name="ldap">
+    <ldap:object-class>
+      <ldap:oid>1.3.6.1.4.1.26027.1.2.91</ldap:oid>
+      <ldap:name>ds-cfg-virtual-attribute</ldap:name>
+      <ldap:superior>top</ldap:superior>
+    </ldap:object-class>
+  </adm:profile>
+  <adm:property name="mandatory-boolean-property" mandatory="true">
+    <adm:synopsis>A mandatory boolean property.</adm:synopsis>
+    <adm:syntax>
+      <adm:boolean />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:oid>1.3.6.1.4.1.26027.1.1.326</ldap:oid>
+        <ldap:name>ds-cfg-virtual-attribute-enabled</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="mandatory-class-property" mandatory="true">
+    <adm:synopsis>
+      A mandatory Java-class property requiring a component restart.
+    </adm:synopsis>
+    <adm:requires-admin-action>
+      <adm:component-restart />
+    </adm:requires-admin-action>
+    <adm:default-behavior>
+      <adm:defined>
+        <adm:value>
+          org.opends.server.extensions.UserDefinedVirtualAttributeProvider
+        </adm:value>
+      </adm:defined>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:java-class>
+        <adm:instance-of>
+          org.opends.server.api.VirtualAttributeProvider
+        </adm:instance-of>
+      </adm:java-class>
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:oid>1.3.6.1.4.1.26027.1.1.325</ldap:oid>
+        <ldap:name>ds-cfg-virtual-attribute-class</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="mandatory-read-only-attribute-type-property"
+    mandatory="true" read-only="true">
+    <adm:synopsis>
+      A mandatory read-only attribute type property.
+    </adm:synopsis>
+    <adm:syntax>
+      <adm:attribute-type />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:oid>1.3.6.1.4.1.26027.1.1.327</ldap:oid>
+        <ldap:name>ds-cfg-virtual-attribute-type</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="optional-multi-valued-dn-property1"
+    multi-valued="true">
+    <adm:synopsis>
+      An optional multi-valued DN property which inherits its values
+      from optional-multi-valued-dn-property in the parent.
+    </adm:synopsis>
+    <adm:default-behavior>
+      <adm:inherited>
+        <adm:relative property-name="optional-multi-valued-dn-property"
+          offset="1" managed-object-name="test-parent" />
+      </adm:inherited>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:dn />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:oid>1.3.6.1.4.1.26027.1.1.328</ldap:oid>
+        <ldap:name>ds-cfg-virtual-attribute-base-dn</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="optional-multi-valued-dn-property2"
+    multi-valued="true">
+    <adm:synopsis>
+      An optional multi-valued DN property which inherits its values
+      from optional-multi-valued-dn-property1.
+    </adm:synopsis>
+    <adm:default-behavior>
+      <adm:inherited>
+        <adm:relative property-name="optional-multi-valued-dn-property1"
+          offset="0" managed-object-name="test-child" />
+      </adm:inherited>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:dn />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:oid>1.3.6.1.4.1.26027.1.1.329</ldap:oid>
+        <ldap:name>ds-cfg-virtual-attribute-group-dn</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+</adm:managed-object>
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfg.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfg.java
index e45c0e5..1105419 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfg.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfg.java
@@ -28,34 +28,229 @@
 
 
 
+import java.util.SortedSet;
+import org.opends.server.admin.Configuration;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.server.ConfigurationAddListener;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.server.ConfigurationDeleteListener;
+import org.opends.server.config.ConfigException;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.DN;
 
 
 
 /**
- * A sample server-side configuration interface for testing.
+ * A server-side interface for querying Test Parent settings.
+ * <p>
+ * A configuration for testing components that have child components.
+ * It re-uses the virtual-attribute configuration LDAP profile.
  */
 public interface TestParentCfg extends Configuration {
 
   /**
-   * {@inheritDoc}
+   * Get the configuration definition associated with this Test Parent.
+   *
+   * @return Returns the configuration definition associated with this Test Parent.
    */
   ManagedObjectDefinition<? extends TestParentCfgClient, ? extends TestParentCfg> definition();
 
 
 
   /**
-   * Get the "maximum-length" property.
+   * Register to be notified when this Test Parent is changed.
    *
-   * @return Returns the value of the "maximum-length" property.
+   * @param listener
+   *          The Test Parent configuration change listener.
    */
-  int getMaximumLength();
+  void addChangeListener(ConfigurationChangeListener<TestParentCfg> listener);
 
 
 
   /**
-   * Get the "minimum-length" property.
+   * Deregister an existing Test Parent configuration change listener.
    *
-   * @return Returns the value of the "minimum-length" property.
+   * @param listener
+   *          The Test Parent configuration change listener.
    */
-  int getMinimumLength();
+  void removeChangeListener(ConfigurationChangeListener<TestParentCfg> listener);
+
+
+
+  /**
+   * Get the "mandatory-boolean-property" property.
+   * <p>
+   * A mandatory boolean property.
+   *
+   * @return Returns the value of the "mandatory-boolean-property" property.
+   */
+  boolean isMandatoryBooleanProperty();
+
+
+
+  /**
+   * Get the "mandatory-class-property" property.
+   * <p>
+   * A mandatory Java-class property requiring a component restart.
+   *
+   * @return Returns the value of the "mandatory-class-property" property.
+   */
+  String getMandatoryClassProperty();
+
+
+
+  /**
+   * Get the "mandatory-read-only-attribute-type-property" property.
+   * <p>
+   * A mandatory read-only attribute type property.
+   *
+   * @return Returns the value of the "mandatory-read-only-attribute-type-property" property.
+   */
+  AttributeType getMandatoryReadOnlyAttributeTypeProperty();
+
+
+
+  /**
+   * Get the "optional-multi-valued-dn-property" property.
+   * <p>
+   * An optional multi-valued DN property with a defined default
+   * behavior.
+   *
+   * @return Returns the values of the "optional-multi-valued-dn-property" property.
+   */
+  SortedSet<DN> getOptionalMultiValuedDNProperty();
+
+
+
+  /**
+   * Lists the Test Children.
+   *
+   * @return Returns an array containing the names of the
+   *         Test Children.
+   */
+  String[] listTestChildren();
+
+
+
+  /**
+   * Gets the named Test Child.
+   *
+   * @param name
+   *          The name of the Test Child to retrieve.
+   * @return Returns the named Test Child.
+   * @throws ConfigException
+   *           If the Test Child could not be found or it
+   *           could not be successfully decoded.
+   */
+  TestChildCfg getTestChild(String name) throws ConfigException;
+
+
+
+  /**
+   * Registers to be notified when new Test Children are added.
+   *
+   * @param listener
+   *          The Test Child configuration add listener.
+   * @throws ConfigException
+   *          If the add listener could not be registered.
+   */
+  void addTestChildAddListener(ConfigurationAddListener<TestChildCfg> listener) throws ConfigException;
+
+
+
+  /**
+   * Deregisters an existing Test Child configuration add listener.
+   *
+   * @param listener
+   *          The Test Child configuration add listener.
+   */
+  void removeTestChildAddListener(ConfigurationAddListener<TestChildCfg> listener);
+
+
+
+  /**
+   * Registers to be notified when existing Test Children are deleted.
+   *
+   * @param listener
+   *          The Test Child configuration delete listener.
+   * @throws ConfigException
+   *          If the delete listener could not be registered.
+   */
+  void addTestChildDeleteListener(ConfigurationDeleteListener<TestChildCfg> listener) throws ConfigException;
+
+
+
+  /**
+   * Deregisters an existing Test Child configuration delete listener.
+   *
+   * @param listener
+   *          The Test Child configuration delete listener.
+   */
+  void removeTestChildDeleteListener(ConfigurationDeleteListener<TestChildCfg> listener);
+
+
+
+  /**
+   * Determines whether or not the Optional Test Child exists.
+   *
+   * @return Returns <true> if the Optional Test Child exists.
+   */
+  boolean hasOptionalTestChild();
+
+
+
+  /**
+   * Gets the Optional Test Child if it is present.
+   *
+   * @return Returns the Optional Test Child if it is present.
+   * @throws ConfigException
+   *           If the Optional Test Child does not exist or it could not
+   *           be successfully decoded.
+   */
+  TestChildCfg getOptionalTestChild() throws ConfigException;
+
+
+
+  /**
+   * Registers to be notified when the Optional Test Child is added.
+   *
+   * @param listener
+   *          The Optional Test Child configuration add listener.
+   * @throws ConfigException
+   *          If the add listener could not be registered.
+   */
+  void addOptionalTestChildAddListener(ConfigurationAddListener<TestChildCfg> listener) throws ConfigException;
+
+
+
+  /**
+   * Deregisters an existing Optional Test Child configuration add listener.
+   *
+   * @param listener
+   *          The Optional Test Child configuration add listener.
+   */
+  void removeOptionalTestChildAddListener(ConfigurationAddListener<TestChildCfg> listener);
+
+
+
+  /**
+   * Registers to be notified the Optional Test Child is deleted.
+   *
+   * @param listener
+   *          The Optional Test Child configuration delete listener.
+   * @throws ConfigException
+   *          If the delete listener could not be registered.
+   */
+  void addOptionalChildTestDeleteListener(ConfigurationDeleteListener<TestChildCfg> listener) throws ConfigException;
+
+
+
+  /**
+   * Deregisters an existing Optional Test Child configuration delete listener.
+   *
+   * @param listener
+   *          The Optional Test Child configuration delete listener.
+   */
+  void removeOptionalTestChildDeleteListener(ConfigurationDeleteListener<TestChildCfg> listener);
+
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgClient.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgClient.java
index b83125e..6bcf604 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgClient.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgClient.java
@@ -29,39 +29,155 @@
 
 
 import java.util.Collection;
-
-import org.opends.server.admin.ConfigurationClient;
-import org.opends.server.admin.ManagedObjectDefinition;
+import java.util.SortedSet;
 import org.opends.server.admin.client.AuthorizationException;
 import org.opends.server.admin.client.CommunicationException;
 import org.opends.server.admin.client.ConcurrentModificationException;
 import org.opends.server.admin.client.ManagedObjectDecodingException;
 import org.opends.server.admin.client.OperationRejectedException;
+import org.opends.server.admin.ConfigurationClient;
+import org.opends.server.admin.DefaultBehaviorException;
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.IllegalPropertyValueException;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.PropertyIsReadOnlyException;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.DN;
 
 
 
 /**
- * A sample client-side configuration interface for testing.
+ * A client-side interface for reading and modifying Test Parent
+ * settings.
+ * <p>
+ * A configuration for testing components that have child components.
+ * It re-uses the virtual-attribute configuration LDAP profile.
  */
 public interface TestParentCfgClient extends ConfigurationClient {
 
   /**
-   * {@inheritDoc}
+   * Get the configuration definition associated with this Test Parent.
+   *
+   * @return Returns the configuration definition associated with this Test Parent.
    */
   ManagedObjectDefinition<? extends TestParentCfgClient, ? extends TestParentCfg> definition();
 
 
 
   /**
-   * Lists the test children.
+   * Get the "mandatory-boolean-property" property.
+   * <p>
+   * A mandatory boolean property.
    *
-   * @return Returns an array containing the names of the test
-   *         children.
+   * @return Returns the value of the "mandatory-boolean-property" property.
+   */
+  Boolean isMandatoryBooleanProperty();
+
+
+
+  /**
+   * Set the "mandatory-boolean-property" property.
+   * <p>
+   * A mandatory boolean property.
+   *
+   * @param value The value of the "mandatory-boolean-property" property.
+   * @throws IllegalPropertyValueException
+   *           If the new value is invalid.
+   */
+  void setMandatoryBooleanProperty(boolean value) throws IllegalPropertyValueException;
+
+
+
+  /**
+   * Get the "mandatory-class-property" property.
+   * <p>
+   * A mandatory Java-class property requiring a component restart.
+   *
+   * @return Returns the value of the "mandatory-class-property" property.
+   */
+  String getMandatoryClassProperty();
+
+
+
+  /**
+   * Set the "mandatory-class-property" property.
+   * <p>
+   * A mandatory Java-class property requiring a component restart.
+   *
+   * @param value The value of the "mandatory-class-property" property.
+   * @throws IllegalPropertyValueException
+   *           If the new value is invalid.
+   */
+  void setMandatoryClassProperty(String value) throws IllegalPropertyValueException;
+
+
+
+  /**
+   * Get the "mandatory-read-only-attribute-type-property" property.
+   * <p>
+   * A mandatory read-only attribute type property.
+   *
+   * @return Returns the value of the "mandatory-read-only-attribute-type-property" property.
+   */
+  AttributeType getMandatoryReadOnlyAttributeTypeProperty();
+
+
+
+  /**
+   * Set the "mandatory-read-only-attribute-type-property" property.
+   * <p>
+   * A mandatory read-only attribute type property.
+   * <p>
+   * This property is read-only and can only be modified during
+   * creation of a Test Parent.
+   *
+   * @param value The value of the "mandatory-read-only-attribute-type-property" property.
+   * @throws IllegalPropertyValueException
+   *           If the new value is invalid.
+   * @throws PropertyIsReadOnlyException
+   *           If this Test Parent is not being initialized.
+   */
+  void setMandatoryReadOnlyAttributeTypeProperty(AttributeType value) throws IllegalPropertyValueException, PropertyIsReadOnlyException;
+
+
+
+  /**
+   * Get the "optional-multi-valued-dn-property" property.
+   * <p>
+   * An optional multi-valued DN property with a defined default
+   * behavior.
+   *
+   * @return Returns the values of the "optional-multi-valued-dn-property" property.
+   */
+  SortedSet<DN> getOptionalMultiValuedDNProperty();
+
+
+
+  /**
+   * Set the "optional-multi-valued-dn-property" property.
+   * <p>
+   * An optional multi-valued DN property with a defined default
+   * behavior.
+   *
+   * @param values The values of the "optional-multi-valued-dn-property" property.
+   * @throws IllegalPropertyValueException
+   *           If one or more of the new values are invalid.
+   */
+  void setOptionalMultiValuedDNProperty(Collection<DN> values) throws IllegalPropertyValueException;
+
+
+
+  /**
+   * Lists the Test Children.
+   *
+   * @return Returns an array containing the names of the Test
+   *         Children.
    * @throws ConcurrentModificationException
-   *           If this test parent has been removed from the server by
+   *           If this Test Parent has been removed from the server by
    *           another client.
    * @throws AuthorizationException
-   *           If the server refuses to list the test children because
+   *           If the server refuses to list the Test Children because
    *           the client does not have the correct privileges.
    * @throws CommunicationException
    *           If the client cannot contact the server due to an
@@ -73,25 +189,26 @@
 
 
   /**
-   * Gets the named test child.
+   * Gets the named Test Child.
    *
    * @param name
-   *          The name of the test child to retrieve.
-   * @return Returns the named test child.
+   *           The name of the Test Child to retrieve.
+   * @return Returns the named Test Child.
    * @throws DefinitionDecodingException
-   *           If the named test child was found but its type could
-   *           not be determined.
+   *           If the named Test Child was found but its type
+   *           could not be determined.
    * @throws ManagedObjectDecodingException
-   *           If the named test child was found but one or more of
-   *           its properties could not be decoded.
+   *           If the named Test Child was found but one or
+   *           more of its properties could not be decoded.
    * @throws ManagedObjectNotFoundException
-   *           If the named test child was not found on the server.
+   *           If the named Test Child was not found on the
+   *           server.
    * @throws ConcurrentModificationException
-   *           If this test parent has been removed from the server by
+   *           If this Test Parent has been removed from the server by
    *           another client.
    * @throws AuthorizationException
-   *           If the server refuses to retrieve the named test child
-   *           because the client does not have the correct
+   *           If the server refuses to retrieve the named Multiple
+   *           Children because the client does not have the correct
    *           privileges.
    * @throws CommunicationException
    *           If the client cannot contact the server due to an
@@ -105,93 +222,151 @@
 
 
   /**
-   * Creates a new test child.
+   * Creates a new Test Child. The new Test Child will
+   * initially not contain any property values (including mandatory
+   * properties). Once the Test Child has been configured it can
+   * be added to the server using the {@link #commit()} method.
    *
    * @param <C>
-   *          The type of the test child being added.
+   *          The type of the Test Child being created.
    * @param d
-   *          The definition of the test child to be created.
+   *          The definition of the Test Child to be created.
    * @param name
-   *          The name of the new test child.
+   *          The name of the new Test Child.
    * @param exceptions
    *          An optional collection in which to place any {@link
    *          DefaultBehaviorException}s that occurred whilst
-   *          attempting to determine the default values of the test
-   *          child. This argument can be <code>null<code>.
-   * @return Returns a new test child instance representing the test
-   *         child that was created.
+   *          attempting to determine the default values of the
+   *          Test Child. This argument can be <code>null<code>.
+   * @return Returns a new Test Child configuration instance.
    */
   <C extends TestChildCfgClient> C createTestChild(
-      ManagedObjectDefinition<C, ?> d, String name,
-      Collection<DefaultBehaviorException> exceptions);
+      ManagedObjectDefinition<C, ?> d, String name, Collection<DefaultBehaviorException> exceptions);
 
 
 
   /**
-   * Removes the named test child.
+   * Removes the named Test Child.
    *
    * @param name
-   *          The name of the test child to remove.
+   *          The name of the Test Child to remove.
    * @throws ManagedObjectNotFoundException
-   *           If the test child does not exist.
+   *           If the Test Child does not exist.
    * @throws OperationRejectedException
-   *           If the server refuses to remove the test child due to
-   *           some server-side constraint which cannot be satisfied
-   *           (for example, if it is referenced by another managed
-   *           object).
+   *           If the server refuses to remove the Test Child
+   *           due to some server-side constraint which cannot be
+   *           satisfied (for example, if it is referenced by another
+   *           managed object).
    * @throws ConcurrentModificationException
-   *           If this test parent has been removed from the server by
+   *           If this Test Parent has been removed from the server by
    *           another client.
    * @throws AuthorizationException
-   *           If the server refuses to remove the test child because
+   *           If the server refuses to remove the Test Child
+   *           because the client does not have the correct privileges.
+   * @throws CommunicationException
+   *           If the client cannot contact the server due to an
+   *           underlying communication problem.
+   */
+  void removeTestChild(String name)
+      throws ManagedObjectNotFoundException, OperationRejectedException,
+      ConcurrentModificationException, AuthorizationException,
+      CommunicationException;
+
+
+
+  /**
+   * Determines whether or not the Optional Test Child exists.
+   *
+   * @return Returns <true> if the Optional Test Child exists.
+   * @throws ConcurrentModificationException
+   *           If this Test Parent has been removed from the server by
+   *           another client.
+   * @throws AuthorizationException
+   *           If the server refuses to make the determination because
    *           the client does not have the correct privileges.
    * @throws CommunicationException
    *           If the client cannot contact the server due to an
    *           underlying communication problem.
    */
-  void removeTestChild(String name) throws ManagedObjectNotFoundException,
-      OperationRejectedException, ConcurrentModificationException,
+  boolean hasOptionalTestChild() throws ConcurrentModificationException,
       AuthorizationException, CommunicationException;
 
 
 
   /**
-   * Get the "maximum-length" property.
+   * Gets the Optional Test Child if it is present.
    *
-   * @return Returns the value of the "maximum-length" property.
+   * @return Returns the Optional Test Child if it is present.
+   * @throws DefinitionDecodingException
+   *           If the Optional Test Child was found but its type could not
+   *           be determined.
+   * @throws ManagedObjectDecodingException
+   *           If the Optional Test Child was found but one or more of its
+   *           properties could not be decoded.
+   * @throws ManagedObjectNotFoundException
+   *           If the Optional Test Child is not present.
+   * @throws ConcurrentModificationException
+   *           If this Test Parent has been removed from the server by
+   *           another client.
+   * @throws AuthorizationException
+   *           If the server refuses to retrieve the Optional Test Child
+   *           because the client does not have the correct privileges.
+   * @throws CommunicationException
+   *           If the client cannot contact the server due to an
+   *           underlying communication problem.
    */
-  int getMaximumLength();
+  TestChildCfgClient getOptionalChild()
+      throws DefinitionDecodingException, ManagedObjectDecodingException,
+      ManagedObjectNotFoundException, ConcurrentModificationException,
+      AuthorizationException, CommunicationException;
 
 
 
   /**
-   * Set the "maximum-length" property.
+   * Creates a new Optional Test Child. The new Optional Test Child will
+   * initially not contain any property values (including mandatory
+   * properties). Once the Optional Test Child has been configured it can be
+   * added to the server using the {@link #commit()} method.
    *
-   * @param value
-   *          The value of the "maximum-length" property.
-   * @throws IllegalPropertyValueException
-   *           If the new value is invalid.
+   * @param <C>
+   *          The type of the Optional Test Child being created.
+   * @param d
+   *          The definition of the Optional Test Child to be created.
+   * @param exceptions
+   *          An optional collection in which to place any {@link
+   *          DefaultBehaviorException}s that occurred whilst
+   *          attempting to determine the default values of the
+   *          Optional Test Child. This argument can be <code>null<code>.
+   * @return Returns a new Optional Test Child configuration instance.
    */
-  void setMaximumLength(Integer value) throws IllegalPropertyValueException;
+  <C extends TestChildCfgClient> C createOptionalTestChild(
+      ManagedObjectDefinition<C, ?> d, Collection<DefaultBehaviorException> exceptions);
 
 
 
   /**
-   * Get the "minimum-length" property.
+   * Removes the Optional Test Child if it exists.
    *
-   * @return Returns the value of the "minimum-length" property.
+   * @throws ManagedObjectNotFoundException
+   *           If the Optional Test Child does not exist.
+   * @throws OperationRejectedException
+   *           If the server refuses to remove the Optional Test Child due
+   *           to some server-side constraint which cannot be satisfied
+   *           (for example, if it is referenced by another managed
+   *           object).
+   * @throws ConcurrentModificationException
+   *           If this Test Parent has been removed from the server by
+   *           another client.
+   * @throws AuthorizationException
+   *           If the server refuses to remove the Optional Test Child
+   *           because the client does not have the correct privileges.
+   * @throws CommunicationException
+   *           If the client cannot contact the server due to an
+   *           underlying communication problem.
    */
-  int getMinimumLength();
+  void removeOptionalTestChild()
+      throws ManagedObjectNotFoundException, OperationRejectedException,
+      ConcurrentModificationException, AuthorizationException,
+      CommunicationException;
 
-
-
-  /**
-   * Set the "minimum-length" property.
-   *
-   * @param value
-   *          The value of the "minimum-length" property.
-   * @throws IllegalPropertyValueException
-   *           If the new value is invalid.
-   */
-  void setMinimumLength(Integer value) throws IllegalPropertyValueException;
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.java
index 48b7a2b..3d88428 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.java
@@ -29,7 +29,11 @@
 
 
 import java.util.Collection;
-
+import java.util.SortedSet;
+import org.opends.server.admin.AdministratorAction;
+import org.opends.server.admin.AttributeTypePropertyDefinition;
+import org.opends.server.admin.BooleanPropertyDefinition;
+import org.opends.server.admin.ClassPropertyDefinition;
 import org.opends.server.admin.client.AuthorizationException;
 import org.opends.server.admin.client.CommunicationException;
 import org.opends.server.admin.client.ConcurrentModificationException;
@@ -37,79 +41,149 @@
 import org.opends.server.admin.client.ManagedObjectDecodingException;
 import org.opends.server.admin.client.MissingMandatoryPropertiesException;
 import org.opends.server.admin.client.OperationRejectedException;
+import org.opends.server.admin.DefaultBehaviorException;
+import org.opends.server.admin.DefaultBehaviorProvider;
+import org.opends.server.admin.DefinedDefaultBehaviorProvider;
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.DNPropertyDefinition;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectAlreadyExistsException;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.PropertyIsReadOnlyException;
+import org.opends.server.admin.PropertyOption;
+import org.opends.server.admin.PropertyProvider;
+import org.opends.server.admin.server.ConfigurationAddListener;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.server.ConfigurationDeleteListener;
 import org.opends.server.admin.server.ServerManagedObject;
-import org.opends.server.admin.std.meta.RootCfgDefn;
+import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
+import org.opends.server.config.ConfigException;
+import org.opends.server.types.AttributeType;
 import org.opends.server.types.DN;
 
 
 
 /**
- * A sample configuration definition class for testing.
+ * An interface for querying the Test Parent managed object definition
+ * meta information.
+ * <p>
+ * A configuration for testing components that have child components.
+ * It re-uses the virtual-attribute configuration LDAP profile.
  */
-public final class TestParentCfgDefn extends
-    ManagedObjectDefinition<TestParentCfgClient, TestParentCfg> {
+public final class TestParentCfgDefn extends ManagedObjectDefinition<TestParentCfgClient, TestParentCfg> {
 
   // The singleton configuration definition instance.
   private static final TestParentCfgDefn INSTANCE = new TestParentCfgDefn();
 
-  /**
-   * The relation between this definition and the root.
-   */
-  public static final InstantiableRelationDefinition<TestParentCfgClient, TestParentCfg> RD_TEST_PARENT;
+
+
+  // The "mandatory-boolean-property" property definition.
+  private static final BooleanPropertyDefinition PD_MANDATORY_BOOLEAN_PROPERTY;
+
+
+
+  // The "mandatory-class-property" property definition.
+  private static final ClassPropertyDefinition PD_MANDATORY_CLASS_PROPERTY;
+
+
+
+  // The "mandatory-read-only-attribute-type-property" property definition.
+  private static final AttributeTypePropertyDefinition PD_MANDATORY_READ_ONLY_ATTRIBUTE_TYPE_PROPERTY;
+
+
+
+  // The "optional-multi-valued-dn-property" property definition.
+  private static final DNPropertyDefinition PD_OPTIONAL_MULTI_VALUED_DN_PROPERTY;
+
+
 
   // The "test-children" relation definition.
   private static final InstantiableRelationDefinition<TestChildCfgClient, TestChildCfg> RD_TEST_CHILDREN;
 
-  // The "maximum-length" property definition.
-  private static final IntegerPropertyDefinition PD_MAXIMUM_LENGTH;
 
-  // The "minimum-length" property definition.
-  private static final IntegerPropertyDefinition PD_MINIMUM_LENGTH;
 
-  // Build the "maximum-length" property definition.
+  // The "optional-test-child" relation definition.
+  private static final OptionalRelationDefinition<TestChildCfgClient, TestChildCfg> RD_OPTIONAL_TEST_CHILD;
+
+
+
+  // Build the "mandatory-boolean-property" property definition.
   static {
-    IntegerPropertyDefinition.Builder builder = IntegerPropertyDefinition
-        .createBuilder(INSTANCE, "maximum-length");
-    DefaultBehaviorProvider<Integer> provider = new DefinedDefaultBehaviorProvider<Integer>(
-        "456");
-    builder.setDefaultBehaviorProvider(provider);
-    builder.setLowerLimit(0);
-    PD_MAXIMUM_LENGTH = builder.getInstance();
-    INSTANCE.registerPropertyDefinition(PD_MAXIMUM_LENGTH);
+      BooleanPropertyDefinition.Builder builder = BooleanPropertyDefinition.createBuilder(INSTANCE, "mandatory-boolean-property");
+      builder.setOption(PropertyOption.MANDATORY);
+      builder.setAdministratorAction(new AdministratorAction(AdministratorAction.Type.NONE, INSTANCE, "mandatory-boolean-property"));
+      builder.setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<Boolean>());
+      PD_MANDATORY_BOOLEAN_PROPERTY = builder.getInstance();
+      INSTANCE.registerPropertyDefinition(PD_MANDATORY_BOOLEAN_PROPERTY);
   }
 
-  // Build the "minimum-length" property definition.
+
+
+  // Build the "mandatory-class-property" property definition.
   static {
-    IntegerPropertyDefinition.Builder builder = IntegerPropertyDefinition
-        .createBuilder(INSTANCE, "minimum-length");
-    DefaultBehaviorProvider<Integer> provider = new DefinedDefaultBehaviorProvider<Integer>(
-        "123");
-    builder.setDefaultBehaviorProvider(provider);
-    builder.setLowerLimit(0);
-    PD_MINIMUM_LENGTH = builder.getInstance();
-    INSTANCE.registerPropertyDefinition(PD_MINIMUM_LENGTH);
+      ClassPropertyDefinition.Builder builder = ClassPropertyDefinition.createBuilder(INSTANCE, "mandatory-class-property");
+      builder.setOption(PropertyOption.MANDATORY);
+      builder.setAdministratorAction(new AdministratorAction(AdministratorAction.Type.COMPONENT_RESTART, INSTANCE, "mandatory-class-property"));
+      DefaultBehaviorProvider<String> provider = new DefinedDefaultBehaviorProvider<String>("org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+      builder.setDefaultBehaviorProvider(provider);
+      builder.addInstanceOf("org.opends.server.api.VirtualAttributeProvider");
+      PD_MANDATORY_CLASS_PROPERTY = builder.getInstance();
+      INSTANCE.registerPropertyDefinition(PD_MANDATORY_CLASS_PROPERTY);
   }
 
-  // Register this as a relation against the root configuration.
+
+
+  // Build the "mandatory-read-only-attribute-type-property" property definition.
   static {
-    RD_TEST_PARENT = new InstantiableRelationDefinition<TestParentCfgClient, TestParentCfg>(
-        INSTANCE, "test-parent", "test-parents", INSTANCE);
-    RootCfgDefn.getInstance().registerRelationDefinition(RD_TEST_PARENT);
+      AttributeTypePropertyDefinition.Builder builder = AttributeTypePropertyDefinition.createBuilder(INSTANCE, "mandatory-read-only-attribute-type-property");
+      builder.setOption(PropertyOption.READ_ONLY);
+      builder.setOption(PropertyOption.MANDATORY);
+      builder.setAdministratorAction(new AdministratorAction(AdministratorAction.Type.NONE, INSTANCE, "mandatory-read-only-attribute-type-property"));
+      builder.setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<AttributeType>());
+      PD_MANDATORY_READ_ONLY_ATTRIBUTE_TYPE_PROPERTY = builder.getInstance();
+      INSTANCE.registerPropertyDefinition(PD_MANDATORY_READ_ONLY_ATTRIBUTE_TYPE_PROPERTY);
   }
 
+
+
+  // Build the "optional-multi-valued-dn-property" property definition.
+  static {
+      DNPropertyDefinition.Builder builder = DNPropertyDefinition.createBuilder(INSTANCE, "optional-multi-valued-dn-property");
+      builder.setOption(PropertyOption.MULTI_VALUED);
+      builder.setAdministratorAction(new AdministratorAction(AdministratorAction.Type.NONE, INSTANCE, "optional-multi-valued-dn-property"));
+      DefaultBehaviorProvider<DN> provider = new DefinedDefaultBehaviorProvider<DN>("dc=domain1,dc=com", "dc=domain2,dc=com", "dc=domain3,dc=com");
+      builder.setDefaultBehaviorProvider(provider);
+      PD_OPTIONAL_MULTI_VALUED_DN_PROPERTY = builder.getInstance();
+      INSTANCE.registerPropertyDefinition(PD_OPTIONAL_MULTI_VALUED_DN_PROPERTY);
+  }
+
+
+
   // Build the "test-children" relation definition.
   static {
     RD_TEST_CHILDREN = new InstantiableRelationDefinition<TestChildCfgClient, TestChildCfg>(
-        INSTANCE, "test-child", "test-children", TestChildCfgDefn.getInstance());
+        INSTANCE, "multiple-children", "test-children", TestChildCfgDefn.getInstance());
     INSTANCE.registerRelationDefinition(RD_TEST_CHILDREN);
   }
 
 
 
+  // Build the "optional-test-child" relation definition.
+  static {
+    RD_OPTIONAL_TEST_CHILD = new OptionalRelationDefinition<TestChildCfgClient, TestChildCfg>(
+        INSTANCE, "optional-test-child", TestChildCfgDefn.getInstance());
+    INSTANCE.registerRelationDefinition(RD_OPTIONAL_TEST_CHILD);
+  }
+
+
+
   /**
-   * Get the definition singleton.
+   * Get the Test Parent configuration definition singleton.
    *
-   * @return Returns the definition singleton.
+   * @return Returns the Test Parent configuration definition
+   *         singleton.
    */
   public static TestParentCfgDefn getInstance() {
     return INSTANCE;
@@ -127,39 +201,6 @@
 
 
   /**
-   * Get the "maximum-length" property definition.
-   *
-   * @return Returns the "maximum-length" property definition.
-   */
-  public IntegerPropertyDefinition getMaximumLengthPropertyDefinition() {
-    return PD_MAXIMUM_LENGTH;
-  }
-
-
-
-  /**
-   * Get the "minimum-length" property definition.
-   *
-   * @return Returns the "minimum-length" property definition.
-   */
-  public IntegerPropertyDefinition getMinimumLengthPropertyDefinition() {
-    return PD_MINIMUM_LENGTH;
-  }
-
-
-
-  /**
-   * Get the "test-children" relation definition.
-   *
-   * @return Returns the "test-children" relation definition.
-   */
-  public InstantiableRelationDefinition<TestChildCfgClient, TestChildCfg> getTestChildrenRelationDefinition() {
-    return RD_TEST_CHILDREN;
-  }
-
-
-
-  /**
    * {@inheritDoc}
    */
   public TestParentCfgClient createClientConfiguration(
@@ -189,9 +230,85 @@
 
 
   /**
+   * Get the "mandatory-boolean-property" property definition.
+   * <p>
+   * A mandatory boolean property.
+   *
+   * @return Returns the "mandatory-boolean-property" property definition.
+   */
+  public BooleanPropertyDefinition getMandatoryBooleanPropertyPropertyDefinition() {
+    return PD_MANDATORY_BOOLEAN_PROPERTY;
+  }
+
+
+
+  /**
+   * Get the "mandatory-class-property" property definition.
+   * <p>
+   * A mandatory Java-class property requiring a component restart.
+   *
+   * @return Returns the "mandatory-class-property" property definition.
+   */
+  public ClassPropertyDefinition getMandatoryClassPropertyPropertyDefinition() {
+    return PD_MANDATORY_CLASS_PROPERTY;
+  }
+
+
+
+  /**
+   * Get the "mandatory-read-only-attribute-type-property" property definition.
+   * <p>
+   * A mandatory read-only attribute type property.
+   *
+   * @return Returns the "mandatory-read-only-attribute-type-property" property definition.
+   */
+  public AttributeTypePropertyDefinition getMandatoryReadOnlyAttributeTypePropertyPropertyDefinition() {
+    return PD_MANDATORY_READ_ONLY_ATTRIBUTE_TYPE_PROPERTY;
+  }
+
+
+
+  /**
+   * Get the "optional-multi-valued-dn-property" property definition.
+   * <p>
+   * An optional multi-valued DN property with a defined default
+   * behavior.
+   *
+   * @return Returns the "optional-multi-valued-dn-property" property definition.
+   */
+  public DNPropertyDefinition getOptionalMultiValuedDNPropertyPropertyDefinition() {
+    return PD_OPTIONAL_MULTI_VALUED_DN_PROPERTY;
+  }
+
+
+
+  /**
+   * Get the "test-children" relation definition.
+   *
+   * @return Returns the "test-children" relation definition.
+   */
+  public InstantiableRelationDefinition<TestChildCfgClient,TestChildCfg> getTestChildrenRelationDefinition() {
+    return RD_TEST_CHILDREN;
+  }
+
+
+
+  /**
+   * Get the "optional-test-child" relation definition.
+   *
+   * @return Returns the "optional-test-child" relation definition.
+   */
+  public OptionalRelationDefinition<TestChildCfgClient,TestChildCfg> getOptionalTestChildRelationDefinition() {
+    return RD_OPTIONAL_TEST_CHILD;
+  }
+
+
+
+  /**
    * Managed object client implementation.
    */
-  private static class TestParentCfgClientImpl implements TestParentCfgClient {
+  private static class TestParentCfgClientImpl implements
+    TestParentCfgClient {
 
     // Private implementation.
     private ManagedObject<? extends TestParentCfgClient> impl;
@@ -209,9 +326,8 @@
     /**
      * {@inheritDoc}
      */
-    public int getMaximumLength() {
-      return impl.getPropertyValue(INSTANCE
-          .getMaximumLengthPropertyDefinition());
+    public Boolean isMandatoryBooleanProperty() {
+      return impl.getPropertyValue(INSTANCE.getMandatoryBooleanPropertyPropertyDefinition());
     }
 
 
@@ -219,9 +335,8 @@
     /**
      * {@inheritDoc}
      */
-    public void setMaximumLength(Integer value) {
-      impl.setPropertyValue(INSTANCE.getMaximumLengthPropertyDefinition(),
-          value);
+    public void setMandatoryBooleanProperty(boolean value) {
+      impl.setPropertyValue(INSTANCE.getMandatoryBooleanPropertyPropertyDefinition(), value);
     }
 
 
@@ -229,9 +344,8 @@
     /**
      * {@inheritDoc}
      */
-    public int getMinimumLength() {
-      return impl.getPropertyValue(INSTANCE
-          .getMinimumLengthPropertyDefinition());
+    public String getMandatoryClassProperty() {
+      return impl.getPropertyValue(INSTANCE.getMandatoryClassPropertyPropertyDefinition());
     }
 
 
@@ -239,9 +353,130 @@
     /**
      * {@inheritDoc}
      */
-    public void setMinimumLength(Integer value) {
-      impl.setPropertyValue(INSTANCE.getMinimumLengthPropertyDefinition(),
-          value);
+    public void setMandatoryClassProperty(String value) {
+      impl.setPropertyValue(INSTANCE.getMandatoryClassPropertyPropertyDefinition(), value);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType getMandatoryReadOnlyAttributeTypeProperty() {
+      return impl.getPropertyValue(INSTANCE.getMandatoryReadOnlyAttributeTypePropertyPropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setMandatoryReadOnlyAttributeTypeProperty(AttributeType value) throws PropertyIsReadOnlyException {
+      impl.setPropertyValue(INSTANCE.getMandatoryReadOnlyAttributeTypePropertyPropertyDefinition(), value);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SortedSet<DN> getOptionalMultiValuedDNProperty() {
+      return impl.getPropertyValues(INSTANCE.getOptionalMultiValuedDNPropertyPropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setOptionalMultiValuedDNProperty(Collection<DN> values) {
+      impl.setPropertyValues(INSTANCE.getOptionalMultiValuedDNPropertyPropertyDefinition(), values);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String[] listTestChildren() throws ConcurrentModificationException,
+        AuthorizationException, CommunicationException {
+      return impl.listChildren(INSTANCE.getTestChildrenRelationDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public TestChildCfgClient getTestChild(String name)
+        throws DefinitionDecodingException, ManagedObjectDecodingException,
+        ManagedObjectNotFoundException, ConcurrentModificationException,
+        AuthorizationException, CommunicationException {
+      return impl.getChild(INSTANCE.getTestChildrenRelationDefinition(), name).getConfiguration();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <M extends TestChildCfgClient> M createTestChild(
+        ManagedObjectDefinition<M, ?> d, String name, Collection<DefaultBehaviorException> exceptions) {
+      return impl.createChild(INSTANCE.getTestChildrenRelationDefinition(), d, name, exceptions).getConfiguration();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeTestChild(String name)
+        throws ManagedObjectNotFoundException, ConcurrentModificationException,
+        OperationRejectedException, AuthorizationException, CommunicationException {
+      impl.removeChild(INSTANCE.getTestChildrenRelationDefinition(), name);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasOptionalTestChild() throws ConcurrentModificationException,
+        AuthorizationException, CommunicationException {
+      return impl.hasChild(INSTANCE.getOptionalTestChildRelationDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public TestChildCfgClient getOptionalChild()
+        throws DefinitionDecodingException, ManagedObjectDecodingException,
+        ManagedObjectNotFoundException, ConcurrentModificationException,
+        AuthorizationException, CommunicationException {
+      return impl.getChild(INSTANCE.getOptionalTestChildRelationDefinition()).getConfiguration();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <M extends TestChildCfgClient> M createOptionalTestChild(
+        ManagedObjectDefinition<M, ?> d, Collection<DefaultBehaviorException> exceptions) {
+      return impl.createChild(INSTANCE.getOptionalTestChildRelationDefinition(), d, exceptions).getConfiguration();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeOptionalTestChild()
+        throws ManagedObjectNotFoundException, ConcurrentModificationException,
+        OperationRejectedException, AuthorizationException, CommunicationException {
+      impl.removeChild(INSTANCE.getOptionalTestChildRelationDefinition());
     }
 
 
@@ -267,58 +502,11 @@
     /**
      * {@inheritDoc}
      */
-    public void commit() throws ConcurrentModificationException,
+    public void commit() throws ManagedObjectAlreadyExistsException,
+        MissingMandatoryPropertiesException, ConcurrentModificationException,
         OperationRejectedException, AuthorizationException,
-        CommunicationException, ManagedObjectAlreadyExistsException,
-        MissingMandatoryPropertiesException {
-      impl.commit();
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public <C extends TestChildCfgClient> C createTestChild(
-        ManagedObjectDefinition<C, ?> d, String name,
-        Collection<DefaultBehaviorException> exceptions) {
-      return impl.createChild(INSTANCE.getTestChildrenRelationDefinition(), d,
-          name, exceptions).getConfiguration();
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public TestChildCfgClient getTestChild(String name)
-        throws DefinitionDecodingException, ManagedObjectDecodingException,
-        ManagedObjectNotFoundException, ConcurrentModificationException,
-        AuthorizationException, CommunicationException {
-      return impl.getChild(INSTANCE.getTestChildrenRelationDefinition(), name)
-          .getConfiguration();
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public String[] listTestChildren() throws ConcurrentModificationException,
-        AuthorizationException, CommunicationException {
-      return impl.listChildren(INSTANCE.getTestChildrenRelationDefinition());
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public void removeTestChild(String name)
-        throws ManagedObjectNotFoundException, OperationRejectedException,
-        ConcurrentModificationException, AuthorizationException,
         CommunicationException {
-      impl.removeChild(INSTANCE.getTestChildrenRelationDefinition(), name);
+      impl.commit();
     }
 
   }
@@ -328,7 +516,8 @@
   /**
    * Managed object server implementation.
    */
-  private static class TestParentCfgServerImpl implements TestParentCfg {
+  private static class TestParentCfgServerImpl implements
+    TestParentCfg {
 
     // Private implementation.
     private ServerManagedObject<? extends TestParentCfg> impl;
@@ -336,8 +525,7 @@
 
 
     // Private constructor.
-    private TestParentCfgServerImpl(
-        ServerManagedObject<? extends TestParentCfg> impl) {
+    private TestParentCfgServerImpl(ServerManagedObject<? extends TestParentCfg> impl) {
       this.impl = impl;
     }
 
@@ -346,9 +534,9 @@
     /**
      * {@inheritDoc}
      */
-    public int getMaximumLength() {
-      return impl.getPropertyValue(INSTANCE
-          .getMaximumLengthPropertyDefinition());
+    public void addChangeListener(
+        ConfigurationChangeListener<TestParentCfg> listener) {
+      impl.registerChangeListener(listener);
     }
 
 
@@ -356,9 +544,161 @@
     /**
      * {@inheritDoc}
      */
-    public int getMinimumLength() {
-      return impl.getPropertyValue(INSTANCE
-          .getMinimumLengthPropertyDefinition());
+    public void removeChangeListener(
+        ConfigurationChangeListener<TestParentCfg> listener) {
+      impl.deregisterChangeListener(listener);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isMandatoryBooleanProperty() {
+      return impl.getPropertyValue(INSTANCE.getMandatoryBooleanPropertyPropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getMandatoryClassProperty() {
+      return impl.getPropertyValue(INSTANCE.getMandatoryClassPropertyPropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType getMandatoryReadOnlyAttributeTypeProperty() {
+      return impl.getPropertyValue(INSTANCE.getMandatoryReadOnlyAttributeTypePropertyPropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SortedSet<DN> getOptionalMultiValuedDNProperty() {
+      return impl.getPropertyValues(INSTANCE.getOptionalMultiValuedDNPropertyPropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String[] listTestChildren() {
+      return impl.listChildren(INSTANCE.getTestChildrenRelationDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public TestChildCfg getTestChild(String name) throws ConfigException {
+      return impl.getChild(INSTANCE.getTestChildrenRelationDefinition(), name).getConfiguration();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addTestChildAddListener(
+        ConfigurationAddListener<TestChildCfg> listener) throws ConfigException {
+      impl.registerAddListener(INSTANCE.getTestChildrenRelationDefinition(), listener);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeTestChildAddListener(
+        ConfigurationAddListener<TestChildCfg> listener) {
+      impl.deregisterAddListener(INSTANCE.getTestChildrenRelationDefinition(), listener);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addTestChildDeleteListener(
+        ConfigurationDeleteListener<TestChildCfg> listener) throws ConfigException {
+      impl.registerDeleteListener(INSTANCE.getTestChildrenRelationDefinition(), listener);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeTestChildDeleteListener(
+        ConfigurationDeleteListener<TestChildCfg> listener) {
+      impl.deregisterDeleteListener(INSTANCE.getTestChildrenRelationDefinition(), listener);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasOptionalTestChild() {
+      return impl.hasChild(INSTANCE.getOptionalTestChildRelationDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public TestChildCfg getOptionalTestChild() throws ConfigException {
+      return impl.getChild(INSTANCE.getOptionalTestChildRelationDefinition()).getConfiguration();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addOptionalTestChildAddListener(
+        ConfigurationAddListener<TestChildCfg> listener) throws ConfigException {
+      impl.registerAddListener(INSTANCE.getOptionalTestChildRelationDefinition(), listener);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeOptionalTestChildAddListener(
+        ConfigurationAddListener<TestChildCfg> listener) {
+      impl.deregisterAddListener(INSTANCE.getOptionalTestChildRelationDefinition(), listener);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addOptionalChildTestDeleteListener(
+        ConfigurationDeleteListener<TestChildCfg> listener) throws ConfigException {
+      impl.registerDeleteListener(INSTANCE.getOptionalTestChildRelationDefinition(), listener);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeOptionalTestChildDeleteListener(
+        ConfigurationDeleteListener<TestChildCfg> listener) {
+      impl.deregisterDeleteListener(INSTANCE.getOptionalTestChildRelationDefinition(), listener);
     }
 
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentConfiguration.xml b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentConfiguration.xml
new file mode 100644
index 0000000..a32158a
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentConfiguration.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ! 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/opends/resource/legal-notices/OpenDS.LICENSE
+  ! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+  ! 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/opends/resource/legal-notices/OpenDS.LICENSE.  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
+  !
+  !
+  !      Portions Copyright 2007 Sun Microsystems, Inc.
+  ! -->
+<adm:managed-object name="test-parent" plural-name="test-parents"
+  package="org.opends.server.admin.std"
+  xmlns:adm="http://www.opends.org/admin"
+  xmlns:ldap="http://www.opends.org/admin-ldap">
+  <adm:synopsis>
+    A configuration for testing components that have child components.
+    It re-uses the virtual-attribute configuration LDAP profile.
+  </adm:synopsis>
+  <adm:profile name="ldap">
+    <ldap:object-class>
+      <ldap:oid>1.3.6.1.4.1.26027.1.2.91</ldap:oid>
+      <ldap:name>ds-cfg-virtual-attribute</ldap:name>
+      <ldap:superior>top</ldap:superior>
+    </ldap:object-class>
+  </adm:profile>
+  <adm:relation name="test-child">
+    <adm:one-to-many />
+    <adm:profile name="ldap">
+      <ldap:rdn-sequence>cn=multiple children</ldap:rdn-sequence>
+    </adm:profile>
+  </adm:relation>
+  <adm:relation name="optional-test-child"
+    managed-object-name="test-child">
+    <adm:one-to-zero-or-one />
+    <adm:profile name="ldap">
+      <ldap:rdn-sequence>cn=optional child</ldap:rdn-sequence>
+    </adm:profile>
+  </adm:relation>
+  <adm:property name="mandatory-boolean-property" mandatory="true">
+    <adm:synopsis>A mandatory boolean property.</adm:synopsis>
+    <adm:syntax>
+      <adm:boolean />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:oid>1.3.6.1.4.1.26027.1.1.326</ldap:oid>
+        <ldap:name>ds-cfg-virtual-attribute-enabled</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="mandatory-class-property" mandatory="true">
+    <adm:synopsis>
+      A mandatory Java-class property requiring a component restart.
+    </adm:synopsis>
+    <adm:requires-admin-action>
+      <adm:component-restart />
+    </adm:requires-admin-action>
+    <adm:default-behavior>
+      <adm:defined>
+        <adm:value>
+          org.opends.server.extensions.UserDefinedVirtualAttributeProvider
+        </adm:value>
+      </adm:defined>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:java-class>
+        <adm:instance-of>
+          org.opends.server.api.VirtualAttributeProvider
+        </adm:instance-of>
+      </adm:java-class>
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:oid>1.3.6.1.4.1.26027.1.1.325</ldap:oid>
+        <ldap:name>ds-cfg-virtual-attribute-class</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="mandatory-read-only-attribute-type-property"
+    mandatory="true" read-only="true">
+    <adm:synopsis>
+      A mandatory read-only attribute type property.
+    </adm:synopsis>
+    <adm:syntax>
+      <adm:attribute-type />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:oid>1.3.6.1.4.1.26027.1.1.327</ldap:oid>
+        <ldap:name>ds-cfg-virtual-attribute-type</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="optional-multi-valued-dn-property"
+    multi-valued="true">
+    <adm:synopsis>
+      An optional multi-valued DN property with a defined default
+      behavior.
+    </adm:synopsis>
+    <adm:default-behavior>
+      <adm:defined>
+        <adm:value>dc=domain1,dc=com</adm:value>
+        <adm:value>dc=domain2,dc=com</adm:value>
+        <adm:value>dc=domain3,dc=com</adm:value>
+      </adm:defined>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:dn />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:oid>1.3.6.1.4.1.26027.1.1.328</ldap:oid>
+        <ldap:name>ds-cfg-virtual-attribute-base-dn</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+</adm:managed-object>
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java
index 2b0a7c8..69f031a 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java
@@ -28,7 +28,10 @@
 
 
 
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.SortedSet;
 
 import javax.naming.NamingException;
 import javax.naming.OperationNotSupportedException;
@@ -38,6 +41,7 @@
 import org.opends.server.TestCaseUtils;
 import org.opends.server.admin.AdminTestCase;
 import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.LDAPProfile;
 import org.opends.server.admin.ManagedObjectAlreadyExistsException;
 import org.opends.server.admin.ManagedObjectNotFoundException;
 import org.opends.server.admin.MockLDAPProfile;
@@ -53,7 +57,10 @@
 import org.opends.server.admin.client.ManagementContext;
 import org.opends.server.admin.client.OperationRejectedException;
 import org.opends.server.admin.std.client.RootCfgClient;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.DN;
 import org.testng.Assert;
+import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -67,25 +74,112 @@
 
   // Test LDIF.
   private static final String[] TEST_LDIF = new String[] {
-      "dn: cn=test-parents", "objectclass: top", "objectclass: ds-cfg-branch",
-      "cn: test-parents", "", "dn: cn=test parent 1, cn=test-parents",
-      "objectclass: top", "objectclass: ds-cfg-test-parent",
-      "cn: test parent 1", "", "dn: cn=test parent 2,cn=test-parents",
-      "objectclass: top", "objectclass: ds-cfg-test-parent",
-      "cn: test parent 2", "ds-cfg-minimum-length: 10000",
-      "ds-cfg-maximum-length: 20000", "",
-      "dn:cn=test-children,cn=test parent 1,cn=test-parents",
-      "objectclass: top", "objectclass: ds-cfg-branch", "cn: test-children",
-      "", "dn:cn=test-children,cn=test parent 2,cn=test-parents",
-      "objectclass: top", "objectclass: ds-cfg-branch", "cn: test-children",
+      // Base entries.
+      "dn: cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-branch",
+      "cn: config",
       "",
-      "dn: cn=test child 1,cn=test-children,cn=test parent 1,cn=test-parents",
-      "objectclass: top", "objectclass: ds-cfg-test-child", "cn: test child 1",
+      "dn: cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-branch",
+      "cn: test-parents",
       "",
-      "dn: cn=test child 2,cn=test-children,cn=test parent 1,cn=test-parents",
-      "objectclass: top", "objectclass: ds-cfg-test-child", "cn: test child 2",
-      "ds-cfg-heartbeat-interval: 12345s", "ds-cfg-minimum-length: 11111",
-      "ds-cfg-maximum-length: 22222", "" };
+      // Parent 1 - uses default values for
+      // optional-multi-valued-dn-property.
+      "dn: cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-virtual-attribute",
+      "cn: test parent 1",
+      "ds-cfg-virtual-attribute-enabled: true",
+      "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+      "ds-cfg-virtual-attribute-type: description",
+      "",
+      // Parent 2 - overrides default values for
+      // optional-multi-valued-dn-property.
+      "dn: cn=test parent 2,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-virtual-attribute",
+      "cn: test parent 2",
+      "ds-cfg-virtual-attribute-enabled: true",
+      "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+      "ds-cfg-virtual-attribute-type: description",
+      "ds-cfg-virtual-attribute-base-dn: dc=default value p2v1,dc=com",
+      "ds-cfg-virtual-attribute-base-dn: dc=default value p2v2,dc=com",
+      "",
+      // Parent 3 - overrides default values for
+      // optional-multi-valued-dn-property.
+      "dn: cn=test parent 3,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-virtual-attribute",
+      "cn: test parent 3",
+      "ds-cfg-virtual-attribute-enabled: true",
+      "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+      "ds-cfg-virtual-attribute-type: description",
+      "ds-cfg-virtual-attribute-base-dn: dc=default value p3v1,dc=com",
+      "ds-cfg-virtual-attribute-base-dn: dc=default value p3v2,dc=com",
+      "",
+      // Child base entries.
+      "dn:cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-branch",
+      "cn: multiple children",
+      "",
+      "dn:cn=test children,cn=test parent 2,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-branch",
+      "cn: multiple children",
+      "",
+      // Child 1 inherits defaults for both
+      // optional-multi-valued-dn-property1 and
+      // optional-multi-valued-dn-property2.
+      "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-virtual-attribute",
+      "cn: test child 1",
+      "ds-cfg-virtual-attribute-enabled: true",
+      "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+      "ds-cfg-virtual-attribute-type: description",
+      "",
+      // Child 2 inherits defaults for
+      // optional-multi-valued-dn-property2.
+      "dn: cn=test child 2,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-virtual-attribute",
+      "cn: test child 2",
+      "ds-cfg-virtual-attribute-enabled: true",
+      "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+      "ds-cfg-virtual-attribute-type: description",
+      "ds-cfg-virtual-attribute-base-dn: dc=default value c2v1,dc=com",
+      "ds-cfg-virtual-attribute-base-dn: dc=default value c2v2,dc=com",
+      "",
+      // Child 3 overrides defaults for
+      // optional-multi-valued-dn-property1 and
+      // optional-multi-valued-dn-property2.
+      "dn: cn=test child 3,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-virtual-attribute",
+      "cn: test child 3",
+      "ds-cfg-virtual-attribute-enabled: true",
+      "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+      "ds-cfg-virtual-attribute-type: description",
+      "ds-cfg-virtual-attribute-base-dn: dc=default value c3v1,dc=com",
+      "ds-cfg-virtual-attribute-base-dn: dc=default value c3v2,dc=com",
+      "ds-cfg-virtual-attribute-group-dn: dc=default value c3v3,dc=com",
+      "ds-cfg-virtual-attribute-group-dn: dc=default value c3v4,dc=com",
+      "",
+      // Child 4 inherits overridden defaults for both
+      // optional-multi-valued-dn-property1 and
+      // optional-multi-valued-dn-property2.
+      "dn: cn=test child 1,cn=test children,cn=test parent 2,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-virtual-attribute",
+      "cn: test child 1",
+      "ds-cfg-virtual-attribute-enabled: true",
+      "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+      "ds-cfg-virtual-attribute-type: description",
+      ""
+  };
 
 
 
@@ -98,18 +192,31 @@
   @DataProvider(name = "createManagedObjectExceptions")
   public Object[][] createManagedObjectExceptions() {
     return new Object[][] {
-        { new javax.naming.CommunicationException(),
-            CommunicationException.class },
-        { new javax.naming.ServiceUnavailableException(),
-            CommunicationException.class },
-        { new javax.naming.CannotProceedException(),
-            CommunicationException.class },
-        { new javax.naming.NameAlreadyBoundException(),
-            ManagedObjectAlreadyExistsException.class },
-        { new javax.naming.NoPermissionException(),
-            AuthorizationException.class },
-        { new OperationNotSupportedException(),
-            OperationRejectedException.class } };
+        {
+            new javax.naming.CommunicationException(),
+            CommunicationException.class
+        },
+        {
+            new javax.naming.ServiceUnavailableException(),
+            CommunicationException.class
+        },
+        {
+            new javax.naming.CannotProceedException(),
+            CommunicationException.class
+        },
+        {
+            new javax.naming.NameAlreadyBoundException(),
+            ManagedObjectAlreadyExistsException.class
+        },
+        {
+            new javax.naming.NoPermissionException(),
+            AuthorizationException.class
+        },
+        {
+            new OperationNotSupportedException(),
+            OperationRejectedException.class
+        }
+    };
   }
 
 
@@ -123,17 +230,30 @@
   @DataProvider(name = "getManagedObjectExceptions")
   public Object[][] getManagedObjectExceptions() {
     return new Object[][] {
-        { new javax.naming.CommunicationException(),
-            CommunicationException.class },
-        { new javax.naming.ServiceUnavailableException(),
-            CommunicationException.class },
-        { new javax.naming.CannotProceedException(),
-            CommunicationException.class },
-        { new javax.naming.NameNotFoundException(),
-            ManagedObjectNotFoundException.class },
-        { new javax.naming.NoPermissionException(),
-            AuthorizationException.class },
-        { new OperationNotSupportedException(), CommunicationException.class } };
+        {
+            new javax.naming.CommunicationException(),
+            CommunicationException.class
+        },
+        {
+            new javax.naming.ServiceUnavailableException(),
+            CommunicationException.class
+        },
+        {
+            new javax.naming.CannotProceedException(),
+            CommunicationException.class
+        },
+        {
+            new javax.naming.NameNotFoundException(),
+            ManagedObjectNotFoundException.class
+        },
+        {
+            new javax.naming.NoPermissionException(),
+            AuthorizationException.class
+        },
+        {
+            new OperationNotSupportedException(), CommunicationException.class
+        }
+    };
   }
 
 
@@ -149,6 +269,17 @@
     // This test suite depends on having the schema available, so
     // we'll start the server.
     TestCaseUtils.startServer();
+    LDAPProfile.getInstance().pushWrapper(new MockLDAPProfile());
+  }
+
+
+
+  /**
+   * Tears down test environment.
+   */
+  @AfterClass
+  public void tearDown() {
+    LDAPProfile.getInstance().popWrapper();
   }
 
 
@@ -162,46 +293,22 @@
   @Test
   public void testCreateChildManagedObject() throws Exception {
     CreateEntryMockLDAPConnection c = new CreateEntryMockLDAPConnection(
-        "cn=test child 3,cn=test-children,cn=test parent 1,cn=test-parents");
+        "cn=test child new,cn=test children,cn=test parent 1,cn=test parents,cn=config");
     c.importLDIF(TEST_LDIF);
-    c.addExpectedAttribute("cn", "test child 3");
-    c.addExpectedAttribute("objectclass", "top", "ds-cfg-test-child");
+    c.addExpectedAttribute("cn", "test child new");
+    c.addExpectedAttribute("objectclass", "top", "ds-cfg-virtual-attribute");
+    c.addExpectedAttribute("ds-cfg-virtual-attribute-enabled", "true");
+    c.addExpectedAttribute("ds-cfg-virtual-attribute-class",
+        "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+    c.addExpectedAttribute("ds-cfg-virtual-attribute-type", "description");
 
-    // LDAP encoding uses base unit.
-    c.addExpectedAttribute("ds-cfg-heartbeat-interval", "10000ms");
-
-    ManagementContext ctx = LDAPManagementContext.createFromContext(c,
-        new MockLDAPProfile());
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
     TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
     TestChildCfgClient child = parent.createTestChild(TestChildCfgDefn
-        .getInstance(), "test child 3", null);
-    child.setHeartbeatInterval(10000L);
-    child.commit();
-
-    c.assertEntryIsCreated();
-  }
-
-
-
-  /**
-   * Tests creation of a child managed object.
-   *
-   * @throws Exception
-   *           If an unexpected error occurred.
-   */
-  @Test
-  public void testCreateChildManagedObjectDefault() throws Exception {
-    CreateEntryMockLDAPConnection c = new CreateEntryMockLDAPConnection(
-        "cn=test child 3,cn=test-children,cn=test parent 1,cn=test-parents");
-    c.importLDIF(TEST_LDIF);
-    c.addExpectedAttribute("cn", "test child 3");
-    c.addExpectedAttribute("objectclass", "top", "ds-cfg-test-child");
-
-    ManagementContext ctx = LDAPManagementContext.createFromContext(c,
-        new MockLDAPProfile());
-    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
-    TestChildCfgClient child = parent.createTestChild(TestChildCfgDefn
-        .getInstance(), "test child 3", null);
+        .getInstance(), "test child new", null);
+    child.setMandatoryBooleanProperty(true);
+    child.setMandatoryReadOnlyAttributeTypeProperty(DirectoryServer
+        .getAttributeType("description"));
     child.commit();
 
     c.assertEntryIsCreated();
@@ -234,10 +341,12 @@
 
     };
     c.importLDIF(TEST_LDIF);
-    ManagementContext ctx = LDAPManagementContext.createFromContext(c,
-        new MockLDAPProfile());
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
     try {
-      TestParentCfgClient parent = createTestParent(ctx, "test parent 3");
+      TestParentCfgClient parent = createTestParent(ctx, "test parent new");
+      parent.setMandatoryBooleanProperty(true);
+      parent.setMandatoryReadOnlyAttributeTypeProperty(DirectoryServer
+          .getAttributeType("description"));
       parent.commit();
     } catch (Exception e) {
       Assert.assertEquals(e.getClass(), expected);
@@ -255,41 +364,20 @@
   @Test
   public void testCreateTopLevelManagedObject() throws Exception {
     CreateEntryMockLDAPConnection c = new CreateEntryMockLDAPConnection(
-        "cn=test parent 3,cn=test-parents");
+        "cn=test parent new,cn=test parents,cn=config");
     c.importLDIF(TEST_LDIF);
-    c.addExpectedAttribute("cn", "test parent 3");
-    c.addExpectedAttribute("objectclass", "top", "ds-cfg-test-parent");
-    c.addExpectedAttribute("ds-cfg-maximum-length", "54321");
-    c.addExpectedAttribute("ds-cfg-minimum-length", "12345");
+    c.addExpectedAttribute("cn", "test parent new");
+    c.addExpectedAttribute("objectclass", "top", "ds-cfg-virtual-attribute");
+    c.addExpectedAttribute("ds-cfg-virtual-attribute-enabled", "true");
+    c.addExpectedAttribute("ds-cfg-virtual-attribute-class",
+        "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+    c.addExpectedAttribute("ds-cfg-virtual-attribute-type", "description");
 
-    ManagementContext ctx = LDAPManagementContext.createFromContext(c,
-        new MockLDAPProfile());
-    TestParentCfgClient parent = createTestParent(ctx, "test parent 3");
-    parent.setMaximumLength(54321);
-    parent.setMinimumLength(12345);
-    parent.commit();
-    c.assertEntryIsCreated();
-  }
-
-
-
-  /**
-   * Tests creation of a top-level managed object.
-   *
-   * @throws Exception
-   *           If an unexpected error occurred.
-   */
-  @Test
-  public void testCreateTopLevelManagedObjectDefault() throws Exception {
-    CreateEntryMockLDAPConnection c = new CreateEntryMockLDAPConnection(
-        "cn=test parent 3,cn=test-parents");
-    c.importLDIF(TEST_LDIF);
-    c.addExpectedAttribute("cn", "test parent 3");
-    c.addExpectedAttribute("objectclass", "top", "ds-cfg-test-parent");
-
-    ManagementContext ctx = LDAPManagementContext.createFromContext(c,
-        new MockLDAPProfile());
-    TestParentCfgClient parent = createTestParent(ctx, "test parent 3");
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
+    TestParentCfgClient parent = createTestParent(ctx, "test parent new");
+    parent.setMandatoryBooleanProperty(true);
+    parent.setMandatoryReadOnlyAttributeTypeProperty(DirectoryServer
+        .getAttributeType("description"));
     parent.commit();
     c.assertEntryIsCreated();
   }
@@ -305,12 +393,20 @@
    */
   @Test
   public void testGetChildManagedObject() throws Exception {
-    ManagementContext ctx = getManagementContext(TEST_LDIF);
+    MockLDAPConnection c = new MockLDAPConnection();
+    c.importLDIF(TEST_LDIF);
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
     TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
-    TestChildCfgClient child = parent.getTestChild("test child 2");
-    Assert.assertEquals(child.getHeartbeatInterval(), 12345000);
-    Assert.assertEquals(child.getMinimumLength(), 11111);
-    Assert.assertEquals(child.getMaximumLength(), 22222);
+    TestChildCfgClient child = parent.getTestChild("test child 3");
+    Assert.assertEquals(child.isMandatoryBooleanProperty(), Boolean.TRUE);
+    Assert.assertEquals(child.getMandatoryClassProperty(),
+        "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+    Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+        DirectoryServer.getAttributeType("description"));
+    assertDNSetEquals(child.getOptionalMultiValuedDNProperty1(),
+        "dc=default value c3v1,dc=com", "dc=default value c3v2,dc=com");
+    assertDNSetEquals(child.getOptionalMultiValuedDNProperty2(),
+        "dc=default value c3v3,dc=com", "dc=default value c3v4,dc=com");
   }
 
 
@@ -323,18 +419,26 @@
    */
   @Test
   public void testGetChildManagedObjectDefault() throws Exception {
-    ManagementContext ctx = getManagementContext(TEST_LDIF);
+    MockLDAPConnection c = new MockLDAPConnection();
+    c.importLDIF(TEST_LDIF);
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
     TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
     TestChildCfgClient child = parent.getTestChild("test child 1");
-    Assert.assertEquals(child.getHeartbeatInterval(), 1000);
-    Assert.assertEquals(child.getMinimumLength(), 10000);
-    Assert.assertEquals(child.getMaximumLength(), 456);
+    Assert.assertEquals(child.isMandatoryBooleanProperty(), Boolean.TRUE);
+    Assert.assertEquals(child.getMandatoryClassProperty(),
+        "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+    Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+        DirectoryServer.getAttributeType("description"));
+    assertDNSetEquals(child.getOptionalMultiValuedDNProperty1(),
+        "dc=domain1,dc=com", "dc=domain2,dc=com", "dc=domain3,dc=com");
+    assertDNSetEquals(child.getOptionalMultiValuedDNProperty2(),
+        "dc=domain1,dc=com", "dc=domain2,dc=com", "dc=domain3,dc=com");
   }
 
 
 
   /**
-   * Tests retrieval of a top-level managed object using fails when an
+   * Tests retrieval of a top-level managed object fails when an
    * underlying NamingException occurs.
    *
    * @param cause
@@ -358,8 +462,7 @@
 
     };
     c.importLDIF(TEST_LDIF);
-    ManagementContext ctx = LDAPManagementContext.createFromContext(c,
-        new MockLDAPProfile());
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
     try {
       getTestParent(ctx, "test parent 2");
     } catch (Exception e) {
@@ -378,10 +481,17 @@
    */
   @Test
   public void testGetTopLevelManagedObject() throws Exception {
-    ManagementContext ctx = getManagementContext(TEST_LDIF);
+    MockLDAPConnection c = new MockLDAPConnection();
+    c.importLDIF(TEST_LDIF);
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
     TestParentCfgClient parent = getTestParent(ctx, "test parent 2");
-    Assert.assertEquals(parent.getMinimumLength(), 10000);
-    Assert.assertEquals(parent.getMaximumLength(), 20000);
+    Assert.assertEquals(parent.isMandatoryBooleanProperty(), Boolean.TRUE);
+    Assert.assertEquals(parent.getMandatoryClassProperty(),
+        "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+    Assert.assertEquals(parent.getMandatoryReadOnlyAttributeTypeProperty(),
+        DirectoryServer.getAttributeType("description"));
+    assertDNSetEquals(parent.getOptionalMultiValuedDNProperty(),
+        "dc=default value p2v1,dc=com", "dc=default value p2v2,dc=com");
   }
 
 
@@ -395,183 +505,17 @@
    */
   @Test
   public void testGetTopLevelManagedObjectDefault() throws Exception {
-    ManagementContext ctx = getManagementContext(TEST_LDIF);
-    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
-    Assert.assertEquals(parent.getMinimumLength(), 123);
-    Assert.assertEquals(parent.getMaximumLength(), 456);
-  }
-
-
-
-  /**
-   * Tests listing of child managed objects.
-   *
-   * @throws Exception
-   *           If an unexpected error occurred.
-   */
-  @Test
-  public void testListChildManagedObjects() throws Exception {
-    ManagementContext ctx = getManagementContext(TEST_LDIF);
-    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
-    String[] actual = parent.listTestChildren();
-    String[] expected = new String[] { "test child 1", "test child 2" };
-    Assert.assertEqualsNoOrder(actual, expected);
-  }
-
-
-
-  /**
-   * Tests listing of child managed objects when their are not any.
-   *
-   * @throws Exception
-   *           If an unexpected error occurred.
-   */
-  @Test
-  public void testListChildManagedObjectsEmpty() throws Exception {
-    ManagementContext ctx = getManagementContext(TEST_LDIF);
-    TestParentCfgClient parent = getTestParent(ctx, "test parent 2");
-    String[] actual = parent.listTestChildren();
-    String[] expected = new String[] {};
-    Assert.assertEqualsNoOrder(actual, expected);
-  }
-
-
-
-  /**
-   * Tests listing of top level managed objects.
-   *
-   * @throws Exception
-   *           If an unexpected error occurred.
-   */
-  @Test
-  public void testListTopLevelManagedObjects() throws Exception {
-    ManagementContext ctx = getManagementContext(TEST_LDIF);
-    String[] actual = listTestParents(ctx);
-    String[] expected = new String[] { "test parent 1", "test parent 2" };
-    Assert.assertEqualsNoOrder(actual, expected);
-  }
-
-
-
-  /**
-   * Tests listing of top level managed objects when their are not
-   * any.
-   *
-   * @throws Exception
-   *           If an unexpected error occurred.
-   */
-  @Test
-  public void testListTopLevelManagedObjectsEmpty() throws Exception {
-    ManagementContext ctx = getManagementContext();
-    String[] actual = listTestParents(ctx);
-    String[] expected = new String[] {};
-    Assert.assertEqualsNoOrder(actual, expected);
-  }
-
-
-
-  /**
-   * Tests modification of a child managed object.
-   *
-   * @throws Exception
-   *           If an unexpected error occurred.
-   */
-  @Test
-  public void testModifyChildManagedObjectResetToDefault() throws Exception {
-    ModifyEntryMockLDAPConnection c = new ModifyEntryMockLDAPConnection(
-        "cn=test child 2,cn=test-children,cn=test parent 1,cn=test-parents");
+    MockLDAPConnection c = new MockLDAPConnection();
     c.importLDIF(TEST_LDIF);
-    c.addExpectedModification("ds-cfg-heartbeat-interval");
-    ManagementContext ctx = LDAPManagementContext.createFromContext(c,
-        new MockLDAPProfile());
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
     TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
-    TestChildCfgClient child = parent.getTestChild("test child 2");
-    child.setHeartbeatInterval(null);
-    child.commit();
-    Assert.assertTrue(c.isEntryModified());
-  }
-
-
-
-  /**
-   * Tests modification of a top-level managed object.
-   *
-   * @throws Exception
-   *           If an unexpected error occurred.
-   */
-  @Test
-  public void testModifyTopLevelManagedObjectNoChanges() throws Exception {
-    ModifyEntryMockLDAPConnection c = new ModifyEntryMockLDAPConnection(
-        "cn=test parent 1,cn=test-parents");
-    c.importLDIF(TEST_LDIF);
-    ManagementContext ctx = LDAPManagementContext.createFromContext(c,
-        new MockLDAPProfile());
-    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
-    parent.commit();
-    Assert.assertFalse(c.isEntryModified());
-  }
-
-
-
-  /**
-   * Tests modification of a top-level managed object.
-   *
-   * @throws Exception
-   *           If an unexpected error occurred.
-   */
-  @Test
-  public void testModifyTopLevelManagedObjectWithChanges() throws Exception {
-    ModifyEntryMockLDAPConnection c = new ModifyEntryMockLDAPConnection(
-        "cn=test parent 1,cn=test-parents");
-    c.importLDIF(TEST_LDIF);
-    c.addExpectedModification("ds-cfg-maximum-length", "54321");
-    c.addExpectedModification("ds-cfg-minimum-length", "12345");
-    ManagementContext ctx = LDAPManagementContext.createFromContext(c,
-        new MockLDAPProfile());
-    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
-    parent.setMaximumLength(54321);
-    parent.setMinimumLength(12345);
-    parent.commit();
-    Assert.assertTrue(c.isEntryModified());
-  }
-
-
-
-  /**
-   * Tests removal of a child managed object.
-   *
-   * @throws Exception
-   *           If an unexpected error occurred.
-   */
-  @Test
-  public void testRemoveChildManagedObject() throws Exception {
-    DeleteSubtreeMockLDAPConnection c = new DeleteSubtreeMockLDAPConnection(
-        "cn=test child 1,cn=test-children,cn=test parent 1,cn=test-parents");
-    c.importLDIF(TEST_LDIF);
-    ManagementContext ctx = LDAPManagementContext.createFromContext(c,
-        new MockLDAPProfile());
-    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
-    parent.removeTestChild("test child 1");
-    c.assertSubtreeIsDeleted();
-  }
-
-
-
-  /**
-   * Tests removal of a top-level managed object.
-   *
-   * @throws Exception
-   *           If an unexpected error occurred.
-   */
-  @Test
-  public void testRemoveTopLevelManagedObject() throws Exception {
-    DeleteSubtreeMockLDAPConnection c = new DeleteSubtreeMockLDAPConnection(
-        "cn=test parent 1,cn=test-parents");
-    c.importLDIF(TEST_LDIF);
-    ManagementContext ctx = LDAPManagementContext.createFromContext(c,
-        new MockLDAPProfile());
-    removeTestParent(ctx, "test parent 1");
-    c.assertSubtreeIsDeleted();
+    Assert.assertEquals(parent.isMandatoryBooleanProperty(), Boolean.TRUE);
+    Assert.assertEquals(parent.getMandatoryClassProperty(),
+        "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+    Assert.assertEquals(parent.getMandatoryReadOnlyAttributeTypeProperty(),
+        DirectoryServer.getAttributeType("description"));
+    assertDNSetEquals(parent.getOptionalMultiValuedDNProperty(),
+        "dc=domain1,dc=com", "dc=domain2,dc=com", "dc=domain3,dc=com");
   }
 
 
@@ -585,24 +529,35 @@
   @Test
   public void testInheritedDefaultValues1() throws Exception {
     CreateEntryMockLDAPConnection c = new CreateEntryMockLDAPConnection(
-        "cn=test child 3,cn=test-children,cn=test parent 1,cn=test-parents");
+        "cn=test child new,cn=test children,cn=test parent 1,cn=test parents,cn=config");
     c.importLDIF(TEST_LDIF);
-    c.addExpectedAttribute("cn", "test child 3");
-    c.addExpectedAttribute("objectclass", "top", "ds-cfg-test-child");
+    c.addExpectedAttribute("cn", "test child new");
+    c.addExpectedAttribute("objectclass", "top", "ds-cfg-virtual-attribute");
+    c.addExpectedAttribute("ds-cfg-virtual-attribute-enabled", "true");
+    c.addExpectedAttribute("ds-cfg-virtual-attribute-class",
+        "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+    c.addExpectedAttribute("ds-cfg-virtual-attribute-type", "description");
 
-    ManagementContext ctx = LDAPManagementContext.createFromContext(c,
-        new MockLDAPProfile());
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
     TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
     TestChildCfgClient child = parent.createTestChild(TestChildCfgDefn
-        .getInstance(), "test child 3", null);
+        .getInstance(), "test child new", null);
 
-    // Inherits from parent (test parent 1).
-    Assert.assertEquals(child.getMinimumLength(), 10000);
-
-    // Inherits from test parent 2.
-    Assert.assertEquals(child.getMaximumLength(), 456);
+    // Check pre-commit values.
+    Assert.assertEquals(child.isMandatoryBooleanProperty(), null);
+    Assert.assertEquals(child.getMandatoryClassProperty(),
+        "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+    Assert
+        .assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(), null);
+    assertDNSetEquals(child.getOptionalMultiValuedDNProperty1(),
+        "dc=domain1,dc=com", "dc=domain2,dc=com", "dc=domain3,dc=com");
+    assertDNSetEquals(child.getOptionalMultiValuedDNProperty2(),
+        "dc=domain1,dc=com", "dc=domain2,dc=com", "dc=domain3,dc=com");
 
     // Check that the default values are not committed.
+    child.setMandatoryBooleanProperty(true);
+    child.setMandatoryReadOnlyAttributeTypeProperty(DirectoryServer
+        .getAttributeType("description"));
     child.commit();
 
     c.assertEntryIsCreated();
@@ -619,24 +574,35 @@
   @Test
   public void testInheritedDefaultValues2() throws Exception {
     CreateEntryMockLDAPConnection c = new CreateEntryMockLDAPConnection(
-        "cn=test child 3,cn=test-children,cn=test parent 2,cn=test-parents");
+        "cn=test child new,cn=test children,cn=test parent 2,cn=test parents,cn=config");
     c.importLDIF(TEST_LDIF);
-    c.addExpectedAttribute("cn", "test child 3");
-    c.addExpectedAttribute("objectclass", "top", "ds-cfg-test-child");
+    c.addExpectedAttribute("cn", "test child new");
+    c.addExpectedAttribute("objectclass", "top", "ds-cfg-virtual-attribute");
+    c.addExpectedAttribute("ds-cfg-virtual-attribute-enabled", "true");
+    c.addExpectedAttribute("ds-cfg-virtual-attribute-class",
+        "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+    c.addExpectedAttribute("ds-cfg-virtual-attribute-type", "description");
 
-    ManagementContext ctx = LDAPManagementContext.createFromContext(c,
-        new MockLDAPProfile());
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
     TestParentCfgClient parent = getTestParent(ctx, "test parent 2");
     TestChildCfgClient child = parent.createTestChild(TestChildCfgDefn
-        .getInstance(), "test child 3", null);
+        .getInstance(), "test child new", null);
 
-    // Inherits from parent (test parent 2).
-    Assert.assertEquals(child.getMinimumLength(), 10000);
-
-    // Inherits from test parent 2.
-    Assert.assertEquals(child.getMaximumLength(), 20000);
+    // Check pre-commit values.
+    Assert.assertEquals(child.isMandatoryBooleanProperty(), null);
+    Assert.assertEquals(child.getMandatoryClassProperty(),
+        "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+    Assert
+        .assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(), null);
+    assertDNSetEquals(child.getOptionalMultiValuedDNProperty1(),
+        "dc=default value p2v1,dc=com", "dc=default value p2v2,dc=com");
+    assertDNSetEquals(child.getOptionalMultiValuedDNProperty2(),
+        "dc=default value p2v1,dc=com", "dc=default value p2v2,dc=com");
 
     // Check that the default values are not committed.
+    child.setMandatoryBooleanProperty(true);
+    child.setMandatoryReadOnlyAttributeTypeProperty(DirectoryServer
+        .getAttributeType("description"));
     child.commit();
 
     c.assertEntryIsCreated();
@@ -644,6 +610,202 @@
 
 
 
+  /**
+   * Tests listing of child managed objects.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testListChildManagedObjects() throws Exception {
+    MockLDAPConnection c = new MockLDAPConnection();
+    c.importLDIF(TEST_LDIF);
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
+    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
+    String[] actual = parent.listTestChildren();
+    String[] expected = new String[] {
+        "test child 1", "test child 2", "test child 3"
+    };
+    Assert.assertEqualsNoOrder(actual, expected);
+  }
+
+
+
+  /**
+   * Tests listing of child managed objects when their are not any.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testListChildManagedObjectsEmpty() throws Exception {
+    MockLDAPConnection c = new MockLDAPConnection();
+    c.importLDIF(TEST_LDIF);
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
+    TestParentCfgClient parent = getTestParent(ctx, "test parent 3");
+    String[] actual = parent.listTestChildren();
+    String[] expected = new String[] {};
+    Assert.assertEqualsNoOrder(actual, expected);
+  }
+
+
+
+  /**
+   * Tests listing of top level managed objects.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testListTopLevelManagedObjects() throws Exception {
+    MockLDAPConnection c = new MockLDAPConnection();
+    c.importLDIF(TEST_LDIF);
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
+    String[] actual = listTestParents(ctx);
+    String[] expected = new String[] {
+        "test parent 1", "test parent 2", "test parent 3"
+    };
+    Assert.assertEqualsNoOrder(actual, expected);
+  }
+
+
+
+  /**
+   * Tests listing of top level managed objects when their are not
+   * any.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testListTopLevelManagedObjectsEmpty() throws Exception {
+    String[] ldif = {};
+    MockLDAPConnection c = new MockLDAPConnection();
+    c.importLDIF(ldif);
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
+    String[] actual = listTestParents(ctx);
+    String[] expected = new String[] {};
+    Assert.assertEqualsNoOrder(actual, expected);
+  }
+
+
+
+  /**
+   * Tests modification of a child managed object.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testModifyChildManagedObjectResetToDefault() throws Exception {
+    ModifyEntryMockLDAPConnection c = new ModifyEntryMockLDAPConnection(
+        "cn=test child 2,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+    c.importLDIF(TEST_LDIF);
+    c.addExpectedModification("ds-cfg-virtual-attribute-base-dn");
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
+    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
+    TestChildCfgClient child = parent.getTestChild("test child 2");
+    child.setOptionalMultiValuedDNProperty1(Collections.<DN> emptySet());
+    child.commit();
+    Assert.assertTrue(c.isEntryModified());
+  }
+
+
+
+  /**
+   * Tests modification of a top-level managed object.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testModifyTopLevelManagedObjectNoChanges() throws Exception {
+    ModifyEntryMockLDAPConnection c = new ModifyEntryMockLDAPConnection(
+        "cn=test parent 1,cn=test parents,cn=config");
+    c.importLDIF(TEST_LDIF);
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
+    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
+    parent.commit();
+    Assert.assertFalse(c.isEntryModified());
+  }
+
+
+
+  /**
+   * Tests modification of a top-level managed object.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testModifyTopLevelManagedObjectWithChanges() throws Exception {
+    ModifyEntryMockLDAPConnection c = new ModifyEntryMockLDAPConnection(
+        "cn=test parent 1,cn=test parents,cn=config");
+    c.importLDIF(TEST_LDIF);
+    c.addExpectedModification("ds-cfg-virtual-attribute-enabled", "false");
+    c.addExpectedModification("ds-cfg-virtual-attribute-base-dn",
+        "dc=mod1,dc=com", "dc=mod2,dc=com");
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
+    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
+    parent.setMandatoryBooleanProperty(false);
+    parent.setOptionalMultiValuedDNProperty(Arrays.asList(DN
+        .decode("dc=mod1,dc=com"), DN.decode("dc=mod2,dc=com")));
+    parent.commit();
+    Assert.assertTrue(c.isEntryModified());
+  }
+
+
+
+  /**
+   * Tests removal of a child managed object.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testRemoveChildManagedObject() throws Exception {
+    DeleteSubtreeMockLDAPConnection c = new DeleteSubtreeMockLDAPConnection(
+        "cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+    c.importLDIF(TEST_LDIF);
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
+    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
+    parent.removeTestChild("test child 1");
+    c.assertSubtreeIsDeleted();
+  }
+
+
+
+  /**
+   * Tests removal of a top-level managed object.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testRemoveTopLevelManagedObject() throws Exception {
+    DeleteSubtreeMockLDAPConnection c = new DeleteSubtreeMockLDAPConnection(
+        "cn=test parent 1,cn=test parents,cn=config");
+    c.importLDIF(TEST_LDIF);
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
+    removeTestParent(ctx, "test parent 1");
+    c.assertSubtreeIsDeleted();
+  }
+
+
+
+  // Asserts that the actual set of DNs contains the expected values.
+  private void assertDNSetEquals(SortedSet<DN> actual, String... expected) {
+    String[] actualStrings = new String[actual.size()];
+    int i = 0;
+    for (DN dn : actual) {
+      actualStrings[i] = dn.toString();
+      i++;
+    }
+    Assert.assertEqualsNoOrder(actualStrings, expected);
+  }
+
+
+
   // Create the named test parent managed object.
   private TestParentCfgClient createTestParent(ManagementContext context,
       String name) throws ManagedObjectDecodingException,
@@ -652,21 +814,13 @@
       CommunicationException {
     ManagedObject<RootCfgClient> root = context
         .getRootConfigurationManagedObject();
-    return root.createChild(TestParentCfgDefn.RD_TEST_PARENT,
+    return root.createChild(
+        org.opends.server.admin.TestCfg.RD_TEST_ONE_TO_MANY_PARENT,
         TestParentCfgDefn.getInstance(), name, null).getConfiguration();
   }
 
 
 
-  // Creates a management context using the provided LDIF.
-  private ManagementContext getManagementContext(String... ldif) {
-    MockLDAPConnection c = new MockLDAPConnection();
-    c.importLDIF(ldif);
-    return LDAPManagementContext.createFromContext(c, new MockLDAPProfile());
-  }
-
-
-
   // Retrieve the named test parent managed object.
   private TestParentCfgClient getTestParent(ManagementContext context,
       String name) throws DefinitionDecodingException,
@@ -675,7 +829,8 @@
       CommunicationException {
     ManagedObject<RootCfgClient> root = context
         .getRootConfigurationManagedObject();
-    return root.getChild(TestParentCfgDefn.RD_TEST_PARENT, name)
+    return root.getChild(
+        org.opends.server.admin.TestCfg.RD_TEST_ONE_TO_MANY_PARENT, name)
         .getConfiguration();
   }
 
@@ -687,7 +842,8 @@
       CommunicationException {
     ManagedObject<RootCfgClient> root = context
         .getRootConfigurationManagedObject();
-    return root.listChildren(TestParentCfgDefn.RD_TEST_PARENT);
+    return root
+        .listChildren(org.opends.server.admin.TestCfg.RD_TEST_ONE_TO_MANY_PARENT);
   }
 
 
@@ -699,6 +855,7 @@
       CommunicationException {
     ManagedObject<RootCfgClient> root = context
         .getRootConfigurationManagedObject();
-    root.removeChild(TestParentCfgDefn.RD_TEST_PARENT, name);
+    root.removeChild(
+        org.opends.server.admin.TestCfg.RD_TEST_ONE_TO_MANY_PARENT, name);
   }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DNBuilderTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DNBuilderTest.java
index 941217e..1f1c6c7 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DNBuilderTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DNBuilderTest.java
@@ -28,25 +28,24 @@
 
 
 
-import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.*;
 
 import org.opends.server.TestCaseUtils;
 import org.opends.server.admin.AdminTestCase;
 import org.opends.server.admin.Configuration;
 import org.opends.server.admin.ConfigurationClient;
-import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.LDAPProfile;
 import org.opends.server.admin.ManagedObjectPath;
 import org.opends.server.admin.MockLDAPProfile;
-import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.RelationDefinition;
 import org.opends.server.admin.SingletonRelationDefinition;
+import org.opends.server.admin.TestCfg;
 import org.opends.server.admin.TestChildCfg;
 import org.opends.server.admin.TestChildCfgClient;
 import org.opends.server.admin.TestChildCfgDefn;
-import org.opends.server.admin.TestParentCfg;
-import org.opends.server.admin.TestParentCfgClient;
 import org.opends.server.admin.TestParentCfgDefn;
-import org.opends.server.admin.std.meta.RootCfgDefn;
 import org.opends.server.types.DN;
+import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -68,6 +67,17 @@
     // This test suite depends on having the schema available, so
     // we'll start the server.
     TestCaseUtils.startServer();
+    LDAPProfile.getInstance().pushWrapper(new MockLDAPProfile());
+  }
+
+
+
+  /**
+   * Tears down test environment.
+   */
+  @AfterClass
+  public void tearDown() {
+    LDAPProfile.getInstance().popWrapper();
   }
 
 
@@ -82,25 +92,19 @@
   @Test
   public void testCreateOneToMany() throws Exception {
     // First create the path.
-    ManagedObjectPath<? extends ConfigurationClient, ? extends Configuration> path = ManagedObjectPath.emptyPath();
+    ManagedObjectPath<? extends ConfigurationClient, ? extends Configuration> path = ManagedObjectPath
+        .emptyPath();
 
-    InstantiableRelationDefinition<TestParentCfgClient, TestParentCfg> r1 = new InstantiableRelationDefinition<TestParentCfgClient, TestParentCfg>(
-        RootCfgDefn.getInstance(), "test-parent", "test-parents",
-        TestParentCfgDefn.getInstance());
-
-    InstantiableRelationDefinition<TestChildCfgClient, TestChildCfg> r2 = new InstantiableRelationDefinition<TestChildCfgClient, TestChildCfg>(
-        TestParentCfgDefn.getInstance(), "test-child",
-        "test-children", TestChildCfgDefn.getInstance());
-
-    path = path.child(r1, "test-parent-1");
-    path = path.child(r2, "test-child-1");
+    path = path.child(TestCfg.RD_TEST_ONE_TO_MANY_PARENT, "test-parent-1");
+    path = path.child(TestParentCfgDefn.getInstance()
+        .getTestChildrenRelationDefinition(), "test-child-1");
 
     // Now serialize it.
-    DNBuilder builder = new DNBuilder(new MockLDAPProfile());
+    DNBuilder builder = new DNBuilder();
     path.serialize(builder);
     DN actual = builder.getInstance();
     DN expected = DN
-        .decode("cn=test-child-1,cn=test-children,cn=test-parent-1,cn=test-parents");
+        .decode("cn=test-child-1,cn=test children,cn=test-parent-1,cn=test parents,cn=config");
 
     assertEquals(actual, expected);
   }
@@ -117,27 +121,44 @@
   @Test
   public void testCreateOneToOne() throws Exception {
     // First create the path.
-    ManagedObjectPath<? extends ConfigurationClient, ? extends Configuration> path = ManagedObjectPath.emptyPath();
+    ManagedObjectPath<? extends ConfigurationClient, ? extends Configuration> path = ManagedObjectPath
+        .emptyPath();
 
-    InstantiableRelationDefinition<TestParentCfgClient, TestParentCfg> r1 = new InstantiableRelationDefinition<TestParentCfgClient, TestParentCfg>(
-        RootCfgDefn.getInstance(), "test-parent", "test-parents",
-        TestParentCfgDefn.getInstance());
-
-    SingletonRelationDefinition<TestChildCfgClient, TestChildCfg> r2 = new SingletonRelationDefinition<TestChildCfgClient, TestChildCfg>(
+    final SingletonRelationDefinition<TestChildCfgClient, TestChildCfg> r2 = new SingletonRelationDefinition<TestChildCfgClient, TestChildCfg>(
         TestParentCfgDefn.getInstance(), "singleton-test-child",
         TestChildCfgDefn.getInstance());
+    LDAPProfile.Wrapper wrapper = new LDAPProfile.Wrapper() {
 
-    path = path.child(r1, "test-parent-1");
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public String getRelationRDNSequence(RelationDefinition<?, ?> r) {
+        if (r == r2) {
+          return "cn=singleton-test-child";
+        } else {
+          return null;
+        }
+      }
+
+    };
+
+    path = path.child(TestCfg.RD_TEST_ONE_TO_MANY_PARENT, "test-parent-1");
     path = path.child(r2);
 
     // Now serialize it.
-    DNBuilder builder = new DNBuilder(new MockLDAPProfile());
-    path.serialize(builder);
-    DN actual = builder.getInstance();
-    DN expected = DN
-        .decode("cn=singleton-test-child,cn=test-parent-1,cn=test-parents");
+    LDAPProfile.getInstance().pushWrapper(wrapper);
+    try {
+      DNBuilder builder = new DNBuilder();
+      path.serialize(builder);
+      DN actual = builder.getInstance();
+      DN expected = DN
+          .decode("cn=singleton-test-child,cn=test-parent-1,cn=test parents,cn=config");
 
-    assertEquals(actual, expected);
+      assertEquals(actual, expected);
+    } finally {
+      LDAPProfile.getInstance().popWrapper();
+    }
   }
 
 
@@ -152,25 +173,19 @@
   @Test
   public void testCreateOneToZeroOrOne() throws Exception {
     // First create the path.
-    ManagedObjectPath<? extends ConfigurationClient, ? extends Configuration> path = ManagedObjectPath.emptyPath();
+    ManagedObjectPath<? extends ConfigurationClient, ? extends Configuration> path = ManagedObjectPath
+        .emptyPath();
 
-    InstantiableRelationDefinition<TestParentCfgClient, TestParentCfg> r1 = new InstantiableRelationDefinition<TestParentCfgClient, TestParentCfg>(
-        RootCfgDefn.getInstance(), "test-parent", "test-parents",
-        TestParentCfgDefn.getInstance());
-
-    OptionalRelationDefinition<TestChildCfgClient, TestChildCfg> r2 = new OptionalRelationDefinition<TestChildCfgClient, TestChildCfg>(
-        TestParentCfgDefn.getInstance(), "optional-test-child",
-        TestChildCfgDefn.getInstance());
-
-    path = path.child(r1, "test-parent-1");
-    path = path.child(r2);
+    path = path.child(TestCfg.RD_TEST_ONE_TO_MANY_PARENT, "test-parent-1");
+    path = path.child(TestParentCfgDefn.getInstance()
+        .getOptionalTestChildRelationDefinition());
 
     // Now serialize it.
-    DNBuilder builder = new DNBuilder(new MockLDAPProfile());
+    DNBuilder builder = new DNBuilder();
     path.serialize(builder);
     DN actual = builder.getInstance();
     DN expected = DN
-        .decode("cn=optional-test-child,cn=test-parent-1,cn=test-parents");
+        .decode("cn=optional test child,cn=test-parent-1,cn=test parents,cn=config");
 
     assertEquals(actual, expected);
   }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ListenerTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ListenerTest.java
new file mode 100644
index 0000000..17f6659
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ListenerTest.java
@@ -0,0 +1,547 @@
+/*
+ * 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/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * 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/opends/resource/legal-notices/OpenDS.LICENSE.  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
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.admin.server;
+
+
+
+import static org.testng.Assert.*;
+
+import java.util.List;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.AdminTestCase;
+import org.opends.server.admin.LDAPProfile;
+import org.opends.server.admin.MockLDAPProfile;
+import org.opends.server.admin.TestCfg;
+import org.opends.server.admin.TestParentCfg;
+import org.opends.server.admin.std.server.RootCfg;
+import org.opends.server.api.ConfigAddListener;
+import org.opends.server.api.ConfigDeleteListener;
+import org.opends.server.config.ConfigEntry;
+import org.opends.server.core.DeleteOperation;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DN;
+import org.opends.server.types.ResultCode;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Test cases for listener registration.
+ */
+public final class ListenerTest extends AdminTestCase {
+
+  // Add listener implementation.
+  private static final class TestParentAddListener implements
+      ConfigurationAddListener<TestParentCfg> {
+
+    /**
+     * {@inheritDoc}
+     */
+    public ConfigChangeResult applyConfigurationAdd(TestParentCfg configuration) {
+      // No implementation required.
+      return null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isConfigurationAddAcceptable(TestParentCfg configuration,
+        List<String> unacceptableReasons) {
+      // No implementation required.
+      return false;
+    }
+  }
+
+
+
+  // Delete listener implementation.
+  private static final class TestParentDeleteListener implements
+      ConfigurationDeleteListener<TestParentCfg> {
+
+    /**
+     * {@inheritDoc}
+     */
+    public ConfigChangeResult applyConfigurationDelete(
+        TestParentCfg configuration) {
+      // No implementation required.
+      return null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isConfigurationDeleteAcceptable(TestParentCfg configuration,
+        List<String> unacceptableReasons) {
+      // No implementation required.
+      return false;
+    }
+
+  }
+
+
+
+  /**
+   * Sets up tests
+   *
+   * @throws Exception
+   *           If the server could not be initialized.
+   */
+  @BeforeClass
+  public void setUp() throws Exception {
+    // This test suite depends on having the schema available, so
+    // we'll start the server.
+    TestCaseUtils.startServer();
+    LDAPProfile.getInstance().pushWrapper(new MockLDAPProfile());
+  }
+
+
+
+  /**
+   * Tears down test environment.
+   */
+  @AfterClass
+  public void tearDown() {
+    LDAPProfile.getInstance().popWrapper();
+  }
+
+
+
+  /**
+   * Checks that a ConfigAddListenerAdaptor is delayed when its
+   * associated instantiable relation entry does not exist.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test
+  public void testConfigAddListenerAdaptorInstantiableDelayed()
+      throws Exception {
+    ServerManagementContext ctx = ServerManagementContext.getInstance();
+    ServerManagedObject<RootCfg> root = ctx.getRootConfigurationManagedObject();
+    ConfigurationAddListener<TestParentCfg> listener = new TestParentAddListener();
+    root.registerAddListener(TestCfg.RD_TEST_ONE_TO_MANY_PARENT, listener);
+
+    // Make sure that the relation entry does not exist.
+    DN relationDN = DN.decode("cn=test parents,cn=config");
+    ConfigEntry configEntry = DirectoryServer.getConfigEntry(relationDN);
+    assertNull(configEntry, "Relation entry " + relationDN + " already exists");
+
+    // Make sure that the listener was delayed and registered against
+    // the parent.
+    DN parentDN = DN.decode("cn=config");
+    configEntry = DirectoryServer.getConfigEntry(parentDN);
+    assertNotNull(configEntry, "Relation parent entry " + parentDN
+        + " does not exist");
+
+    boolean isFound = false;
+    for (ConfigAddListener l : configEntry.getAddListeners()) {
+      if (l instanceof DelayedConfigAddListener) {
+        DelayedConfigAddListener dl = (DelayedConfigAddListener) l;
+        ConfigAddListener tmp = dl.getDelayedAddListener();
+        if (tmp instanceof ConfigAddListenerAdaptor) {
+          ConfigAddListenerAdaptor al = (ConfigAddListenerAdaptor) tmp;
+          if (al.getConfigurationAddListener() == listener) {
+            isFound = true;
+          }
+        }
+      }
+    }
+
+    if (!isFound) {
+      fail("Unable to locate delayed listener in entry " + parentDN);
+    }
+
+    // Now make sure that the delayed listener is removed from the
+    // parent and the add listener register against the relation entry
+    // when it is created.
+    String[] entry = new String[] {
+        "dn: cn=test parents,cn=config",
+        "objectclass: top",
+        "objectclass: ds-cfg-branch",
+        "cn: test-parents"
+    };
+    TestCaseUtils.addEntry(entry);
+
+    // Check the delayed listener is removed.
+    for (ConfigAddListener l : configEntry.getAddListeners()) {
+      if (l instanceof DelayedConfigAddListener) {
+        DelayedConfigAddListener dl = (DelayedConfigAddListener) l;
+        ConfigAddListener tmp = dl.getDelayedAddListener();
+        if (tmp instanceof ConfigAddListenerAdaptor) {
+          ConfigAddListenerAdaptor al = (ConfigAddListenerAdaptor) tmp;
+          if (al.getConfigurationAddListener() == listener) {
+            fail("Delayed listener still exists in entry " + parentDN
+                + " when it should have been removed");
+
+            // Clean up.
+            configEntry.deregisterAddListener(dl);
+          }
+        }
+      }
+    }
+
+    // Check the add listener is registered.
+    configEntry = DirectoryServer.getConfigEntry(relationDN);
+    assertNotNull(configEntry, "Relation entry " + relationDN
+        + " does not exist");
+
+    isFound = false;
+    for (ConfigAddListener l : configEntry.getAddListeners()) {
+      if (l instanceof ConfigAddListenerAdaptor) {
+        ConfigAddListenerAdaptor al = (ConfigAddListenerAdaptor) l;
+        if (al.getConfigurationAddListener() == listener) {
+          isFound = true;
+
+          // Clean up.
+          configEntry.deregisterAddListener(al);
+        }
+      }
+    }
+
+    if (!isFound) {
+      fail("Unable to locate listener adaptor in entry " + relationDN);
+    }
+
+    // Remove the test entry.
+    InternalClientConnection conn = InternalClientConnection
+        .getRootConnection();
+    DeleteOperation deleteOperation = conn.processDelete(relationDN);
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+  }
+
+
+
+  /**
+   * Checks that a ConfigAddListenerAdaptor is not delayed when its
+   * associated instantiable relation entry already exists.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test
+  public void testConfigAddListenerAdaptorInstantiableImmediate()
+      throws Exception {
+    ServerManagementContext ctx = ServerManagementContext.getInstance();
+    ServerManagedObject<RootCfg> root = ctx.getRootConfigurationManagedObject();
+    ConfigurationAddListener<TestParentCfg> listener = new TestParentAddListener();
+    root.registerAddListener(TestCfg.RD_TEST_ONE_TO_MANY_PARENT, listener);
+
+    // Add the relation entry.
+    String[] entry = new String[] {
+        "dn: cn=test parents,cn=config",
+        "objectclass: top",
+        "objectclass: ds-cfg-branch",
+        "cn: test-parents"
+    };
+    TestCaseUtils.addEntry(entry);
+
+    // Make sure that the relation entry exist.
+    DN relationDN = DN.decode("cn=test parents,cn=config");
+    ConfigEntry configEntry = DirectoryServer.getConfigEntry(relationDN);
+    assertNotNull(configEntry, "Relation entry " + relationDN
+        + " does not exist");
+
+    // Check the add listener is registered.
+    boolean isFound = false;
+    for (ConfigAddListener l : configEntry.getAddListeners()) {
+      if (l instanceof ConfigAddListenerAdaptor) {
+        ConfigAddListenerAdaptor al = (ConfigAddListenerAdaptor) l;
+        if (al.getConfigurationAddListener() == listener) {
+          isFound = true;
+
+          // Clean up.
+          configEntry.deregisterAddListener(al);
+        }
+      }
+    }
+
+    if (!isFound) {
+      fail("Unable to locate listener adaptor in entry " + relationDN);
+    }
+
+    // Remove the test entry.
+    InternalClientConnection conn = InternalClientConnection
+        .getRootConnection();
+    DeleteOperation deleteOperation = conn.processDelete(relationDN);
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+  }
+
+
+
+  /**
+   * Checks that a ConfigAddListenerAdaptor is registered for optional
+   * relations.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test
+  public void testConfigAddListenerAdaptorOptional() throws Exception {
+    ServerManagementContext ctx = ServerManagementContext.getInstance();
+    ServerManagedObject<RootCfg> root = ctx.getRootConfigurationManagedObject();
+    ConfigurationAddListener<TestParentCfg> listener = new TestParentAddListener();
+    root.registerAddListener(TestCfg.RD_TEST_ONE_TO_ZERO_OR_ONE_PARENT,
+        listener);
+
+    // Make sure that the relation entry exists.
+    DN relationDN = DN.decode("cn=config");
+    ConfigEntry configEntry = DirectoryServer.getConfigEntry(relationDN);
+    assertNotNull(configEntry, "Relation entry " + relationDN
+        + " does not exist");
+
+    // Check the add listener is registered.
+    boolean isFound = false;
+    for (ConfigAddListener l : configEntry.getAddListeners()) {
+      if (l instanceof ConfigAddListenerAdaptor) {
+        ConfigAddListenerAdaptor al = (ConfigAddListenerAdaptor) l;
+        if (al.getConfigurationAddListener() == listener) {
+          isFound = true;
+
+          // Clean up.
+          configEntry.deregisterAddListener(al);
+        }
+      }
+    }
+
+    if (!isFound) {
+      fail("Unable to locate listener adaptor in entry " + relationDN);
+    }
+  }
+
+
+
+  /**
+   * Checks that a ConfigDeleteListenerAdaptor is delayed when its
+   * associated instantiable relation entry does not exist.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test
+  public void testConfigDeleteListenerAdaptorInstantiableDelayed()
+      throws Exception {
+    ServerManagementContext ctx = ServerManagementContext.getInstance();
+    ServerManagedObject<RootCfg> root = ctx.getRootConfigurationManagedObject();
+    ConfigurationDeleteListener<TestParentCfg> listener = new TestParentDeleteListener();
+    root.registerDeleteListener(TestCfg.RD_TEST_ONE_TO_MANY_PARENT, listener);
+
+    // Make sure that the relation entry does not exist.
+    DN relationDN = DN.decode("cn=test parents,cn=config");
+    ConfigEntry configEntry = DirectoryServer.getConfigEntry(relationDN);
+    assertNull(configEntry, "Relation entry " + relationDN + " already exists");
+
+    // Make sure that the listener was delayed and registered against
+    // the parent.
+    DN parentDN = DN.decode("cn=config");
+    configEntry = DirectoryServer.getConfigEntry(parentDN);
+    assertNotNull(configEntry, "Relation parent entry " + parentDN
+        + " does not exist");
+
+    boolean isFound = false;
+    for (ConfigAddListener l : configEntry.getAddListeners()) {
+      if (l instanceof DelayedConfigAddListener) {
+        DelayedConfigAddListener dl = (DelayedConfigAddListener) l;
+        ConfigDeleteListener tmp = dl.getDelayedDeleteListener();
+        if (tmp instanceof ConfigDeleteListenerAdaptor) {
+          ConfigDeleteListenerAdaptor al = (ConfigDeleteListenerAdaptor) tmp;
+          if (al.getConfigurationDeleteListener() == listener) {
+            isFound = true;
+          }
+        }
+      }
+    }
+
+    if (!isFound) {
+      fail("Unable to locate delayed listener in entry " + parentDN);
+    }
+
+    // Now make sure that the delayed listener is removed from the
+    // parent and the add listener register against the relation entry
+    // when it is created.
+    String[] entry = new String[] {
+        "dn: cn=test parents,cn=config",
+        "objectclass: top",
+        "objectclass: ds-cfg-branch",
+        "cn: test-parents"
+    };
+    TestCaseUtils.addEntry(entry);
+
+    // Check the delayed listener is removed.
+    for (ConfigAddListener l : configEntry.getAddListeners()) {
+      if (l instanceof DelayedConfigAddListener) {
+        DelayedConfigAddListener dl = (DelayedConfigAddListener) l;
+        ConfigDeleteListener tmp = dl.getDelayedDeleteListener();
+        if (tmp instanceof ConfigDeleteListenerAdaptor) {
+          ConfigDeleteListenerAdaptor al = (ConfigDeleteListenerAdaptor) tmp;
+          if (al.getConfigurationDeleteListener() == listener) {
+            fail("Delayed listener still exists in entry " + parentDN
+                + " when it should have been removed");
+
+            // Clean up.
+            configEntry.deregisterAddListener(dl);
+          }
+        }
+      }
+    }
+
+    // Check the add listener is registered.
+    configEntry = DirectoryServer.getConfigEntry(relationDN);
+    assertNotNull(configEntry, "Relation entry " + relationDN
+        + " does not exist");
+
+    isFound = false;
+    for (ConfigDeleteListener l : configEntry.getDeleteListeners()) {
+      if (l instanceof ConfigDeleteListenerAdaptor) {
+        ConfigDeleteListenerAdaptor al = (ConfigDeleteListenerAdaptor) l;
+        if (al.getConfigurationDeleteListener() == listener) {
+          isFound = true;
+
+          // Clean up.
+          configEntry.deregisterDeleteListener(al);
+        }
+      }
+    }
+
+    if (!isFound) {
+      fail("Unable to locate listener adaptor in entry " + relationDN);
+    }
+
+    // Remove the test entry.
+    InternalClientConnection conn = InternalClientConnection
+        .getRootConnection();
+    DeleteOperation deleteOperation = conn.processDelete(relationDN);
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+  }
+
+
+
+  /**
+   * Checks that a ConfigDeleteListenerAdaptor is not delayed when its
+   * associated instantiable relation entry already exists.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test
+  public void testConfigDeleteListenerAdaptorInstantiableImmediate()
+      throws Exception {
+    ServerManagementContext ctx = ServerManagementContext.getInstance();
+    ServerManagedObject<RootCfg> root = ctx.getRootConfigurationManagedObject();
+    ConfigurationDeleteListener<TestParentCfg> listener = new TestParentDeleteListener();
+    root.registerDeleteListener(TestCfg.RD_TEST_ONE_TO_MANY_PARENT, listener);
+
+    // Add the relation entry.
+    String[] entry = new String[] {
+        "dn: cn=test parents,cn=config",
+        "objectclass: top",
+        "objectclass: ds-cfg-branch",
+        "cn: test-parents"
+    };
+    TestCaseUtils.addEntry(entry);
+
+    // Make sure that the relation entry exist.
+    DN relationDN = DN.decode("cn=test parents,cn=config");
+    ConfigEntry configEntry = DirectoryServer.getConfigEntry(relationDN);
+    assertNotNull(configEntry, "Relation entry " + relationDN
+        + " does not exist");
+
+    // Check the add listener is registered.
+    boolean isFound = false;
+    for (ConfigDeleteListener l : configEntry.getDeleteListeners()) {
+      if (l instanceof ConfigDeleteListenerAdaptor) {
+        ConfigDeleteListenerAdaptor al = (ConfigDeleteListenerAdaptor) l;
+        if (al.getConfigurationDeleteListener() == listener) {
+          isFound = true;
+
+          // Clean up.
+          configEntry.deregisterDeleteListener(al);
+        }
+      }
+    }
+
+    if (!isFound) {
+      fail("Unable to locate listener adaptor in entry " + relationDN);
+    }
+
+    // Remove the test entry.
+    InternalClientConnection conn = InternalClientConnection
+        .getRootConnection();
+    DeleteOperation deleteOperation = conn.processDelete(relationDN);
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+  }
+
+
+
+  /**
+   * Checks that a ConfigDeleteListenerAdaptor is registered for
+   * optional relations.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test
+  public void testConfigDeleteListenerAdaptorOptional() throws Exception {
+    ServerManagementContext ctx = ServerManagementContext.getInstance();
+    ServerManagedObject<RootCfg> root = ctx.getRootConfigurationManagedObject();
+    ConfigurationDeleteListener<TestParentCfg> listener = new TestParentDeleteListener();
+    root.registerDeleteListener(TestCfg.RD_TEST_ONE_TO_ZERO_OR_ONE_PARENT,
+        listener);
+
+    // Make sure that the relation entry exists.
+    DN relationDN = DN.decode("cn=config");
+    ConfigEntry configEntry = DirectoryServer.getConfigEntry(relationDN);
+    assertNotNull(configEntry, "Relation entry " + relationDN
+        + " does not exist");
+
+    // Check the add listener is registered.
+    boolean isFound = false;
+    for (ConfigDeleteListener l : configEntry.getDeleteListeners()) {
+      if (l instanceof ConfigDeleteListenerAdaptor) {
+        ConfigDeleteListenerAdaptor al = (ConfigDeleteListenerAdaptor) l;
+        if (al.getConfigurationDeleteListener() == listener) {
+          isFound = true;
+
+          // Clean up.
+          configEntry.deregisterDeleteListener(al);
+        }
+      }
+    }
+
+    if (!isFound) {
+      fail("Unable to locate listener adaptor in entry " + relationDN);
+    }
+  }
+}

--
Gitblit v1.10.0