From 22117901143acf6b4d8c449ee88fab4fe1e4baf9 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Wed, 05 Sep 2007 20:12:11 +0000
Subject: [PATCH] Partial fix for issue 1449: administration framework aggregation support

---
 opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java                            |   11 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/AggregationTest.java       |  357 +++++++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.java                  |  108 +
 opendj-sdk/opends/resource/admin/property-types.xsl                                                                 |    1 
 opendj-sdk/opends/src/server/org/opends/server/admin/PropertyValueVisitor.java                                      |   29 
 opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java                            |  174 ++
 opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java                                    |  144 ++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgClient.java                |   25 
 opendj-sdk/opends/src/server/org/opends/server/admin/ManagedObjectDefinitionI18NResource.java                       |   85 +
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildConfiguration.xml             |   24 
 opendj-sdk/opends/src/server/org/opends/server/admin/Reference.java                                                 |  245 +++++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfg.java                      |   12 
 opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java                                 |   22 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.properties           |   12 
 opendj-sdk/opends/build.xml                                                                                         |    5 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ConstraintTest.java             |   34 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java                           |  155 ++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java                   |    6 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java        |   19 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.properties            |    9 
 opendj-sdk/opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java                             |  551 +++++++++++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java        |   58 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AggregationTest.java            |  377 +++++++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DNBuilderTest.java              |    4 
 opendj-sdk/opends/src/server/org/opends/server/admin/client/spi/Driver.java                                         |   20 
 opendj-sdk/opends/resource/admin/admin.xsd                                                                          |   95 +
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ListenerTest.java               |    7 
 opendj-sdk/opends/resource/admin/property-types/aggregation.xsl                                                     |  153 +++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AggregationPropertyDefinitionTest.java |  132 ++
 opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java                             |   50 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentConfiguration.xml            |    6 
 31 files changed, 2,716 insertions(+), 214 deletions(-)

diff --git a/opendj-sdk/opends/build.xml b/opendj-sdk/opends/build.xml
index 7edae79..d3af905 100644
--- a/opendj-sdk/opends/build.xml
+++ b/opendj-sdk/opends/build.xml
@@ -1088,6 +1088,11 @@
         <path refid="quickSetup.classpath" />
       </classpath>
     </javac>
+    
+    <copy todir="${unittest.classes.dir}">
+      <fileset dir="${unittest.testng.src.dir}"
+               includes="**/*.properties" />
+    </copy>
 
     <!-- Prep the TestNG XML file -->
 
diff --git a/opendj-sdk/opends/resource/admin/admin.xsd b/opendj-sdk/opends/resource/admin/admin.xsd
index b84659b..6dbbb93 100644
--- a/opendj-sdk/opends/resource/admin/admin.xsd
+++ b/opendj-sdk/opends/resource/admin/admin.xsd
@@ -61,9 +61,9 @@
         type="tns:description-type">
         <xsd:annotation>
           <xsd:documentation>
-            The user friendly plural name of this managed object. This element
-            is optional and by default the user friendly plural name is derived
-            from the definition's plural-name attribute.
+            The user friendly plural name of this managed object. This
+            element is optional and by default the user friendly plural
+            name is derived from the definition's plural-name attribute.
           </xsd:documentation>
         </xsd:annotation>
       </xsd:element>
@@ -678,17 +678,6 @@
         </xsd:documentation>
       </xsd:annotation>
     </xsd:attribute>
-    <xsd:attribute name="aggregation" type="tns:path-type"
-      use="optional">
-      <xsd:annotation>
-        <xsd:documentation>
-          For aggregation relations, the path locating the relation
-          beneath which the referenced (aggregated) managed objects can
-          be found. If this attribute is not specified, the relation is
-          a composition by default.
-        </xsd:documentation>
-      </xsd:annotation>
-    </xsd:attribute>
     <xsd:attribute name="managed-object-name" type="tns:name-type"
       use="optional">
       <xsd:annotation>
@@ -1032,6 +1021,84 @@
       </xsd:documentation>
     </xsd:annotation>
     <xsd:choice>
+      <xsd:element name="aggregation">
+        <xsd:annotation>
+          <xsd:documentation>
+            An aggregation property names one or more managed objects
+            which are required by the managed object associated with
+            this property. An aggregation property definition takes care
+            to perform referential integrity checks: referenced managed
+            objects cannot be deleted. Nor can an aggregation reference
+            non-existent managed objects. Referential integrity checks
+            are not performed during value validation. Instead they are
+            performed when changes to the managed object are committed.
+          </xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexType>
+          <xsd:attribute name="parent-path" type="tns:path-type"
+            use="required">
+            <xsd:annotation>
+              <xsd:documentation>
+                The name of the managed object which is the parent of
+                the aggregated managed objects.
+              </xsd:documentation>
+            </xsd:annotation>
+          </xsd:attribute>
+          <xsd:attribute name="relation-name" type="tns:name-type"
+            use="required">
+            <xsd:annotation>
+              <xsd:documentation>
+                The relation in the parent managed object which contains
+                the aggregated managed objects.
+              </xsd:documentation>
+            </xsd:annotation>
+          </xsd:attribute>
+          <xsd:attribute name="managed-object-name" type="tns:name-type"
+            use="optional">
+            <xsd:annotation>
+              <xsd:documentation>
+                The type of managed object referenced by this
+                aggregation if different from this relation's name.
+              </xsd:documentation>
+            </xsd:annotation>
+          </xsd:attribute>
+          <xsd:attribute name="managed-object-package"
+            type="tns:package-type" use="optional">
+            <xsd:annotation>
+              <xsd:documentation>
+                The package containing the referenced managed object
+                definition if it is not the same as this managed
+                object's package.
+              </xsd:documentation>
+            </xsd:annotation>
+          </xsd:attribute>
+          <xsd:attribute name="source-enabled-property-name"
+            type="tns:name-type" use="optional">
+            <xsd:annotation>
+              <xsd:documentation>
+                The optional boolean "enabled" property in the
+                aggregating managed object. When this property is true,
+                the "target-enabled-property-name" in the aggregated
+                managed objects must also be true. The
+                "target-enabled-property-name" attribute must be
+                specified when this attribute is defined.
+              </xsd:documentation>
+            </xsd:annotation>
+          </xsd:attribute>
+          <xsd:attribute name="target-enabled-property-name"
+            type="tns:name-type" use="optional">
+            <xsd:annotation>
+              <xsd:documentation>
+                The optional boolean "enabled" property in the
+                aggregated managed objects. This property must not be
+                false while the aggregated managed object is referenced.
+                This attribute must be defined when the
+                "source-enabled-property-name" attribute is specified.
+              </xsd:documentation>
+            </xsd:annotation>
+          </xsd:attribute>
+        </xsd:complexType>
+      </xsd:element>
       <xsd:element name="attribute-type">
         <xsd:annotation>
           <xsd:documentation>
diff --git a/opendj-sdk/opends/resource/admin/property-types.xsl b/opendj-sdk/opends/resource/admin/property-types.xsl
index 69f94d0..760dc2e 100644
--- a/opendj-sdk/opends/resource/admin/property-types.xsl
+++ b/opendj-sdk/opends/resource/admin/property-types.xsl
@@ -39,6 +39,7 @@
     
     
   -->
+  <xsl:include href="property-types/aggregation.xsl" />
   <xsl:include href="property-types/attribute-type.xsl" />
   <xsl:include href="property-types/boolean.xsl" />
   <xsl:include href="property-types/dn.xsl" />
diff --git a/opendj-sdk/opends/resource/admin/property-types/aggregation.xsl b/opendj-sdk/opends/resource/admin/property-types/aggregation.xsl
new file mode 100644
index 0000000..158609c
--- /dev/null
+++ b/opendj-sdk/opends/resource/admin/property-types/aggregation.xsl
@@ -0,0 +1,153 @@
+<!--
+  ! 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.
+  ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <!-- 
+    Templates for processing aggregation properties.
+  -->
+  <xsl:template match="adm:aggregation" mode="java-definition-imports">
+    <xsl:element name="import">
+      <xsl:call-template name="get-definition-package" />
+      <xsl:value-of select="'.client.'" />
+      <xsl:call-template name="get-client-type" />
+    </xsl:element>
+    <xsl:element name="import">
+      <xsl:call-template name="get-definition-package" />
+      <xsl:value-of select="'.server.'" />
+      <xsl:call-template name="get-server-type" />
+    </xsl:element>
+    <xsl:element name="import">
+      <xsl:call-template name="get-definition-package" />
+      <xsl:value-of select="'.meta.'" />
+      <xsl:call-template name="get-definition-type" />
+    </xsl:element>
+    <import>org.opends.server.admin.ManagedObjectPath</import>
+  </xsl:template>
+  <xsl:template match="adm:aggregation" mode="java-value-type">
+    <xsl:value-of select="'String'" />
+  </xsl:template>
+  <xsl:template match="adm:aggregation" mode="java-definition-type">
+    <xsl:value-of select="'AggregationPropertyDefinition'" />
+  </xsl:template>
+  <xsl:template match="adm:aggregation"
+    mode="java-definition-generic-type">
+    <xsl:call-template name="get-client-type" />
+    <xsl:value-of select="', '" />
+    <xsl:call-template name="get-server-type" />
+  </xsl:template>
+  <xsl:template match="adm:aggregation" mode="java-definition-ctor">
+    <xsl:if test="not(@parent-path)">
+      <xsl:message terminate="yes">
+        <xsl:value-of
+          select="concat('No parent-path defined for aggregation property ', ../../@name)" />
+      </xsl:message>
+    </xsl:if>
+    <xsl:if test="not(@relation-name)">
+      <xsl:message terminate="yes">
+        <xsl:value-of
+          select="concat('No relation-name defined for aggregation property ', ../../@name)" />
+      </xsl:message>
+    </xsl:if>
+    <xsl:if
+      test="@source-enabled-property-name and not(@target-enabled-property-name)">
+      <xsl:message terminate="yes">
+        <xsl:value-of
+          select="concat('source-enabled-property-name defined but target-enabled-property-name undefined in aggregation property ', ../../@name)" />
+      </xsl:message>
+    </xsl:if>
+    <xsl:value-of
+      select="concat('      builder.setParentPath(ManagedObjectPath.valueOf(&quot;',
+                     normalize-space(@parent-path), '&quot;));&#xa;')" />
+    <xsl:value-of
+      select="concat('      builder.setRelationDefinition(&quot;',
+                     normalize-space(@relation-name), '&quot;);&#xa;')" />
+    <xsl:value-of select="'      builder.setManagedObjectDefinition('" />
+    <xsl:call-template name="get-definition-type" />
+    <xsl:value-of select="'.getInstance());&#xa;'" />
+    <xsl:if test="@source-enabled-property-name">
+      <xsl:value-of
+        select="concat('      builder.setSourceEnabledPropertyName(&quot;',
+                       normalize-space(@source-enabled-property-name), '&quot;);&#xa;')" />
+    </xsl:if>
+    <xsl:if test="@target-enabled-property-name">
+      <xsl:value-of
+        select="concat('      builder.setTargetEnabledPropertyName(&quot;',
+                       normalize-space(@target-enabled-property-name), '&quot;);&#xa;')" />
+    </xsl:if>
+  </xsl:template>
+  <!--
+    Gets the Java client configuration interface for the referenced type.
+  -->
+  <xsl:template name="get-client-type">
+    <xsl:call-template name="get-reference-type" />
+    <xsl:value-of select="'CfgClient'" />
+  </xsl:template>
+  <!--
+    Gets the Java server configuration interface for the referenced type.
+  -->
+  <xsl:template name="get-server-type">
+    <xsl:call-template name="get-reference-type" />
+    <xsl:value-of select="'Cfg'" />
+  </xsl:template>
+  <!--
+    Gets the Java definition configuration interface for the referenced type.
+  -->
+  <xsl:template name="get-definition-type">
+    <xsl:call-template name="get-reference-type" />
+    <xsl:value-of select="'CfgDefn'" />
+  </xsl:template>
+  <!--
+    Gets the Java definition configuration package.
+  -->
+  <xsl:template name="get-definition-package">
+    <xsl:choose>
+      <xsl:when test="@managed-object-package">
+        <xsl:value-of select="@managed-object-package" />
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="$this-package" />
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  <!--
+    Gets the Java name for the referenced type.
+  -->
+  <xsl:template name="get-reference-type">
+    <xsl:choose>
+      <xsl:when test="@managed-object-name">
+        <xsl:call-template name="name-to-java">
+          <xsl:with-param name="value" select="@managed-object-name" />
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:call-template name="name-to-java">
+          <xsl:with-param name="value" select="@relation-name" />
+        </xsl:call-template>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+</xsl:stylesheet>
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java b/opendj-sdk/opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java
new file mode 100644
index 0000000..56bbccc
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java
@@ -0,0 +1,551 @@
+/*
+ * 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 static org.opends.server.util.Validator.*;
+
+import java.util.EnumSet;
+
+import org.opends.server.types.DN;
+
+
+
+/**
+ * Aggregation property definition.
+ * <p>
+ * An aggregation property names one or more managed objects which are
+ * required by the managed object associated with this property. An
+ * aggregation property definition takes care to perform referential
+ * integrity checks: referenced managed objects cannot be deleted. Nor
+ * can an aggregation reference non-existent managed objects.
+ * Referential integrity checks are <b>not</b> performed during value
+ * validation. Instead they are performed when changes to the managed
+ * object are committed.
+ * <p>
+ * An aggregation property definition can optionally identify two
+ * properties:
+ * <ul>
+ * <li>an <code>enabled</code> property in the aggregated managed
+ * object - the property must be a {@link BooleanPropertyDefinition}
+ * and indicate whether the aggregated managed object is enabled or
+ * not. If specified, the administration framework will prevent the
+ * aggregated managed object from being disabled while it is
+ * referenced
+ * <li>an <code>enabled</code> property in this property's managed
+ * object - the property must be a {@link BooleanPropertyDefinition}
+ * and indicate whether this property's managed object is enabled or
+ * not. If specified, and as long as there is an equivalent
+ * <code>enabled</code> property defined for the aggregated managed
+ * object, the <code>enabled</code> property in the aggregated
+ * managed object will only be checked when this property is true.
+ * </ul>
+ * In other words, these properties can be used to make sure that
+ * referenced managed objects are not disabled while they are
+ * referenced.
+ *
+ * @param <C>
+ *          The type of client managed object configuration that this
+ *          aggregation property definition refers to.
+ * @param <S>
+ *          The type of server managed object configuration that this
+ *          aggregation property definition refers to.
+ */
+public final class AggregationPropertyDefinition
+    <C extends ConfigurationClient, S extends Configuration>
+    extends PropertyDefinition<String> {
+
+  /**
+   * An interface for incrementally constructing aggregation property
+   * definitions.
+   *
+   * @param <C>
+   *          The type of client managed object configuration that
+   *          this aggregation property definition refers to.
+   * @param <S>
+   *          The type of server managed object configuration that
+   *          this aggregation property definition refers to.
+   */
+  public static class Builder
+      <C extends ConfigurationClient, S extends Configuration>
+      extends AbstractBuilder<String, AggregationPropertyDefinition<C, S>> {
+
+    // The name of the managed object which is the parent of the
+    // aggregated managed objects.
+    private ManagedObjectPath<?, ?> p = null;
+
+    // The name of a relation in the parent managed object which
+    // contains the aggregated managed objects.
+    private String rdName = null;
+
+    // The type of referenced managed objects.
+    private AbstractManagedObjectDefinition<?, ?> cd = null;
+
+    // The optional name of a boolean "enabled" property in this
+    // managed object. When this property is true, the enabled
+    // property in the aggregated managed object must also be true.
+    private String sourceEnabledPropertyName = null;
+
+    // The optional name of a boolean "enabled" property in the
+    // aggregated managed object. This property must not be false
+    // while the aggregated managed object is referenced.
+    private String targetEnabledPropertyName = null;
+
+
+
+    // Private constructor
+    private Builder(AbstractManagedObjectDefinition<?, ?> d,
+        String propertyName) {
+      super(d, propertyName);
+    }
+
+
+
+    /**
+     * Sets the name of the managed object which is the parent of the
+     * aggregated managed objects.
+     * <p>
+     * This must be defined before the property definition can be
+     * built.
+     *
+     * @param p
+     *          The name of the managed object which is the parent of
+     *          the aggregated managed objects.
+     */
+    public final void setParentPath(ManagedObjectPath<?, ?> p) {
+      this.p = p;
+    }
+
+
+
+    /**
+     * Sets the relation in the parent managed object which contains
+     * the aggregated managed objects.
+     * <p>
+     * This must be defined before the property definition can be
+     * built.
+     *
+     * @param rdName
+     *          The name of a relation in the parent managed object
+     *          which contains the aggregated managed objects.
+     */
+    public final void setRelationDefinition(String rdName) {
+      this.rdName = rdName;
+    }
+
+
+
+    /**
+     * Sets the definition of the type of referenced managed objects.
+     * <p>
+     * This must be defined before the property definition can be
+     * built.
+     *
+     * @param d
+     *          The definition of the type of referenced managed
+     *          objects.
+     */
+    public final void setManagedObjectDefinition(
+        AbstractManagedObjectDefinition<C, S> d) {
+      this.cd = d;
+    }
+
+
+
+    /**
+     * Sets the optional boolean "enabled" property in this managed
+     * object. When this property is true, the enabled property in the
+     * aggregated managed object must also be true.
+     * <p>
+     * By default no source property is defined. When it is defined,
+     * the target property must also be defined.
+     *
+     * @param sourceEnabledPropertyName
+     *          The optional boolean "enabled" property in this
+     *          managed object.
+     */
+    public final void setSourceEnabledPropertyName(
+        String sourceEnabledPropertyName) {
+      this.sourceEnabledPropertyName = sourceEnabledPropertyName;
+    }
+
+
+
+    /**
+     * Sets the optional boolean "enabled" property in the aggregated
+     * managed object. This property must not be false while the
+     * aggregated managed object is referenced.
+     * <p>
+     * By default no target property is defined. It must be defined,
+     * if the source property is defined.
+     *
+     * @param targetEnabledPropertyName
+     *          The optional boolean "enabled" property in the
+     *          aggregated managed object.
+     */
+    public final void setTargetEnabledPropertyName(
+        String targetEnabledPropertyName) {
+      this.targetEnabledPropertyName = targetEnabledPropertyName;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    protected AggregationPropertyDefinition<C, S> buildInstance(
+        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
+        EnumSet<PropertyOption> options, AdministratorAction adminAction,
+        DefaultBehaviorProvider<String> defaultBehavior) {
+      // Make sure that the parent path has been defined.
+      if (p == null) {
+        throw new IllegalStateException("Parent path undefined");
+      }
+
+      // Make sure that the relation definition has been defined.
+      if (rdName == null) {
+        throw new IllegalStateException("Relation definition undefined");
+      }
+
+      // Make sure that the managed object definition has been
+      // defined.
+      if (cd == null) {
+        throw new IllegalStateException("Managed object definition undefined");
+      }
+
+      // Make sure that the relation definition is a member of the
+      // parent path's definition.
+      AbstractManagedObjectDefinition<?, ?> parent = p
+          .getManagedObjectDefinition();
+      RelationDefinition<?, ?> rd = parent.getRelationDefinition(rdName);
+
+      // Make sure the relation refers to the child type.
+      AbstractManagedObjectDefinition<?, ?> dTmp = rd.getChildDefinition();
+      if (dTmp != cd) {
+        throw new IllegalStateException("Relation definition \"" + rd.getName()
+            + "\" does not refer to definition " + d.getName());
+      }
+
+      // Force the relation to the correct type.
+      InstantiableRelationDefinition<C, S> relation =
+        (InstantiableRelationDefinition<C, S>) rd;
+
+      // Make sure that if a source property is specified then a
+      // target property is also specified.
+      if (sourceEnabledPropertyName != null
+          && targetEnabledPropertyName == null) {
+        throw new IllegalStateException(
+            "Source property defined but target property is undefined");
+      }
+
+      return new AggregationPropertyDefinition<C, S>(d, propertyName, options,
+          adminAction, defaultBehavior, p, relation, sourceEnabledPropertyName,
+          targetEnabledPropertyName);
+    }
+
+  }
+
+
+
+  /**
+   * Creates an aggregation property definition builder.
+   *
+   * @param <C>
+   *          The type of client managed object configuration that
+   *          this aggregation property definition refers to.
+   * @param <S>
+   *          The type of server managed object configuration that
+   *          this aggregation property definition refers to.
+   * @param d
+   *          The managed object definition associated with this
+   *          property definition.
+   * @param propertyName
+   *          The property name.
+   * @return Returns the new aggregation property definition builder.
+   */
+  public static <C extends ConfigurationClient, S extends Configuration>
+  Builder<C, S> createBuilder(
+      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
+    return new Builder<C, S>(d, propertyName);
+  }
+
+  // The name of the managed object which is the parent of the
+  // aggregated managed objects.
+  private final ManagedObjectPath<?, ?> parentPath;
+
+  // The relation in the parent managed object which contains the
+  // aggregated managed objects.
+  private final InstantiableRelationDefinition<C, S> relationDefinition;
+
+  // The optional name of a boolean "enabled" property in this managed
+  // object. When this property is true, the enabled property in the
+  // aggregated managed object must also be true.
+  private final String sourceEnabledPropertyName;
+
+  // The optional name of a boolean "enabled" property in the
+  // aggregated managed object. This property must not be false while
+  // the aggregated managed object is referenced.
+  private final String targetEnabledPropertyName;
+
+
+
+  // Private constructor.
+  private AggregationPropertyDefinition(
+      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
+      EnumSet<PropertyOption> options, AdministratorAction adminAction,
+      DefaultBehaviorProvider<String> defaultBehavior,
+      ManagedObjectPath<?, ?> parentPath,
+      InstantiableRelationDefinition<C, S> relationDefinition,
+      String sourceEnabledPropertyName, String targetEnabledPropertyName) {
+    super(d, String.class, propertyName, options, adminAction, defaultBehavior);
+
+    this.parentPath = parentPath;
+    this.relationDefinition = relationDefinition;
+    this.sourceEnabledPropertyName = sourceEnabledPropertyName;
+    this.targetEnabledPropertyName = targetEnabledPropertyName;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+    return v.visitAggregation(this, p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public <R, P> R accept(PropertyValueVisitor<R, P> v, String value, P p) {
+    return v.visitAggregation(this, value, p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String decodeValue(String value)
+      throws IllegalPropertyValueStringException {
+    ensureNotNull(value);
+
+    try {
+      validateValue(value);
+      return value;
+    } catch (IllegalPropertyValueException e) {
+      throw new IllegalPropertyValueStringException(this, value);
+    }
+  }
+
+
+
+  /**
+   * Constructs a DN for a referenced managed object having the
+   * provided name. This method is implemented by first calling
+   * {@link #getChildPath(String)} and then invoking
+   * {@link ManagedObjectPath#toDN()} on the returned path.
+   *
+   * @param name
+   *          The name of the child managed object.
+   * @return Returns a DN for a referenced managed object having the
+   *         provided name.
+   */
+  public final DN getChildDN(String name) {
+    return getChildPath(name).toDN();
+  }
+
+
+
+  /**
+   * Constructs a managed object path for a referenced managed object
+   * having the provided name.
+   *
+   * @param name
+   *          The name of the child managed object.
+   * @return Returns a managed object path for a referenced managed
+   *         object having the provided name.
+   */
+  public final ManagedObjectPath<C, S> getChildPath(String name) {
+    return parentPath.child(relationDefinition, name);
+  }
+
+
+
+  /**
+   * Gets the name of the managed object which is the parent of the
+   * aggregated managed objects.
+   *
+   * @return Returns the name of the managed object which is the
+   *         parent of the aggregated managed objects.
+   */
+  public final ManagedObjectPath<?, ?> getParentPath() {
+    return parentPath;
+  }
+
+
+
+  /**
+   * Gets the relation in the parent managed object which contains the
+   * aggregated managed objects.
+   *
+   * @return Returns the relation in the parent managed object which
+   *         contains the aggregated managed objects.
+   */
+  public final InstantiableRelationDefinition<C, S> getRelationDefinition() {
+    return relationDefinition;
+  }
+
+
+
+  /**
+   * Gets the optional boolean "enabled" property in this managed
+   * object. When this property is true, the enabled property in the
+   * aggregated managed object must also be true.
+   *
+   * @return Returns the optional boolean "enabled" property in this
+   *         managed object, or <code>null</code> if none is
+   *         defined.
+   * @throws IllegalArgumentException
+   *           If the named property does not exist in this property's
+   *           associated managed object definition.
+   * @throws ClassCastException
+   *           If the named property does exist but is not a
+   *           {@link BooleanPropertyDefinition}.
+   */
+  public final BooleanPropertyDefinition getSourceEnabledPropertyDefinition()
+      throws IllegalArgumentException, ClassCastException {
+    if (sourceEnabledPropertyName == null) {
+      return null;
+    }
+
+    AbstractManagedObjectDefinition<?, ?> d = getManagedObjectDefinition();
+
+    PropertyDefinition<?> pd;
+    pd = d.getPropertyDefinition(sourceEnabledPropertyName);
+
+    return (BooleanPropertyDefinition) pd;
+  }
+
+
+
+  /**
+   * Gets the optional boolean "enabled" property in the aggregated
+   * managed object. This property must not be false while the
+   * aggregated managed object is referenced.
+   *
+   * @return Returns the optional boolean "enabled" property in the
+   *         aggregated managed object, or <code>null</code> if none
+   *         is defined.
+   * @throws IllegalArgumentException
+   *           If the named property does not exist in the aggregated
+   *           managed object's definition.
+   * @throws ClassCastException
+   *           If the named property does exist but is not a
+   *           {@link BooleanPropertyDefinition}.
+   */
+  public final BooleanPropertyDefinition getTargetEnabledPropertyDefinition()
+      throws IllegalArgumentException, ClassCastException {
+    if (targetEnabledPropertyName == null) {
+      return null;
+    }
+
+    AbstractManagedObjectDefinition<?, ?> d;
+    PropertyDefinition<?> pd;
+
+    d = relationDefinition.getChildDefinition();
+    pd = d.getPropertyDefinition(targetEnabledPropertyName);
+
+    return (BooleanPropertyDefinition) pd;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String normalizeValue(String value)
+      throws IllegalPropertyValueException {
+    try {
+      Reference<C, S> reference = Reference.parseName(parentPath,
+          relationDefinition, value);
+      return reference.getNormalizedName();
+    } catch (IllegalArgumentException e) {
+      throw new IllegalPropertyValueException(this, value);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void toString(StringBuilder builder) {
+    super.toString(builder);
+
+    builder.append(" parentPath=");
+    builder.append(parentPath);
+
+    builder.append(" relationDefinition=");
+    builder.append(relationDefinition.getName());
+
+    if (sourceEnabledPropertyName != null) {
+      builder.append(" sourceEnabledPropertyName=");
+      builder.append(sourceEnabledPropertyName);
+    }
+
+    if (targetEnabledPropertyName != null) {
+      builder.append(" targetEnabledPropertyName=");
+      builder.append(targetEnabledPropertyName);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void validateValue(String value) throws IllegalPropertyValueException {
+    try {
+      Reference.parseName(parentPath, relationDefinition, value);
+    } catch (IllegalArgumentException e) {
+      throw new IllegalPropertyValueException(this, value);
+    }
+  }
+
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/ManagedObjectDefinitionI18NResource.java b/opendj-sdk/opends/src/server/org/opends/server/admin/ManagedObjectDefinitionI18NResource.java
index 4615588..2280700 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/ManagedObjectDefinitionI18NResource.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/ManagedObjectDefinitionI18NResource.java
@@ -214,6 +214,91 @@
 
 
 
+  /**
+   * Forcefully removes any resource bundles associated with the
+   * provided definition and using the default locale.
+   * <p>
+   * This method is intended for internal testing only.
+   *
+   * @param d
+   *          The managed object definition.
+   */
+  synchronized void removeResourceBundle(
+      AbstractManagedObjectDefinition<?, ?> d) {
+    removeResourceBundle(d, Locale.getDefault());
+  }
+
+
+
+  /**
+   * Forcefully removes any resource bundles associated with the
+   * provided definition and locale.
+   * <p>
+   * This method is intended for internal testing only.
+   *
+   * @param d
+   *          The managed object definition.
+   * @param locale
+   *          The locale.
+   */
+  synchronized void removeResourceBundle(
+      AbstractManagedObjectDefinition<?, ?> d, Locale locale) {
+    // Get the locale resource mapping.
+    Map<Locale, ResourceBundle> map = resources.get(d);
+    if (map != null) {
+      map.remove(locale);
+    }
+  }
+
+
+
+  /**
+   * Forcefully adds the provided resource bundle to this I18N
+   * resource for the default locale.
+   * <p>
+   * This method is intended for internal testing only.
+   *
+   * @param d
+   *          The managed object definition.
+   * @param resoureBundle
+   *          The resource bundle to be used.
+   */
+  synchronized void setResourceBundle(AbstractManagedObjectDefinition<?, ?> d,
+      ResourceBundle resoureBundle) {
+    setResourceBundle(d, Locale.getDefault(), resoureBundle);
+  }
+
+
+
+  /**
+   * Forcefully adds the provided resource bundle to this I18N
+   * resource.
+   * <p>
+   * This method is intended for internal testing only.
+   *
+   * @param d
+   *          The managed object definition.
+   * @param locale
+   *          The locale.
+   * @param resoureBundle
+   *          The resource bundle to be used.
+   */
+  synchronized void setResourceBundle(AbstractManagedObjectDefinition<?, ?> d,
+      Locale locale, ResourceBundle resoureBundle) {
+    // First get the locale-resource mapping, creating it if
+    // necessary.
+    Map<Locale, ResourceBundle> map = resources.get(d);
+    if (map == null) {
+      map = new HashMap<Locale, ResourceBundle>();
+      resources.put(d, map);
+    }
+
+    // Add the resource bundle.
+    map.put(locale, resoureBundle);
+  }
+
+
+
   // Retrieve the resource bundle associated with a managed object and
   // locale, lazily loading it if necessary.
   private synchronized ResourceBundle getResourceBundle(
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java b/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java
index 466f5a3..e1292bf 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java
@@ -72,6 +72,17 @@
      * {@inheritDoc}
      */
     @Override
+    public <C extends ConfigurationClient, S extends Configuration>
+    Message visitAggregation(AggregationPropertyDefinition<C, S> d, Void p) {
+      return Message.raw("NAME");
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     public Message visitAttributeType(AttributeTypePropertyDefinition d,
         Void p) {
       return Message.raw("OID");
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java b/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java
index 63e7c0b..34cdd89 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java
@@ -65,6 +65,28 @@
 
 
   /**
+   * Visit an aggregation property definition.
+   *
+   * @param <C>
+   *          The type of client managed object configuration that
+   *          this aggregation property definition refers to.
+   * @param <S>
+   *          The type of server managed object configuration that
+   *          this aggregation property definition refers to.
+   * @param d
+   *          The aggregation property definition to visit.
+   * @param p
+   *          A visitor specified parameter.
+   * @return Returns a visitor specified result.
+   */
+  public <C extends ConfigurationClient, S extends Configuration>
+  R visitAggregation(AggregationPropertyDefinition<C, S> d, P p) {
+    return visitUnknown(d, p);
+  }
+
+
+
+  /**
    * Visit an attribute type property definition.
    *
    * @param d
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyValueVisitor.java b/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyValueVisitor.java
index 43038e8..27d5584 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyValueVisitor.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/PropertyValueVisitor.java
@@ -73,6 +73,31 @@
 
 
   /**
+   * Visit an aggregation property value.
+   *
+   * @param <C>
+   *          The type of client managed object configuration that
+   *          this aggregation property definition refers to.
+   * @param <S>
+   *          The type of server managed object configuration that
+   *          this aggregation property definition refers to.
+   * @param d
+   *          The aggregation property definition to visit.
+   * @param v
+   *          The property value to visit.
+   * @param p
+   *          A visitor specified parameter.
+   * @return Returns a visitor specified result.
+   */
+  public <C extends ConfigurationClient, S extends Configuration>
+  R visitAggregation(
+      AggregationPropertyDefinition<C, S> d, String v, P p) {
+    return visitUnknown(d, v, p);
+  }
+
+
+
+  /**
    * Visit an attribute type.
    *
    * @param d
@@ -172,8 +197,8 @@
    *          A visitor specified parameter.
    * @return Returns a visitor specified result.
    */
-  public <E extends Enum<E>> R visitEnum(
-      EnumPropertyDefinition<E> d, E v, P p) {
+  public <E extends Enum<E>>
+  R visitEnum(EnumPropertyDefinition<E> d, E v, P p) {
     return visitUnknown(d, v, p);
   }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/Reference.java b/opendj-sdk/opends/src/server/org/opends/server/admin/Reference.java
new file mode 100644
index 0000000..3792a26
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/Reference.java
@@ -0,0 +1,245 @@
+/*
+ * 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.types.AttributeValue;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.RDN;
+import org.opends.server.util.StaticUtils;
+
+
+
+/**
+ * A reference to another managed object.
+ *
+ * @param <C>
+ *          The type of client managed object configuration that this
+ *          reference refers to.
+ * @param <S>
+ *          The type of server managed object configuration that this
+ *          reference refers to.
+ */
+public final class Reference<C extends ConfigurationClient,
+                             S extends Configuration> {
+
+  /**
+   * Parses a DN string value as a reference using the provided
+   * managed object path and relation definition.
+   *
+   * @param <C>
+   *          The type of client managed object configuration that
+   *          this reference refers to.
+   * @param <S>
+   *          The type of server managed object configuration that
+   *          this reference refers to.
+   * @param p
+   *          The path of the referenced managed object's parent.
+   * @param rd
+   *          The instantiable relation in the parent which contains
+   *          the referenced managed object.
+   * @param s
+   *          The DN string value.
+   * @return Returns the new reference based on the provided DN string
+   *         value.
+   * @throws IllegalArgumentException
+   *           If the DN string value could not be decoded as a DN or
+   *           if the provided DN did not correspond to the provided
+   *           path and relation.
+   */
+  public static <C extends ConfigurationClient, S extends Configuration>
+  Reference<C, S> parseDN(
+      ManagedObjectPath<?, ?> p, InstantiableRelationDefinition<C, S> rd,
+      String s) throws IllegalArgumentException {
+    AbstractManagedObjectDefinition<?, ?> d = p.getManagedObjectDefinition();
+    RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName());
+    if (tmp != rd) {
+      throw new IllegalArgumentException("The relation \"" + rd.getName()
+          + "\" is not associated with the definition \"" + d.getName() + "\"");
+    }
+
+    DN dn;
+    try {
+      dn = DN.decode(s);
+    } catch (DirectoryException e) {
+      throw new IllegalArgumentException("Unabled to decode the DN string: \""
+          + s + "\"");
+    }
+
+    RDN rdn = dn.getRDN();
+    if (rdn == null) {
+      throw new IllegalArgumentException("Unabled to decode the DN string: \""
+          + s + "\"");
+    }
+
+    AttributeValue av = rdn.getAttributeValue(0);
+    if (av == null) {
+      throw new IllegalArgumentException("Unabled to decode the DN string: \""
+          + s + "\"");
+    }
+
+    String name = av.getStringValue();
+
+    // Check that the DN was valid.
+    DN expected = p.child(rd, name).toDN();
+    if (!dn.equals(expected)) {
+      throw new IllegalArgumentException("Unabled to decode the DN string: \""
+          + s + "\"");
+    }
+
+    return new Reference<C, S>(p, rd, name);
+  }
+
+
+
+  /**
+   * Parses a name as a reference using the provided managed object
+   * path and relation definition.
+   *
+   * @param <C>
+   *          The type of client managed object configuration that
+   *          this reference refers to.
+   * @param <S>
+   *          The type of server managed object configuration that
+   *          this reference refers to.
+   * @param p
+   *          The path of the referenced managed object's parent.
+   * @param rd
+   *          The instantiable relation in the parent which contains
+   *          the referenced managed object.
+   * @param s
+   *          The name of the referenced managed object.
+   * @return Returns the new reference based on the provided name.
+   * @throws IllegalArgumentException
+   *           If the relation is not associated with the provided
+   *           parent's definition, or if the provided name is empty.
+   */
+  public static <C extends ConfigurationClient, S extends Configuration>
+  Reference<C, S> parseName(
+      ManagedObjectPath<?, ?> p, InstantiableRelationDefinition<C, S> rd,
+      String s) throws IllegalArgumentException {
+    // Sanity checks.
+    AbstractManagedObjectDefinition<?, ?> d = p.getManagedObjectDefinition();
+    RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName());
+    if (tmp != rd) {
+      throw new IllegalArgumentException("The relation \"" + rd.getName()
+          + "\" is not associated with the definition \"" + d.getName() + "\"");
+    }
+
+    if (s.trim().length() == 0) {
+      throw new IllegalArgumentException("Empty names are not allowed");
+    }
+
+    return new Reference<C, S>(p, rd, s);
+  }
+
+  // The name of the referenced managed object.
+  private final String name;
+
+  // The path of the referenced managed object.
+  private final ManagedObjectPath<C, S> path;
+
+  // The instantiable relation in the parent which contains the
+  // referenced managed object.
+  private final InstantiableRelationDefinition<C, S> relation;
+
+
+
+  // Private constructor.
+  private Reference(ManagedObjectPath<?, ?> parent,
+      InstantiableRelationDefinition<C, S> relation, String name)
+      throws IllegalArgumentException {
+    this.relation = relation;
+    this.name = name;
+    this.path = parent.child(relation, name);
+  }
+
+
+
+  /**
+   * Gets the name of the referenced managed object.
+   *
+   * @return Returns the name of the referenced managed object.
+   */
+  public String getName() {
+    return name;
+  }
+
+
+
+  /**
+   * Gets the normalized name of the referenced managed object.
+   *
+   * @return Returns the normalized name of the referenced managed
+   *         object.
+   */
+  public String getNormalizedName() {
+    PropertyDefinition<?> pd = relation.getNamingPropertyDefinition();
+    return normalizeName(pd);
+  }
+
+
+
+  /**
+   * Gets the DN of the referenced managed object.
+   *
+   * @return Returns the DN of the referenced managed object.
+   */
+  public DN toDN() {
+    return path.toDN();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String toString() {
+    return name;
+  }
+
+
+
+  // Normalize a value using the specified naming property definition
+  // if defined.
+  private <T> String normalizeName(PropertyDefinition<T> pd) {
+    if (pd != null) {
+      try {
+        T tvalue = pd.decodeValue(name);
+        return pd.normalizeValue(tvalue);
+      } catch (IllegalPropertyValueStringException e) {
+        // Fall through to default normalization.
+      }
+    }
+
+    // FIXME: should really use directory string normalizer.
+    String s = name.trim().replaceAll(" +", " ");
+    return StaticUtils.toLowerCase(s);
+  }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java b/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java
index eaa99ab..668d495 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java
@@ -49,6 +49,7 @@
 
 import org.opends.messages.Message;
 import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.AggregationPropertyDefinition;
 import org.opends.server.admin.Configuration;
 import org.opends.server.admin.ConfigurationClient;
 import org.opends.server.admin.DefaultBehaviorException;
@@ -61,11 +62,14 @@
 import org.opends.server.admin.ManagedObjectNotFoundException;
 import org.opends.server.admin.ManagedObjectPath;
 import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyDefinitionVisitor;
 import org.opends.server.admin.PropertyException;
 import org.opends.server.admin.PropertyIsMandatoryException;
 import org.opends.server.admin.PropertyIsSingleValuedException;
 import org.opends.server.admin.PropertyOption;
+import org.opends.server.admin.Reference;
 import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.UnknownPropertyDefinitionException;
 import org.opends.server.admin.DefinitionDecodingException.Reason;
 import org.opends.server.admin.client.AuthorizationException;
 import org.opends.server.admin.client.CommunicationException;
@@ -84,6 +88,73 @@
  */
 final class LDAPDriver extends Driver {
 
+  /**
+   * A visitor which is used to decode property LDAP values.
+   */
+  private static final class ValueDecoder extends
+      PropertyDefinitionVisitor<Object, String> {
+
+    /**
+     * Decodes the provided property LDAP value.
+     *
+     * @param <PD>
+     *          The type of the property.
+     * @param pd
+     *          The property definition.
+     * @param value
+     *          The LDAP string representation.
+     * @return Returns the decoded LDAP value.
+     * @throws IllegalPropertyValueStringException
+     *           If the property value could not be decoded because it
+     *           was invalid.
+     */
+    public static <PD> PD decode(PropertyDefinition<PD> pd, Object value)
+        throws IllegalPropertyValueStringException {
+      String s = String.valueOf(value);
+      return pd.castValue(pd.accept(new ValueDecoder(), s));
+    }
+
+
+
+    // Prevent instantiation.
+    private ValueDecoder() {
+      // No implementation required.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <C extends ConfigurationClient, S extends Configuration>
+    Object visitAggregation(AggregationPropertyDefinition<C, S> d, String p) {
+      // Aggregations values are stored as full DNs in LDAP, but
+      // just their common name is exposed in the admin framework.
+      try {
+        Reference<C, S> reference = Reference.parseDN(d.getParentPath(), d
+            .getRelationDefinition(), p);
+        return reference.getName();
+      } catch (IllegalArgumentException e) {
+        throw new IllegalPropertyValueStringException(d, p);
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <T> Object visitUnknown(PropertyDefinition<T> d, String p)
+        throws UnknownPropertyDefinitionException {
+      // By default the property definition's decoder will do.
+      return d.decodeValue(p);
+    }
+  }
+
+
+
   // The LDAP connection.
   private final LDAPConnection connection;
 
@@ -151,20 +222,8 @@
       for (PropertyDefinition<?> pd : mod.getAllPropertyDefinitions()) {
         String attrID = profile.getAttributeName(mod, pd);
         Attribute attribute = attributes.get(attrID);
-        List<String> values = new LinkedList<String>();
-
-        if (attribute != null && attribute.size() != 0) {
-          NamingEnumeration<?> ldapValues = attribute.getAll();
-          while (ldapValues.hasMore()) {
-            Object obj = ldapValues.next();
-            if (obj != null) {
-              values.add(obj.toString());
-            }
-          }
-        }
-
         try {
-          decodeProperty(newProperties, path, pd, values);
+          decodeProperty(newProperties, path, pd, attribute);
         } catch (PropertyException e) {
           exceptions.add(e);
         }
@@ -193,12 +252,23 @@
   /**
    * {@inheritDoc}
    */
+  @SuppressWarnings("unchecked")
   @Override
-  public <PD> SortedSet<PD> getPropertyValues(ManagedObjectPath<?, ?> path,
+  public <C extends ConfigurationClient, S extends Configuration, PD>
+  SortedSet<PD> getPropertyValues(ManagedObjectPath<C, S> path,
       PropertyDefinition<PD> pd) throws IllegalArgumentException,
       DefinitionDecodingException, AuthorizationException,
       ManagedObjectNotFoundException, CommunicationException,
       PropertyException {
+    // Check that the requested property is from the definition
+    // associated with the path.
+    AbstractManagedObjectDefinition<C, S> d = path.getManagedObjectDefinition();
+    PropertyDefinition<?> tmp = d.getPropertyDefinition(pd.getName());
+    if (tmp != pd) {
+      throw new IllegalArgumentException("The property " + pd.getName()
+          + " is not associated with a " + d.getName());
+    }
+
     if (!managedObjectExists(path)) {
       throw new ManagedObjectNotFoundException();
     }
@@ -206,26 +276,27 @@
     try {
       // Read the entry associated with the managed object.
       LdapName dn = LDAPNameBuilder.create(path, profile);
-      AbstractManagedObjectDefinition<?, ?> d = path
-          .getManagedObjectDefinition();
-      ManagedObjectDefinition<?, ?> mod = getEntryDefinition(d, dn);
+      ManagedObjectDefinition<? extends C, ? extends S> mod;
+      mod = getEntryDefinition(d, dn);
+
+      // Make sure we use the correct property definition, the
+      // provided one might have been overridden in the resolved
+      // definition.
+      pd = (PropertyDefinition<PD>) mod.getPropertyDefinition(pd.getName());
 
       String attrID = profile.getAttributeName(mod, pd);
       Attributes attributes = connection.readEntry(dn, Collections
           .singleton(attrID));
       Attribute attribute = attributes.get(attrID);
 
+      // Decode the values.
       SortedSet<PD> values = new TreeSet<PD>(pd);
-      if (attribute == null || attribute.size() == 0) {
-        // Use the property's default values.
-        values.addAll(findDefaultValues(path, pd, false));
-      } else {
-        // Decode the values.
+      if (attribute != null) {
         NamingEnumeration<?> ldapValues = attribute.getAll();
         while (ldapValues.hasMore()) {
           Object obj = ldapValues.next();
           if (obj != null) {
-            PD value = pd.decodeValue(obj.toString());
+            PD value = ValueDecoder.decode(pd, obj);
             values.add(value);
           }
         }
@@ -240,6 +311,11 @@
         throw new PropertyIsMandatoryException(pd);
       }
 
+      if (values.isEmpty()) {
+        // Use the property's default values.
+        values.addAll(findDefaultValues(path.asSubType(mod), pd, false));
+      }
+
       return values;
     } catch (NameNotFoundException e) {
       throw new ManagedObjectNotFoundException();
@@ -471,24 +547,28 @@
 
   // Create a property using the provided string values.
   private <PD> void decodeProperty(PropertySet newProperties,
-      ManagedObjectPath<?, ?> p, PropertyDefinition<PD> pd, List<String> values)
-      throws PropertyException {
+      ManagedObjectPath<?, ?> p, PropertyDefinition<PD> pd,
+      Attribute attribute) throws PropertyException,
+      NamingException {
     PropertyException exception = null;
 
     // Get the property's active values.
-    Collection<PD> activeValues = new ArrayList<PD>(values.size());
-    for (String value : values) {
-      try {
-        activeValues.add(pd.decodeValue(value));
-      } catch (IllegalPropertyValueStringException e) {
-        exception = e;
+    SortedSet<PD> activeValues = new TreeSet<PD>(pd);
+    if (attribute != null) {
+      NamingEnumeration<?> ldapValues = attribute.getAll();
+      while (ldapValues.hasMore()) {
+        Object obj = ldapValues.next();
+        if (obj != null) {
+          PD value = ValueDecoder.decode(pd, obj);
+          activeValues.add(value);
+        }
       }
     }
 
     if (activeValues.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) {
       // This exception takes precedence over previous exceptions.
       exception = new PropertyIsSingleValuedException(pd);
-      PD value = activeValues.iterator().next();
+      PD value = activeValues.first();
       activeValues.clear();
       activeValues.add(value);
     }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java b/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
index 7b60e04..ec2f65e 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
@@ -41,6 +41,7 @@
 import javax.naming.ldap.Rdn;
 
 import org.opends.messages.Message;
+import org.opends.server.admin.AggregationPropertyDefinition;
 import org.opends.server.admin.Configuration;
 import org.opends.server.admin.ConfigurationClient;
 import org.opends.server.admin.InstantiableRelationDefinition;
@@ -50,7 +51,10 @@
 import org.opends.server.admin.ManagedObjectPath;
 import org.opends.server.admin.PropertyDefinition;
 import org.opends.server.admin.PropertyOption;
+import org.opends.server.admin.PropertyValueVisitor;
+import org.opends.server.admin.Reference;
 import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.UnknownPropertyDefinitionException;
 import org.opends.server.admin.client.AuthorizationException;
 import org.opends.server.admin.client.CommunicationException;
 import org.opends.server.admin.client.ConcurrentModificationException;
@@ -73,6 +77,47 @@
 final class LDAPManagedObject<T extends ConfigurationClient> extends
     AbstractManagedObject<T> {
 
+  /**
+   * A visitor which is used to encode property LDAP values.
+   */
+  private static final class ValueEncoder extends
+      PropertyValueVisitor<Object, Void> {
+
+    // Prevent instantiation.
+    private ValueEncoder() {
+      // No implementation required.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <C extends ConfigurationClient, S extends Configuration>
+    Object visitAggregation(
+        AggregationPropertyDefinition<C, S> d, String v, Void p) {
+      // Aggregations values are stored as full DNs in LDAP, but
+      // just their common name is exposed in the admin framework.
+      Reference<C, S> reference = Reference.parseName(d.getParentPath(), d
+          .getRelationDefinition(), v);
+      return reference.toDN().toString();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <PD> Object visitUnknown(PropertyDefinition<PD> d, PD v, Void p)
+        throws UnknownPropertyDefinitionException {
+      return d.encodeValue(v);
+    }
+  }
+
+
+
   // The LDAP management driver associated with this managed object.
   private final LDAPDriver driver;
 
@@ -294,17 +339,18 @@
   // Encode a property into LDAP string values.
   private <PD> void encodeProperty(Attribute attribute,
       PropertyDefinition<PD> pd) {
+    PropertyValueVisitor<Object, Void> visitor = new ValueEncoder();
     Property<PD> p = getProperty(pd);
     if (pd.hasOption(PropertyOption.MANDATORY)) {
       // For mandatory properties we fall-back to the default values
       // if defined which can sometimes be the case e.g when a
       // mandatory property is overridden.
       for (PD value : p.getEffectiveValues()) {
-        attribute.add(pd.encodeValue(value));
+        attribute.add(pd.accept(visitor, value, null));
       }
     } else {
       for (PD value : p.getPendingValues()) {
-        attribute.add(pd.encodeValue(value));
+        attribute.add(pd.accept(visitor, value, null));
       }
     }
   }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/client/spi/Driver.java b/opendj-sdk/opends/src/server/org/opends/server/admin/client/spi/Driver.java
index c39601d..e7b0a19 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/client/spi/Driver.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/client/spi/Driver.java
@@ -430,6 +430,12 @@
    * Gets the effective value of a property in the named managed
    * object.
    *
+   * @param <C>
+   *          The type of client managed object configuration that the
+   *          path definition refers to.
+   * @param <S>
+   *          The type of server managed object configuration that the
+   *          path definition refers to.
    * @param <PD>
    *          The type of the property to be retrieved.
    * @param path
@@ -458,7 +464,8 @@
    *           If the client cannot contact the server due to an
    *           underlying communication problem.
    */
-  public final <PD> PD getPropertyValue(ManagedObjectPath<?, ?> path,
+  public final <C extends ConfigurationClient, S extends Configuration, PD>
+  PD getPropertyValue(ManagedObjectPath<C, S> path,
       PropertyDefinition<PD> pd) throws IllegalArgumentException,
       DefinitionDecodingException, AuthorizationException,
       ManagedObjectNotFoundException, CommunicationException,
@@ -486,6 +493,12 @@
    * managed object contains a property which inherits default values
    * from another property in the same managed object.
    *
+   * @param <C>
+   *          The type of client managed object configuration that the
+   *          path definition refers to.
+   * @param <S>
+   *          The type of server managed object configuration that the
+   *          path definition refers to.
    * @param <PD>
    *          The type of the property to be retrieved.
    * @param path
@@ -514,8 +527,9 @@
    *           If the client cannot contact the server due to an
    *           underlying communication problem.
    */
-  public abstract <PD> SortedSet<PD> getPropertyValues(
-      ManagedObjectPath<?, ?> path, PropertyDefinition<PD> pd)
+  public abstract <C extends ConfigurationClient, S extends Configuration, PD>
+  SortedSet<PD> getPropertyValues(
+      ManagedObjectPath<C, S> path, PropertyDefinition<PD> pd)
       throws IllegalArgumentException, DefinitionDecodingException,
       AuthorizationException, ManagedObjectNotFoundException,
       CommunicationException, PropertyException;
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java
index ea2f943..a8d3391 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java
@@ -47,6 +47,7 @@
 import org.opends.messages.Message;
 import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
 import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.AggregationPropertyDefinition;
 import org.opends.server.admin.AliasDefaultBehaviorProvider;
 import org.opends.server.admin.Configuration;
 import org.opends.server.admin.ConfigurationClient;
@@ -62,14 +63,17 @@
 import org.opends.server.admin.ManagedObjectDefinition;
 import org.opends.server.admin.ManagedObjectPath;
 import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyDefinitionVisitor;
 import org.opends.server.admin.PropertyException;
 import org.opends.server.admin.PropertyIsMandatoryException;
 import org.opends.server.admin.PropertyIsSingleValuedException;
 import org.opends.server.admin.PropertyNotFoundException;
 import org.opends.server.admin.PropertyOption;
+import org.opends.server.admin.Reference;
 import org.opends.server.admin.RelationDefinition;
 import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider;
 import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
+import org.opends.server.admin.UnknownPropertyDefinitionException;
 import org.opends.server.admin.DefinitionDecodingException.Reason;
 import org.opends.server.admin.std.meta.RootCfgDefn;
 import org.opends.server.admin.std.server.RootCfg;
@@ -263,22 +267,22 @@
           throw new PropertyNotFoundException(propertyName);
         }
 
-        List<String> stringValues = getAttribute(mod, pd2, configEntry);
-        if (stringValues.isEmpty()) {
+        List<AttributeValue> values = getAttribute(mod, pd2, configEntry);
+        if (values.isEmpty()) {
           // Recursively retrieve this property's default values.
           Collection<T> tmp = find(target, pd2);
-          Collection<T> values = new ArrayList<T>(tmp.size());
+          Collection<T> pvalues = new ArrayList<T>(tmp.size());
           for (T value : tmp) {
             pd1.validateValue(value);
-            values.add(value);
+            pvalues.add(value);
           }
-          return values;
+          return pvalues;
         } else {
-          Collection<T> values = new ArrayList<T>(stringValues.size());
-          for (String s : stringValues) {
-            values.add(pd1.decodeValue(s));
+          Collection<T> pvalues = new ArrayList<T>(values.size());
+          for (AttributeValue value : values) {
+            pvalues.add(ValueDecoder.decode(pd1, value));
           }
-          return values;
+          return pvalues;
         }
       } catch (DefinitionDecodingException e) {
         throw new DefaultBehaviorException(pd1, e);
@@ -321,7 +325,76 @@
       String oc = LDAPProfile.getInstance().getObjectClass(d);
       return entry.hasObjectClass(oc);
     }
-  };
+  }
+
+
+
+  /**
+   * A visitor which is used to decode property LDAP values.
+   */
+  private static final class ValueDecoder extends
+      PropertyDefinitionVisitor<Object, String> {
+
+    /**
+     * Decodes the provided property LDAP value.
+     *
+     * @param <PD>
+     *          The type of the property.
+     * @param pd
+     *          The property definition.
+     * @param value
+     *          The LDAP string representation.
+     * @return Returns the decoded LDAP value.
+     * @throws IllegalPropertyValueStringException
+     *           If the property value could not be decoded because it
+     *           was invalid.
+     */
+    public static <PD> PD decode(PropertyDefinition<PD> pd,
+        AttributeValue value) throws IllegalPropertyValueStringException {
+      String s = value.getStringValue();
+      return pd.castValue(pd.accept(new ValueDecoder(), s));
+    }
+
+
+
+    // Prevent instantiation.
+    private ValueDecoder() {
+      // No implementation required.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <C extends ConfigurationClient, S extends Configuration>
+    Object visitAggregation(AggregationPropertyDefinition<C, S> d, String p) {
+      // Aggregations values are stored as full DNs in LDAP, but
+      // just their common name is exposed in the admin framework.
+      try {
+        Reference<C, S> reference = Reference.parseDN(d.getParentPath(), d
+            .getRelationDefinition(), p);
+        return reference.getName();
+      } catch (IllegalArgumentException e) {
+        throw new IllegalPropertyValueStringException(d, p);
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <T> Object visitUnknown(PropertyDefinition<T> d, String p)
+        throws UnknownPropertyDefinitionException {
+      // By default the property definition's decoder will do.
+      return d.decodeValue(p);
+    }
+  }
+
+
 
   // Singleton instance.
   private final static ServerManagementContext INSTANCE =
@@ -399,6 +472,12 @@
    * Gets the effective value of a property in the named managed
    * object.
    *
+   * @param <C>
+   *          The type of client managed object configuration that the
+   *          path definition refers to.
+   * @param <S>
+   *          The type of server managed object configuration that the
+   *          path definition refers to.
    * @param <PD>
    *          The type of the property to be retrieved.
    * @param path
@@ -417,7 +496,8 @@
    *           If the named managed object could not be found or if it
    *           could not be decoded.
    */
-  public <PD> PD getPropertyValue(ManagedObjectPath<?, ?> path,
+  public <C extends ConfigurationClient, S extends Configuration, PD>
+  PD getPropertyValue(ManagedObjectPath<C, S> path,
       PropertyDefinition<PD> pd) throws IllegalArgumentException,
       ConfigException, PropertyException {
     SortedSet<PD> values = getPropertyValues(path, pd);
@@ -434,6 +514,12 @@
    * Gets the effective values of a property in the named managed
    * object.
    *
+   * @param <C>
+   *          The type of client managed object configuration that the
+   *          path definition refers to.
+   * @param <S>
+   *          The type of server managed object configuration that the
+   *          path definition refers to.
    * @param <PD>
    *          The type of the property to be retrieved.
    * @param path
@@ -452,15 +538,27 @@
    *           If the named managed object could not be found or if it
    *           could not be decoded.
    */
-  public <PD> SortedSet<PD> getPropertyValues(ManagedObjectPath<?, ?> path,
+  @SuppressWarnings("unchecked")
+  public <C extends ConfigurationClient, S extends Configuration, PD>
+  SortedSet<PD> getPropertyValues(ManagedObjectPath<C, S> path,
       PropertyDefinition<PD> pd) throws IllegalArgumentException,
       ConfigException, PropertyException {
+    // Check that the requested property is from the definition
+    // associated with the path.
+    AbstractManagedObjectDefinition<C, S> d = path.getManagedObjectDefinition();
+    PropertyDefinition<?> tmp = d.getPropertyDefinition(pd.getName());
+    if (tmp != pd) {
+      throw new IllegalArgumentException("The property " + pd.getName()
+          + " is not associated with a " + d.getName());
+    }
+
+    // Determine the exact type of managed object referenced by the
+    // path.
     DN dn = DNBuilder.create(path);
     ConfigEntry configEntry = getManagedObjectConfigEntry(dn);
 
     DefinitionResolver resolver = new MyDefinitionResolver(configEntry);
-    AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition();
-    ManagedObjectDefinition<?, ?> mod;
+    ManagedObjectDefinition<? extends C, ? extends S> mod;
 
     try {
       mod = d.resolveManagedObjectDefinition(resolver);
@@ -469,8 +567,13 @@
           .createDecodingExceptionAdaptor(dn, e);
     }
 
-    List<String> values = getAttribute(mod, pd, configEntry);
-    return decodeProperty(path, pd, values, null);
+    // Make sure we use the correct property definition, the
+    // provided one might have been overridden in the resolved
+    // definition.
+    pd = (PropertyDefinition<PD>) mod.getPropertyDefinition(pd.getName());
+
+    List<AttributeValue> values = getAttribute(mod, pd, configEntry);
+    return decodeProperty(path.asSubType(mod), pd, values, null);
   }
 
 
@@ -649,7 +752,7 @@
     Map<PropertyDefinition<?>, SortedSet<?>> properties =
       new HashMap<PropertyDefinition<?>, SortedSet<?>>();
     for (PropertyDefinition<?> pd : mod.getAllPropertyDefinitions()) {
-      List<String> values = getAttribute(mod, pd, configEntry);
+      List<AttributeValue> values = getAttribute(mod, pd, configEntry);
       try {
         SortedSet<?> pvalues = decodeProperty(path, pd, values, newConfigEntry);
         properties.put(pd, pvalues);
@@ -686,16 +789,16 @@
 
   // Create a property using the provided string values.
   private <T> SortedSet<T> decodeProperty(ManagedObjectPath<?, ?> path,
-      PropertyDefinition<T> pd, List<String> stringValues,
+      PropertyDefinition<T> pd, List<AttributeValue> values,
       ConfigEntry newConfigEntry) throws PropertyException {
     PropertyException exception = null;
-    SortedSet<T> values = new TreeSet<T>(pd);
+    SortedSet<T> pvalues = new TreeSet<T>(pd);
 
-    if (!stringValues.isEmpty()) {
+    if (!values.isEmpty()) {
       // The property has values defined for it.
-      for (String value : stringValues) {
+      for (AttributeValue value : values) {
         try {
-          values.add(pd.decodeValue(value));
+          pvalues.add(ValueDecoder.decode(pd, value));
         } catch (IllegalPropertyValueStringException e) {
           exception = e;
         }
@@ -703,21 +806,21 @@
     } else {
       // No values defined so get the defaults.
       try {
-        values.addAll(getDefaultValues(path, pd, newConfigEntry));
+        pvalues.addAll(getDefaultValues(path, pd, newConfigEntry));
       } catch (DefaultBehaviorException e) {
         exception = e;
       }
     }
 
-    if (values.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) {
+    if (pvalues.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) {
       // This exception takes precedence over previous exceptions.
       exception = new PropertyIsSingleValuedException(pd);
-      T value = values.first();
-      values.clear();
-      values.add(value);
+      T value = pvalues.first();
+      pvalues.clear();
+      pvalues.add(value);
     }
 
-    if (values.isEmpty() && pd.hasOption(PropertyOption.MANDATORY)) {
+    if (pvalues.isEmpty() && pd.hasOption(PropertyOption.MANDATORY)) {
       // The values maybe empty because of a previous exception.
       if (exception == null) {
         exception = new PropertyIsMandatoryException(pd);
@@ -727,29 +830,30 @@
     if (exception != null) {
       throw exception;
     } else {
-      return values;
+      return pvalues;
     }
   }
 
 
 
   // Gets the attribute associated with a property from a ConfigEntry.
-  private List<String> getAttribute(ManagedObjectDefinition<?, ?> d,
+  private List<AttributeValue> getAttribute(ManagedObjectDefinition<?, ?> d,
       PropertyDefinition<?> pd, ConfigEntry configEntry) {
     // TODO: we create a default attribute type if it is
     // undefined. We should log a warning here if this is the case
     // since the attribute should have been defined.
     String attrID = LDAPProfile.getInstance().getAttributeName(d, pd);
     AttributeType type = DirectoryServer.getAttributeType(attrID, true);
-    AttributeValueDecoder<String> decoder =
-      new AttributeValueDecoder<String>() {
+    AttributeValueDecoder<AttributeValue> decoder =
+      new AttributeValueDecoder<AttributeValue>() {
 
-      public String decode(AttributeValue value) throws DirectoryException {
-        return value.getStringValue();
+      public AttributeValue decode(AttributeValue value)
+          throws DirectoryException {
+        return value;
       }
     };
 
-    List<String> values = new LinkedList<String>();
+    List<AttributeValue> values = new LinkedList<AttributeValue>();
     try {
       configEntry.getEntry().getAttributeValues(type, decoder, values);
     } catch (DirectoryException e) {
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AggregationPropertyDefinitionTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AggregationPropertyDefinitionTest.java
new file mode 100644
index 0000000..48dadf9
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AggregationPropertyDefinitionTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.DirectoryServerTestCase;
+import org.opends.server.TestCaseUtils;
+import org.opends.server.types.DN;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * AggregationPropertyDefinition Tester.
+ */
+@Test(sequential = true)
+public class AggregationPropertyDefinitionTest extends DirectoryServerTestCase {
+
+  /**
+   * 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();
+    TestCfg.setUp();
+  }
+
+
+
+  /**
+   * Tears down test environment.
+   */
+  @AfterClass
+  public void tearDown() {
+    TestCfg.cleanup();
+  }
+
+
+
+  /**
+   * Tests that the
+   * {@link AggregationPropertyDefinition#normalizeValue(String)}
+   * works.
+   *
+   * @throws Exception
+   *           If the test unexpectedly fails.
+   */
+  @Test
+  public void testNormalizeValue() throws Exception {
+    TestChildCfgDefn d = TestChildCfgDefn.getInstance();
+    AggregationPropertyDefinition<?, ?> pd = d
+        .getAggregationPropertyPropertyDefinition();
+    String nvalue = pd.normalizeValue("  LDAP   connection    handler  ");
+    Assert.assertEquals(nvalue, "ldap connection handler");
+  }
+
+
+
+  /**
+   * Tests that the
+   * {@link AggregationPropertyDefinition#getChildDN(String)} works.
+   *
+   * @throws Exception
+   *           If the test unexpectedly fails.
+   */
+  @Test
+  public void testGetChildDN() throws Exception {
+    TestChildCfgDefn d = TestChildCfgDefn.getInstance();
+    AggregationPropertyDefinition<?, ?> pd = d
+        .getAggregationPropertyPropertyDefinition();
+    DN expected = DN
+        .decode("cn=ldap connection handler, cn=connection handlers, cn=config");
+    DN actual = pd.getChildDN("  LDAP  connection handler  ");
+    Assert.assertEquals(actual, expected);
+  }
+
+
+
+  /**
+   * Tests that the
+   * {@link AggregationPropertyDefinition#getChildPath(String)} works.
+   *
+   * @throws Exception
+   *           If the test unexpectedly fails.
+   */
+  @Test
+  public void testGetChildPath() throws Exception {
+    TestChildCfgDefn d = TestChildCfgDefn.getInstance();
+    AggregationPropertyDefinition<?, ?> pd = d
+        .getAggregationPropertyPropertyDefinition();
+    ManagedObjectPath<?, ?> path = pd.getChildPath("LDAP connection handler");
+
+    Assert.assertSame(path.getManagedObjectDefinition(), pd
+        .getRelationDefinition().getChildDefinition());
+    Assert.assertSame(path.getRelationDefinition(), pd.getRelationDefinition());
+  }
+
+}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java
index 399c4df..8effbd0 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java
@@ -81,6 +81,8 @@
         return "ds-cfg-virtual-attribute-base-dn";
       } else if (pd == (PropertyDefinition<?>)td.getOptionalMultiValuedDNProperty2PropertyDefinition()) {
         return "ds-cfg-virtual-attribute-group-dn";
+      } else if (pd == (PropertyDefinition<?>)td.getAggregationPropertyPropertyDefinition()) {
+        return "ds-cfg-backend-base-dn";
       } else {
         throw new RuntimeException("Unexpected test-child property"
             + pd.getName());
@@ -117,9 +119,9 @@
   public String getObjectClass(AbstractManagedObjectDefinition<?, ?> d) {
     // These casts throughout are required to work around a bug in JDK versions prior to 1.5.0_08.
     if (d == (AbstractManagedObjectDefinition<?, ?>)TestParentCfgDefn.getInstance()) {
-      return "ds-cfg-virtual-attribute";
+      return "ds-cfg-test-parent-dummy";
     } else if (d == (AbstractManagedObjectDefinition<?, ?>)TestChildCfgDefn.getInstance()) {
-      return "ds-cfg-virtual-attribute";
+      return "ds-cfg-test-child-dummy";
     } else {
       // Not known.
       return null;
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java
index 3745d18..53e2e37 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java
@@ -28,7 +28,14 @@
 
 
 
+import java.util.ResourceBundle;
+
 import org.opends.server.admin.std.meta.RootCfgDefn;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.schema.ObjectClassSyntax;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringFactory;
+import org.opends.server.types.ObjectClass;
 
 
 
@@ -51,8 +58,7 @@
 
   // Create a one-to-many relation for test-parent components.
   static {
-    InstantiableRelationDefinition.Builder<TestParentCfgClient, TestParentCfg> builder =
-      new InstantiableRelationDefinition.Builder<TestParentCfgClient, TestParentCfg>(
+    InstantiableRelationDefinition.Builder<TestParentCfgClient, TestParentCfg> builder = new InstantiableRelationDefinition.Builder<TestParentCfgClient, TestParentCfg>(
         RootCfgDefn.getInstance(), "test-one-to-many-parent",
         "test-one-to-many-parents", TestParentCfgDefn.getInstance());
     RD_TEST_ONE_TO_MANY_PARENT = builder.getInstance();
@@ -60,13 +66,94 @@
 
   // Create a one-to-many relation for test-parent components.
   static {
-    OptionalRelationDefinition.Builder<TestParentCfgClient, TestParentCfg> builder =
-      new OptionalRelationDefinition.Builder<TestParentCfgClient, TestParentCfg>(
+    OptionalRelationDefinition.Builder<TestParentCfgClient, TestParentCfg> builder = new OptionalRelationDefinition.Builder<TestParentCfgClient, TestParentCfg>(
         RootCfgDefn.getInstance(), "test-one-to-zero-or-one-parent",
         TestParentCfgDefn.getInstance());
     RD_TEST_ONE_TO_ZERO_OR_ONE_PARENT = builder.getInstance();
   }
 
+  // Test parent object class definition.
+  private static ObjectClass TEST_PARENT_OCD = null;
+
+  // Test child object class definition.
+  private static ObjectClass TEST_CHILD_OCD = null;
+
+
+
+  /**
+   * Registers test parent and child object class definitions and any
+   * required resource bundles.
+   * <p>
+   * Unit tests which call this method <b>must</b> call
+   * {@link #cleanup()} on completion.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  public synchronized static void setUp() throws Exception {
+    if (TEST_PARENT_OCD == null) {
+      String ocd = "( 1.3.6.1.4.1.26027.1.2.4455114401 "
+          + "NAME 'ds-cfg-test-parent-dummy' "
+          + "SUP top STRUCTURAL "
+          + "MUST ( cn $ ds-cfg-virtual-attribute-class $ "
+          + "ds-cfg-virtual-attribute-enabled $ ds-cfg-virtual-attribute-type ) "
+          + "MAY ( ds-cfg-virtual-attribute-base-dn $ ds-cfg-virtual-attribute-group-dn $ "
+          + "ds-cfg-virtual-attribute-filter $ ds-cfg-virtual-attribute-conflict-behavior ) "
+          + "X-ORIGIN 'OpenDS Directory Server' )";
+      ByteString b = ByteStringFactory.create(ocd);
+
+      TEST_PARENT_OCD = ObjectClassSyntax.decodeObjectClass(b, DirectoryServer
+          .getSchema(), false);
+    }
+
+    if (TEST_CHILD_OCD == null) {
+      String ocd = "( 1.3.6.1.4.1.26027.1.2.4455114402 "
+          + "NAME 'ds-cfg-test-child-dummy' "
+          + "SUP top STRUCTURAL "
+          + "MUST ( cn $ ds-cfg-virtual-attribute-class $ "
+          + "ds-cfg-virtual-attribute-enabled $ ds-cfg-virtual-attribute-type ) "
+          + "MAY ( ds-cfg-virtual-attribute-base-dn $ ds-cfg-virtual-attribute-group-dn $ "
+          + "ds-cfg-virtual-attribute-filter $ ds-cfg-virtual-attribute-conflict-behavior $"
+          + "ds-cfg-backend-base-dn) " + "X-ORIGIN 'OpenDS Directory Server' )";
+      ByteString b = ByteStringFactory.create(ocd);
+
+      TEST_CHILD_OCD = ObjectClassSyntax.decodeObjectClass(b, DirectoryServer
+          .getSchema(), false);
+    }
+
+    {
+      // Register the test parent object class.
+      DirectoryServer.registerObjectClass(TEST_PARENT_OCD, true);
+
+      // Register the test parent resource bundle.
+      TestParentCfgDefn d = TestParentCfgDefn.getInstance();
+      String baseName = d.getClass().getName();
+      ResourceBundle resourceBundle = ResourceBundle.getBundle(baseName);
+      ManagedObjectDefinitionI18NResource.getInstance().setResourceBundle(d,
+          resourceBundle);
+    }
+
+    {
+      // Register the test child object class.
+      DirectoryServer.registerObjectClass(TEST_CHILD_OCD, true);
+
+      // Register the test child resource bundle.
+      TestChildCfgDefn d = TestChildCfgDefn.getInstance();
+      String baseName = d.getClass().getName();
+      ResourceBundle resourceBundle = ResourceBundle.getBundle(baseName);
+      ManagedObjectDefinitionI18NResource.getInstance().setResourceBundle(d,
+          resourceBundle);
+    }
+
+    // Ensure that the relations are registered (do this after things
+    // that can fail and leave tests in a bad state).
+    RootCfgDefn.getInstance().registerRelationDefinition(
+        RD_TEST_ONE_TO_MANY_PARENT);
+    RootCfgDefn.getInstance().registerRelationDefinition(
+        RD_TEST_ONE_TO_ZERO_OR_ONE_PARENT);
+    LDAPProfile.getInstance().pushWrapper(new MockLDAPProfile());
+  }
+
 
 
   /**
@@ -74,10 +161,24 @@
    * framework.
    */
   public static void cleanup() {
-    RootCfgDefn.getInstance().deregisterRelationDefinition(
-        RD_TEST_ONE_TO_MANY_PARENT);
-    RootCfgDefn.getInstance().deregisterRelationDefinition(
-        RD_TEST_ONE_TO_ZERO_OR_ONE_PARENT);
+    LDAPProfile.getInstance().popWrapper();
+
+    {
+      RootCfgDefn.getInstance().deregisterRelationDefinition(
+          RD_TEST_ONE_TO_MANY_PARENT);
+      RootCfgDefn.getInstance().deregisterRelationDefinition(
+          RD_TEST_ONE_TO_ZERO_OR_ONE_PARENT);
+      DirectoryServer.deregisterObjectClass(TEST_PARENT_OCD);
+      TestParentCfgDefn d = TestParentCfgDefn.getInstance();
+      ManagedObjectDefinitionI18NResource.getInstance().removeResourceBundle(d);
+    }
+
+    {
+      DirectoryServer.deregisterObjectClass(TEST_CHILD_OCD);
+      TestChildCfgDefn d = TestChildCfgDefn.getInstance();
+      ManagedObjectDefinitionI18NResource.getInstance().removeResourceBundle(d);
+    }
+
   }
 
 
@@ -86,16 +187,13 @@
    * Gets the one-to-many relation between the root and test-parent
    * components.
    * <p>
-   * Unit tests which call this method <b>must</b> call
-   * {@link #cleanup()} on completion.
+   * Unit tests which call this method <b>must</b> have already
+   * called {@link #setUp()}.
    *
    * @return Returns the one-to-many relation between the root and
    *         test-parent components.
    */
   public static InstantiableRelationDefinition<TestParentCfgClient, TestParentCfg> getTestOneToManyParentRelationDefinition() {
-    // Ensure that the relation is registered.
-    RootCfgDefn.getInstance().registerRelationDefinition(
-        RD_TEST_ONE_TO_MANY_PARENT);
     return RD_TEST_ONE_TO_MANY_PARENT;
   }
 
@@ -105,21 +203,42 @@
    * Gets the one-to-zero-or-one relation between the root and a
    * test-parent component.
    * <p>
-   * Unit tests which call this method <b>must</b> call
-   * {@link #cleanup()} on completion.
+   * Unit tests which call this method <b>must</b> have already
+   * called {@link #setUp()}.
    *
    * @return Returns the one-to-zero-or-one relation between the root
    *         and a test-parent component.
    */
   public static OptionalRelationDefinition<TestParentCfgClient, TestParentCfg> getTestOneToZeroOrOneParentRelationDefinition() {
-    // Ensure that the relation is registered.
-    RootCfgDefn.getInstance().registerRelationDefinition(
-        RD_TEST_ONE_TO_ZERO_OR_ONE_PARENT);
     return RD_TEST_ONE_TO_ZERO_OR_ONE_PARENT;
   }
 
 
 
+  /**
+   * Adds a constraint temporarily with test child definition.
+   *
+   * @param constraint
+   *          The constraint.
+   */
+  public static void addConstraint(Constraint constraint) {
+    TestChildCfgDefn.getInstance().registerConstraint(constraint);
+  }
+
+
+
+  /**
+   * Removes a constraint from the test child definition.
+   *
+   * @param constraint
+   *          The constraint.
+   */
+  public static void removeConstraint(Constraint constraint) {
+    TestChildCfgDefn.getInstance().deregisterConstraint(constraint);
+  }
+
+
+
   // Prevent instantiation.
   private TestCfg() {
     // No implementation required.
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfg.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfg.java
index 3d391a2..fb79669 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfg.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfg.java
@@ -32,6 +32,7 @@
 import org.opends.server.admin.Configuration;
 import org.opends.server.admin.ManagedObjectDefinition;
 import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.TestChildCfgClient;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.DN;
 
@@ -76,6 +77,17 @@
 
 
   /**
+   * Get the "aggregation-property" property.
+   * <p>
+   * An aggregation property which references connection handlers.
+   *
+   * @return Returns the values of the "aggregation-property" property.
+   */
+  SortedSet<String> getAggregationProperty();
+
+
+
+  /**
    * Get the "mandatory-boolean-property" property.
    * <p>
    * A mandatory boolean property.
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgClient.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgClient.java
index b1a025a..6772f1b 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgClient.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgClient.java
@@ -34,6 +34,7 @@
 import org.opends.server.admin.IllegalPropertyValueException;
 import org.opends.server.admin.ManagedObjectDefinition;
 import org.opends.server.admin.PropertyIsReadOnlyException;
+import org.opends.server.admin.TestChildCfg;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.DN;
 
@@ -59,6 +60,30 @@
 
 
   /**
+   * Get the "aggregation-property" property.
+   * <p>
+   * An aggregation property which references connection handlers.
+   *
+   * @return Returns the values of the "aggregation-property" property.
+   */
+  SortedSet<String> getAggregationProperty();
+
+
+
+  /**
+   * Set the "aggregation-property" property.
+   * <p>
+   * An aggregation property which references connection handlers.
+   *
+   * @param values The values of the "aggregation-property" property.
+   * @throws IllegalPropertyValueException
+   *           If one or more of the new values are invalid.
+   */
+  void setAggregationProperty(Collection<String> values) throws IllegalPropertyValueException;
+
+
+
+  /**
    * Get the "mandatory-boolean-property" property.
    * <p>
    * A mandatory boolean property.
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.java
index 7d91ae3..4a5780c 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.java
@@ -34,24 +34,30 @@
 import org.opends.server.admin.AttributeTypePropertyDefinition;
 import org.opends.server.admin.BooleanPropertyDefinition;
 import org.opends.server.admin.ClassPropertyDefinition;
+import org.opends.server.admin.DNPropertyDefinition;
+import org.opends.server.admin.DefaultBehaviorProvider;
+import org.opends.server.admin.DefinedDefaultBehaviorProvider;
+import org.opends.server.admin.ManagedObjectAlreadyExistsException;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.ManagedObjectPath;
+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.UndefinedDefaultBehaviorProvider;
 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.admin.std.client.ConnectionHandlerCfgClient;
+import org.opends.server.admin.TestChildCfgClient;
+import org.opends.server.admin.std.meta.ConnectionHandlerCfgDefn;
+import org.opends.server.admin.std.server.ConnectionHandlerCfg;
+import org.opends.server.admin.TestChildCfg;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.DN;
 
@@ -72,6 +78,11 @@
 
 
 
+  // The "aggregation-property" property definition.
+  private static final AggregationPropertyDefinition<ConnectionHandlerCfgClient, ConnectionHandlerCfg> PD_AGGREGATION_PROPERTY;
+
+
+
   // The "mandatory-boolean-property" property definition.
   private static final BooleanPropertyDefinition PD_MANDATORY_BOOLEAN_PROPERTY;
 
@@ -97,6 +108,21 @@
 
 
 
+  // Build the "aggregation-property" property definition.
+  static {
+      AggregationPropertyDefinition.Builder<ConnectionHandlerCfgClient, ConnectionHandlerCfg> builder = AggregationPropertyDefinition.createBuilder(INSTANCE, "aggregation-property");
+      builder.setOption(PropertyOption.MULTI_VALUED);
+      builder.setAdministratorAction(new AdministratorAction(AdministratorAction.Type.NONE, INSTANCE, "aggregation-property"));
+      builder.setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<String>());
+      builder.setParentPath(ManagedObjectPath.valueOf("/"));
+      builder.setRelationDefinition("connection-handler");
+      builder.setManagedObjectDefinition(ConnectionHandlerCfgDefn.getInstance());
+      PD_AGGREGATION_PROPERTY = builder.getInstance();
+      INSTANCE.registerPropertyDefinition(PD_AGGREGATION_PROPERTY);
+  }
+
+
+
   // Build the "mandatory-boolean-property" property definition.
   static {
       BooleanPropertyDefinition.Builder builder = BooleanPropertyDefinition.createBuilder(INSTANCE, "mandatory-boolean-property");
@@ -180,28 +206,6 @@
   private TestChildCfgDefn() {
     super("test-child", null);
   }
-  
-  
-  
-  /**
-   * Adds a constraint temporarily with this test definition.
-   * 
-   * @param constraint The constraint.
-   */
-  public void addConstraint(Constraint constraint) {
-    registerConstraint(constraint);
-  }
-  
-  
-  
-  /**
-   * Removes a constraint from this test definition.
-   * 
-   * @param constraint The constraint.
-   */
-  public void removeConstraint(Constraint constraint) {
-    deregisterConstraint(constraint);
-  }
 
 
 
@@ -235,6 +239,19 @@
 
 
   /**
+   * Get the "aggregation-property" property definition.
+   * <p>
+   * An aggregation property which references connection handlers.
+   *
+   * @return Returns the "aggregation-property" property definition.
+   */
+  public AggregationPropertyDefinition<ConnectionHandlerCfgClient, ConnectionHandlerCfg> getAggregationPropertyPropertyDefinition() {
+    return PD_AGGREGATION_PROPERTY;
+  }
+
+
+
+  /**
    * Get the "mandatory-boolean-property" property definition.
    * <p>
    * A mandatory boolean property.
@@ -323,6 +340,24 @@
     /**
      * {@inheritDoc}
      */
+    public SortedSet<String> getAggregationProperty() {
+      return impl.getPropertyValues(INSTANCE.getAggregationPropertyPropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setAggregationProperty(Collection<String> values) {
+      impl.setPropertyValues(INSTANCE.getAggregationPropertyPropertyDefinition(), values);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
     public Boolean isMandatoryBooleanProperty() {
       return impl.getPropertyValue(INSTANCE.getMandatoryBooleanPropertyPropertyDefinition());
     }
@@ -483,6 +518,15 @@
     /**
      * {@inheritDoc}
      */
+    public SortedSet<String> getAggregationProperty() {
+      return impl.getPropertyValues(INSTANCE.getAggregationPropertyPropertyDefinition());
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
     public boolean isMandatoryBooleanProperty() {
       return impl.getPropertyValue(INSTANCE.getMandatoryBooleanPropertyPropertyDefinition());
     }
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.properties b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.properties
new file mode 100644
index 0000000..a5d5ac7
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.properties
@@ -0,0 +1,9 @@
+user-friendly-name=Test Child
+user-friendly-plural-name=Test Children
+synopsis=A configuration for testing components that are subordinate to a parent component. It re-uses the virtual-attribute configuration LDAP profile.
+property.aggregation-property.synopsis=An aggregation property which references connection handlers.
+property.mandatory-boolean-property.synopsis=A mandatory boolean property.
+property.mandatory-class-property.synopsis=A mandatory Java-class property requiring a component restart.
+property.mandatory-read-only-attribute-type-property.synopsis=A mandatory read-only attribute type property.
+property.optional-multi-valued-dn-property1.synopsis=An optional multi-valued DN property which inherits its values from optional-multi-valued-dn-property in the parent.
+property.optional-multi-valued-dn-property2.synopsis=An optional multi-valued DN property which inherits its values from optional-multi-valued-dn-property1.
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildConfiguration.xml b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildConfiguration.xml
index 48bcef1..a15de26 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildConfiguration.xml
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildConfiguration.xml
@@ -26,7 +26,7 @@
   !      Portions Copyright 2007 Sun Microsystems, Inc.
   ! -->
 <adm:managed-object name="test-child" plural-name="test-children"
-  package="org.opends.server.admin.std"
+  package="org.opends.server.admin"
   xmlns:adm="http://www.opends.org/admin"
   xmlns:ldap="http://www.opends.org/admin-ldap">
   <adm:synopsis>
@@ -36,8 +36,8 @@
   </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:oid>1.3.6.1.4.1.26027.1.2.4455114402</ldap:oid>
+      <ldap:name>ds-cfg-test-child-dummy</ldap:name>
       <ldap:superior>top</ldap:superior>
     </ldap:object-class>
   </adm:profile>
@@ -140,4 +140,22 @@
       </ldap:attribute>
     </adm:profile>
   </adm:property>
+  <adm:property name="aggregation-property" multi-valued="true">
+    <adm:synopsis>
+      An aggregation property which references connection handlers.
+    </adm:synopsis>
+    <adm:default-behavior>
+      <adm:undefined />
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:aggregation parent-path="/"
+        relation-name="connection-handler" />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:oid>1.3.6.1.4.1.26027.1.1.332</ldap:oid>
+        <ldap:name>ds-task-initialize-domain-dn</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
 </adm:managed-object>
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.properties b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.properties
new file mode 100644
index 0000000..2e5c044
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.properties
@@ -0,0 +1,12 @@
+user-friendly-name=Test Parent
+user-friendly-plural-name=Test Parents
+synopsis=A configuration for testing components that have child components. It re-uses the virtual-attribute configuration LDAP profile.
+property.mandatory-boolean-property.synopsis=A mandatory boolean property.
+property.mandatory-class-property.synopsis=A mandatory Java-class property requiring a component restart.
+property.mandatory-read-only-attribute-type-property.synopsis=A mandatory read-only attribute type property.
+property.optional-multi-valued-dn-property.synopsis=An optional multi-valued DN property with a defined default behavior.
+relation.optional-test-child.user-friendly-name=Optional Test Child
+relation.optional-test-child.synopsis=A configuration for testing components that are subordinate to a parent component. It re-uses the virtual-attribute configuration LDAP profile.
+relation.test-child.user-friendly-name=Test Child
+relation.test-child.user-friendly-plural-name=Test Children
+relation.test-child.synopsis=A configuration for testing components that are subordinate to a parent component. It re-uses the virtual-attribute configuration LDAP profile.
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentConfiguration.xml b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentConfiguration.xml
index a32158a..85f5935 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentConfiguration.xml
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentConfiguration.xml
@@ -26,7 +26,7 @@
   !      Portions Copyright 2007 Sun Microsystems, Inc.
   ! -->
 <adm:managed-object name="test-parent" plural-name="test-parents"
-  package="org.opends.server.admin.std"
+  package="org.opends.server.admin"
   xmlns:adm="http://www.opends.org/admin"
   xmlns:ldap="http://www.opends.org/admin-ldap">
   <adm:synopsis>
@@ -35,8 +35,8 @@
   </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:oid>1.3.6.1.4.1.26027.1.2.4455114401</ldap:oid>
+      <ldap:name>ds-cfg-test-parent-dummy</ldap:name>
       <ldap:superior>top</ldap:superior>
     </ldap:object-class>
   </adm:profile>
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/AggregationTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/AggregationTest.java
new file mode 100644
index 0000000..13b226c
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/AggregationTest.java
@@ -0,0 +1,357 @@
+/*
+ * 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.client.ldap;
+
+
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.AdminTestCase;
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.IllegalPropertyValueStringException;
+import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.PropertyException;
+import org.opends.server.admin.TestCfg;
+import org.opends.server.admin.TestChildCfgClient;
+import org.opends.server.admin.TestChildCfgDefn;
+import org.opends.server.admin.TestParentCfgClient;
+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.ManagedObjectDecodingException;
+import org.opends.server.admin.client.ManagementContext;
+import org.opends.server.admin.std.client.RootCfgClient;
+import org.opends.server.core.DirectoryServer;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Test cases for aggregations on the client-side.
+ */
+@Test(sequential = true)
+public class AggregationTest extends AdminTestCase {
+
+  // Test LDIF.
+  private static final String[] TEST_LDIF = new String[] {
+      // Base entries.
+      "dn: cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-branch",
+      "cn: config",
+      "",
+      "dn: cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-branch",
+      "cn: test-parents",
+      "",
+      // 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-test-parent-dummy",
+      "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",
+      "",
+      // Child base entry.
+      "dn:cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-branch",
+      "cn: multiple children",
+      "",
+      // Child 1 has no references.
+      "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-test-child-dummy",
+      "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 has a single valid reference.
+      "dn: cn=test child 2,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-test-child-dummy",
+      "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-backend-base-dn: cn=LDAP Connection Handler, cn=connection handlers, cn=config",
+      "",
+      // Child 3 has a multiple valid references.
+      "dn: cn=test child 3,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-test-child-dummy",
+      "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-backend-base-dn: cn=LDAP Connection Handler, cn=connection handlers, cn=config",
+      "ds-cfg-backend-base-dn: cn=LDAPS Connection Handler, cn=connection handlers, cn=config",
+      "",
+      // Child 4 has a single bad reference.
+      "dn: cn=test child 4,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-test-child-dummy",
+      "cn: test child 4",
+      "ds-cfg-virtual-attribute-enabled: true",
+      "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
+      "ds-cfg-virtual-attribute-type: description",
+      "ds-cfg-backend-base-dn: cn=LDAP Connection Handler, cn=bad rdn, cn=config",
+      "",
+  };
+
+
+
+  /**
+   * 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();
+    TestCfg.setUp();
+  }
+
+
+
+  /**
+   * Tears down test environment.
+   */
+  @AfterClass
+  public void tearDown() {
+    TestCfg.cleanup();
+  }
+
+
+
+  /**
+   * Tests that aggregation contains no values when it contains does
+   * not contain any DN attribute values.
+   *
+   * @throws Exception
+   *           If the test unexpectedly fails.
+   */
+  @Test
+  public void testAggregationEmpty() throws Exception {
+    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");
+    assertSetEquals(child.getAggregationProperty(), new String[0]);
+  }
+
+
+
+  /**
+   * Tests that aggregation contains single valid value when it
+   * contains a single valid DN attribute values.
+   *
+   * @throws Exception
+   *           If the test unexpectedly fails.
+   */
+  @Test
+  public void testAggregationSingle() throws Exception {
+    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");
+
+    // Test normalization.
+    assertSetEquals(child.getAggregationProperty(), "LDAP Connection Handler");
+    assertSetEquals(child.getAggregationProperty(),
+        "  LDAP   Connection  Handler ");
+    assertSetEquals(child.getAggregationProperty(),
+        "  ldap connection HANDLER ");
+  }
+
+
+
+  /**
+   * Tests that aggregation contains multiple valid values when it
+   * contains a multiple valid DN attribute values.
+   *
+   * @throws Exception
+   *           If the test unexpectedly fails.
+   */
+  @Test
+  public void testAggregationMultiple() throws Exception {
+    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 3");
+    assertSetEquals(child.getAggregationProperty(), "LDAPS Connection Handler",
+        "LDAP Connection Handler");
+  }
+
+
+
+  /**
+   * Tests that aggregation is rejected when the LDAP DN contains a
+   * valid RDN but an invalid parent DN.
+   *
+   * @throws Exception
+   *           If the test unexpectedly fails.
+   */
+  @Test
+  public void testAggregationBadBaseDN() throws Exception {
+    MockLDAPConnection c = new MockLDAPConnection();
+    c.importLDIF(TEST_LDIF);
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
+    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
+
+    try {
+      parent.getTestChild("test child 4");
+      Assert.fail("Unexpectedly retrieved test child 4"
+          + " when it had a bad aggregation value");
+    } catch (ManagedObjectDecodingException e) {
+      Collection<PropertyException> causes = e.getCauses();
+      Assert.assertEquals(causes.size(), 1);
+
+      Throwable cause = causes.iterator().next();
+      if (cause instanceof IllegalPropertyValueStringException) {
+        IllegalPropertyValueStringException pe = (IllegalPropertyValueStringException) cause;
+        Assert.assertEquals(pe.getPropertyDefinition(), TestChildCfgDefn
+            .getInstance().getAggregationPropertyPropertyDefinition());
+        Assert.assertEquals(pe.getIllegalValueString(),
+            "cn=LDAP Connection Handler, cn=bad rdn, cn=config");
+      } else {
+        // Got an unexpected cause.
+        throw e;
+      }
+    }
+  }
+
+
+
+  /**
+   * Tests creation of a child managed object with a single reference.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testCreateChildManagedObject() throws Exception {
+    CreateEntryMockLDAPConnection c = new CreateEntryMockLDAPConnection(
+        "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 new");
+    c.addExpectedAttribute("objectclass", "top", "ds-cfg-test-child-dummy");
+    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");
+    c.addExpectedAttribute("ds-cfg-backend-base-dn",
+        "cn=LDAP Connection Handler,cn=connection handlers,cn=config");
+
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
+    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
+    TestChildCfgClient child = parent.createTestChild(TestChildCfgDefn
+        .getInstance(), "test child new", null);
+    child.setMandatoryBooleanProperty(true);
+    child.setMandatoryReadOnlyAttributeTypeProperty(DirectoryServer
+        .getAttributeType("description"));
+    child.setAggregationProperty(Collections
+        .singleton("LDAP Connection Handler"));
+    child.commit();
+
+    c.assertEntryIsCreated();
+  }
+
+
+
+  /**
+   * Tests modification of a child managed object so that it has a
+   * different reference.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testModifyChildManagedObject() 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-backend-base-dn",
+        "cn=LDAPS Connection Handler,cn=connection handlers,cn=config",
+        "cn=JMX Connection Handler,cn=connection handlers,cn=config");
+    ManagementContext ctx = LDAPManagementContext.createFromContext(c);
+    TestParentCfgClient parent = getTestParent(ctx, "test parent 1");
+    TestChildCfgClient child = parent.getTestChild("test child 2");
+    child.setAggregationProperty(Arrays.asList("LDAPS Connection Handler",
+        "JMX Connection Handler"));
+    child.commit();
+    Assert.assertTrue(c.isEntryModified());
+  }
+
+
+
+  // Retrieve the named test parent managed object.
+  private TestParentCfgClient getTestParent(ManagementContext context,
+      String name) throws DefinitionDecodingException,
+      ManagedObjectDecodingException, AuthorizationException,
+      ManagedObjectNotFoundException, ConcurrentModificationException,
+      CommunicationException {
+    ManagedObject<RootCfgClient> root = context
+        .getRootConfigurationManagedObject();
+    return root.getChild(TestCfg.getTestOneToManyParentRelationDefinition(),
+        name).getConfiguration();
+  }
+
+
+
+  // Asserts that the actual set of DNs contains the expected values.
+  private void assertSetEquals(SortedSet<String> actual, String... expected) {
+    SortedSet<String> values = new TreeSet<String>(TestChildCfgDefn
+        .getInstance().getAggregationPropertyPropertyDefinition());
+    if (expected != null) {
+      for (String value : expected) {
+        values.add(value);
+      }
+    }
+    Assert.assertEquals((Object) actual, (Object) values);
+  }
+
+}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java
index 9c7e8b1..624647e 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java
@@ -42,10 +42,8 @@
 import org.opends.server.admin.AdminTestCase;
 import org.opends.server.admin.Constraint;
 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;
 import org.opends.server.admin.TestCfg;
 import org.opends.server.admin.TestChildCfgClient;
 import org.opends.server.admin.TestChildCfgDefn;
@@ -93,7 +91,7 @@
       // optional-multi-valued-dn-property.
       "dn: cn=test parent 1,cn=test parents,cn=config",
       "objectclass: top",
-      "objectclass: ds-cfg-virtual-attribute",
+      "objectclass: ds-cfg-test-parent-dummy",
       "cn: test parent 1",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -103,7 +101,7 @@
       // optional-multi-valued-dn-property.
       "dn: cn=test parent 2,cn=test parents,cn=config",
       "objectclass: top",
-      "objectclass: ds-cfg-virtual-attribute",
+      "objectclass: ds-cfg-test-parent-dummy",
       "cn: test parent 2",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -115,7 +113,7 @@
       // optional-multi-valued-dn-property.
       "dn: cn=test parent 3,cn=test parents,cn=config",
       "objectclass: top",
-      "objectclass: ds-cfg-virtual-attribute",
+      "objectclass: ds-cfg-test-parent-dummy",
       "cn: test parent 3",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -139,7 +137,7 @@
       // 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",
+      "objectclass: ds-cfg-test-child-dummy",
       "cn: test child 1",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -149,7 +147,7 @@
       // 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",
+      "objectclass: ds-cfg-test-child-dummy",
       "cn: test child 2",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -162,7 +160,7 @@
       // 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",
+      "objectclass: ds-cfg-test-child-dummy",
       "cn: test child 3",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -177,12 +175,12 @@
       // 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",
+      "objectclass: ds-cfg-test-child-dummy",
       "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",
-      ""
+      "",
   };
 
 
@@ -273,7 +271,7 @@
     // This test suite depends on having the schema available, so
     // we'll start the server.
     TestCaseUtils.startServer();
-    LDAPProfile.getInstance().pushWrapper(new MockLDAPProfile());
+    TestCfg.setUp();
   }
 
 
@@ -283,7 +281,6 @@
    */
   @AfterClass
   public void tearDown() {
-    LDAPProfile.getInstance().popWrapper();
     TestCfg.cleanup();
   }
 
@@ -301,7 +298,7 @@
         "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 new");
-    c.addExpectedAttribute("objectclass", "top", "ds-cfg-virtual-attribute");
+    c.addExpectedAttribute("objectclass", "top", "ds-cfg-test-child-dummy");
     c.addExpectedAttribute("ds-cfg-virtual-attribute-enabled", "true");
     c.addExpectedAttribute("ds-cfg-virtual-attribute-class",
         "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
@@ -372,7 +369,7 @@
         "cn=test parent new,cn=test parents,cn=config");
     c.importLDIF(TEST_LDIF);
     c.addExpectedAttribute("cn", "test parent new");
-    c.addExpectedAttribute("objectclass", "top", "ds-cfg-virtual-attribute");
+    c.addExpectedAttribute("objectclass", "top", "ds-cfg-test-parent-dummy");
     c.addExpectedAttribute("ds-cfg-virtual-attribute-enabled", "true");
     c.addExpectedAttribute("ds-cfg-virtual-attribute-class",
         "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
@@ -438,6 +435,7 @@
         "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");
+    Assert.assertEquals(child.isMandatoryBooleanProperty(), Boolean.TRUE);
   }
 
 
@@ -537,7 +535,7 @@
         "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 new");
-    c.addExpectedAttribute("objectclass", "top", "ds-cfg-virtual-attribute");
+    c.addExpectedAttribute("objectclass", "top", "ds-cfg-test-child-dummy");
     c.addExpectedAttribute("ds-cfg-virtual-attribute-enabled", "true");
     c.addExpectedAttribute("ds-cfg-virtual-attribute-class",
         "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
@@ -582,7 +580,7 @@
         "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 new");
-    c.addExpectedAttribute("objectclass", "top", "ds-cfg-virtual-attribute");
+    c.addExpectedAttribute("objectclass", "top", "ds-cfg-test-child-dummy");
     c.addExpectedAttribute("ds-cfg-virtual-attribute-enabled", "true");
     c.addExpectedAttribute("ds-cfg-virtual-attribute-class",
         "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
@@ -808,14 +806,14 @@
   @Test
   public void testAddConstraintSuccess() throws Exception {
     Constraint constraint = new MockConstraint(true, false, false);
-    TestChildCfgDefn.getInstance().addConstraint(constraint);
+    TestCfg.addConstraint(constraint);
 
     try {
       CreateEntryMockLDAPConnection c = new CreateEntryMockLDAPConnection(
           "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 new");
-      c.addExpectedAttribute("objectclass", "top", "ds-cfg-virtual-attribute");
+      c.addExpectedAttribute("objectclass", "top", "ds-cfg-test-child-dummy");
       c.addExpectedAttribute("ds-cfg-virtual-attribute-enabled", "true");
       c.addExpectedAttribute("ds-cfg-virtual-attribute-class",
           "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
@@ -833,7 +831,7 @@
       c.assertEntryIsCreated();
     } finally {
       // Clean up.
-      TestChildCfgDefn.getInstance().removeConstraint(constraint);
+      TestCfg.removeConstraint(constraint);
     }
   }
 
@@ -849,14 +847,14 @@
   @Test(expectedExceptions=OperationRejectedException.class)
   public void testAddConstraintFail() throws Exception {
     Constraint constraint = new MockConstraint(false, true, true);
-    TestChildCfgDefn.getInstance().addConstraint(constraint);
+    TestCfg.addConstraint(constraint);
 
     try {
       CreateEntryMockLDAPConnection c = new CreateEntryMockLDAPConnection(
           "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 new");
-      c.addExpectedAttribute("objectclass", "top", "ds-cfg-virtual-attribute");
+      c.addExpectedAttribute("objectclass", "top", "ds-cfg-test-child-dummy");
       c.addExpectedAttribute("ds-cfg-virtual-attribute-enabled", "true");
       c.addExpectedAttribute("ds-cfg-virtual-attribute-class",
           "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
@@ -873,7 +871,7 @@
       Assert.fail("The add constraint failed to prevent creation of the managed object");
     } finally {
       // Clean up.
-      TestChildCfgDefn.getInstance().removeConstraint(constraint);
+      TestCfg.removeConstraint(constraint);
     }
   }
 
@@ -889,7 +887,7 @@
   @Test
   public void testRemoveConstraintSuccess() throws Exception {
     Constraint constraint = new MockConstraint(false, false, true);
-    TestChildCfgDefn.getInstance().addConstraint(constraint);
+    TestCfg.addConstraint(constraint);
 
     try {
       DeleteSubtreeMockLDAPConnection c = new DeleteSubtreeMockLDAPConnection(
@@ -901,7 +899,7 @@
       c.assertSubtreeIsDeleted();
     } finally {
       // Clean up.
-      TestChildCfgDefn.getInstance().removeConstraint(constraint);
+      TestCfg.removeConstraint(constraint);
     }
   }
 
@@ -917,7 +915,7 @@
   @Test(expectedExceptions=OperationRejectedException.class)
   public void testRemoveConstraintFail() throws Exception {
     Constraint constraint = new MockConstraint(true, true, false);
-    TestChildCfgDefn.getInstance().addConstraint(constraint);
+    TestCfg.addConstraint(constraint);
 
     try {
       DeleteSubtreeMockLDAPConnection c = new DeleteSubtreeMockLDAPConnection(
@@ -929,7 +927,7 @@
       Assert.fail("The remove constraint failed to prevent removal of the managed object");
     } finally {
       // Clean up.
-      TestChildCfgDefn.getInstance().removeConstraint(constraint);
+      TestCfg.removeConstraint(constraint);
     }
   }
 
@@ -945,7 +943,7 @@
   @Test
   public void testModifyConstraintSuccess() throws Exception {
     Constraint constraint = new MockConstraint(false, true, false);
-    TestChildCfgDefn.getInstance().addConstraint(constraint);
+    TestCfg.addConstraint(constraint);
 
     try {
       ModifyEntryMockLDAPConnection c = new ModifyEntryMockLDAPConnection(
@@ -960,7 +958,7 @@
       Assert.assertTrue(c.isEntryModified());
     } finally {
       // Clean up.
-      TestChildCfgDefn.getInstance().removeConstraint(constraint);
+      TestCfg.removeConstraint(constraint);
     }
   }
 
@@ -976,7 +974,7 @@
   @Test(expectedExceptions = OperationRejectedException.class)
   public void testModifyConstraintFail() throws Exception {
     Constraint constraint = new MockConstraint(true, false, true);
-    TestChildCfgDefn.getInstance().addConstraint(constraint);
+    TestCfg.addConstraint(constraint);
 
     try {
       ModifyEntryMockLDAPConnection c = new ModifyEntryMockLDAPConnection(
@@ -992,7 +990,7 @@
           .fail("The modify constraint failed to prevent modification of the managed object");
     } finally {
       // Clean up.
-      TestChildCfgDefn.getInstance().removeConstraint(constraint);
+      TestCfg.removeConstraint(constraint);
     }
   }
 
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AggregationTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AggregationTest.java
new file mode 100644
index 0000000..3641a92
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AggregationTest.java
@@ -0,0 +1,377 @@
+/*
+ * 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 java.util.Collection;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.naming.ldap.LdapName;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.AdminTestCase;
+import org.opends.server.admin.IllegalPropertyValueStringException;
+import org.opends.server.admin.PropertyException;
+import org.opends.server.admin.TestCfg;
+import org.opends.server.admin.TestChildCfg;
+import org.opends.server.admin.TestChildCfgDefn;
+import org.opends.server.admin.TestParentCfg;
+import org.opends.server.admin.client.ldap.JNDIDirContextAdaptor;
+import org.opends.server.admin.std.server.RootCfg;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Test cases for aggregations on the server-side.
+ */
+@Test(sequential=true)
+public final class AggregationTest extends AdminTestCase {
+
+  // Test child 1 LDIF.
+  private static final String[] TEST_CHILD_1 = new String[] {
+      "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-test-child-dummy",
+      "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",
+      "ds-cfg-virtual-attribute-conflict-behavior: virtual-overrides-real"
+  };
+
+
+
+  // Assert that the values of child 1 are correct.
+  private void assertChild1(TestChildCfg child) {
+    Assert.assertEquals(child.getMandatoryClassProperty(),
+        "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+    Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+        DirectoryServer.getAttributeType("description"));
+    assertSetEquals(child.getAggregationProperty(), new String[0]);
+  }
+
+  // Test child 2 LDIF.
+  private static final String[] TEST_CHILD_2 = new String[] {
+      "dn: cn=test child 2,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-test-child-dummy",
+      "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-conflict-behavior: virtual-overrides-real",
+      "ds-cfg-backend-base-dn: cn=LDAP Connection Handler, cn=connection handlers, cn=config"
+  };
+
+
+
+  // Assert that the values of child 2 are correct.
+  private void assertChild2(TestChildCfg child) {
+    Assert.assertEquals(child.getMandatoryClassProperty(),
+        "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+    Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+        DirectoryServer.getAttributeType("description"));
+
+    // Test normalization.
+    assertSetEquals(child.getAggregationProperty(), "LDAP Connection Handler");
+    assertSetEquals(child.getAggregationProperty(),
+        "  LDAP   Connection  Handler ");
+    assertSetEquals(child.getAggregationProperty(),
+        "  ldap connection HANDLER ");
+  }
+
+  // Test child 3 LDIF (invalid reference).
+  private static final String[] TEST_CHILD_3 = new String[] {
+      "dn: cn=test child 3,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-test-child-dummy",
+      "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-conflict-behavior: virtual-overrides-real",
+      "ds-cfg-backend-base-dn: cn=LDAP Connection Handler, cn=bad rdn, cn=config"
+  };
+
+  // Test child 4 LDIF.
+  private static final String[] TEST_CHILD_4 = new String[] {
+      "dn: cn=test child 4,cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-test-child-dummy",
+      "cn: test child 4",
+      "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-conflict-behavior: virtual-overrides-real",
+      "ds-cfg-backend-base-dn: cn=LDAP Connection Handler, cn=connection handlers, cn=config",
+      "ds-cfg-backend-base-dn: cn=LDAPS Connection Handler, cn=connection handlers, cn=config"
+  };
+
+
+
+  // Assert that the values of child 4 are correct.
+  private void assertChild4(TestChildCfg child) {
+    Assert.assertEquals(child.getMandatoryClassProperty(),
+        "org.opends.server.extensions.UserDefinedVirtualAttributeProvider");
+    Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(),
+        DirectoryServer.getAttributeType("description"));
+    assertSetEquals(child.getAggregationProperty(), "LDAPS Connection Handler",
+        "LDAP Connection Handler");
+  }
+
+  // Test LDIF.
+  private static final String[] TEST_LDIF = new String[] {
+      // Base entries.
+      "dn: cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-branch",
+      "cn: test parents",
+      "",
+      // Parent 1.
+      "dn: cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-test-parent-dummy",
+      "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",
+      "ds-cfg-virtual-attribute-conflict-behavior: virtual-overrides-real",
+      "",
+      // Child base entries.
+      "dn:cn=test children,cn=test parent 1,cn=test parents,cn=config",
+      "objectclass: top",
+      "objectclass: ds-cfg-branch",
+      "cn: test children",
+      ""
+  };
+
+  // JNDI LDAP context.
+  private JNDIDirContextAdaptor adaptor = null;
+
+
+
+  /**
+   * 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();
+    TestCfg.setUp();
+
+    // Add test managed objects.
+    TestCaseUtils.addEntries(TEST_LDIF);
+  }
+
+
+
+  /**
+   * Tears down test environment.
+   *
+   * @throws Exception
+   *           If the test entries could not be removed.
+   */
+  @AfterClass
+  public void tearDown() throws Exception {
+    TestCfg.cleanup();
+
+    // Remove test entries.
+    deleteSubtree("cn=test parents,cn=config");
+  }
+
+
+
+  /**
+   * Tests that aggregation contains no values when it
+   * contains does not contain any DN attribute values.
+   *
+   * @throws Exception
+   *           If the test unexpectedly fails.
+   */
+  @Test
+  public void testAggregationEmpty() throws Exception {
+    // Add the entry.
+    TestCaseUtils.addEntry(TEST_CHILD_1);
+
+    try {
+      TestParentCfg parent = getParent("test parent 1");
+      assertChild1(parent.getTestChild("test child 1"));
+    } finally {
+      deleteSubtree("cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+    }
+  }
+
+
+
+  /**
+   * Tests that aggregation contains single valid value when it
+   * contains a single valid DN attribute values.
+   *
+   * @throws Exception
+   *           If the test unexpectedly fails.
+   */
+  @Test
+  public void testAggregationSingle() throws Exception {
+    // Add the entry.
+    TestCaseUtils.addEntry(TEST_CHILD_2);
+
+    try {
+      TestParentCfg parent = getParent("test parent 1");
+      assertChild2(parent.getTestChild("test child 2"));
+    } finally {
+      deleteSubtree("cn=test child 2,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+    }
+  }
+
+
+
+  /**
+   * Tests that aggregation is rejected when the LDAP DN contains a
+   * valid RDN but an invalid parent DN.
+   *
+   * @throws Exception
+   *           If the test unexpectedly fails.
+   */
+  @Test
+  public void testAggregationBadBaseDN() throws Exception {
+    // Add the entry.
+    TestCaseUtils.addEntry(TEST_CHILD_3);
+
+    try {
+      TestParentCfg parent = getParent("test parent 1");
+      parent.getTestChild("test child 3");
+      Assert
+          .fail("Unexpectedly added test child 3 when it had a bad aggregation value");
+    } catch (ConfigException e) {
+      // Check that we have a decoding exception as the cause and
+      // there was only one cause the illegal property value.
+      Throwable cause = e.getCause();
+      if (cause instanceof ServerManagedObjectDecodingException) {
+        ServerManagedObjectDecodingException de = (ServerManagedObjectDecodingException) cause;
+
+        Collection<PropertyException> causes = de.getCauses();
+        Assert.assertEquals(causes.size(), 1);
+
+        cause = causes.iterator().next();
+        if (cause instanceof IllegalPropertyValueStringException) {
+          IllegalPropertyValueStringException pe = (IllegalPropertyValueStringException) cause;
+          Assert.assertEquals(pe.getPropertyDefinition(), TestChildCfgDefn
+              .getInstance().getAggregationPropertyPropertyDefinition());
+          Assert.assertEquals(pe.getIllegalValueString(),
+              "cn=LDAP Connection Handler, cn=bad rdn, cn=config");
+        } else {
+          // Got an unexpected cause.
+          throw e;
+        }
+      } else {
+        // Got an unexpected cause.
+        throw e;
+      }
+    } finally {
+      deleteSubtree("cn=test child 3,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+    }
+  }
+
+
+
+  /**
+   * Tests that aggregation contains multiple valid values when it
+   * contains a multiple valid DN attribute values.
+   *
+   * @throws Exception
+   *           If the test unexpectedly fails.
+   */
+  @Test
+  public void testAggregationMultipleValues() throws Exception {
+    // Add the entry.
+    TestCaseUtils.addEntry(TEST_CHILD_4);
+
+    try {
+      TestParentCfg parent = getParent("test parent 1");
+      assertChild4(parent.getTestChild("test child 4"));
+    } finally {
+      deleteSubtree("cn=test child 4,cn=test children,cn=test parent 1,cn=test parents,cn=config");
+    }
+  }
+
+
+
+  // Asserts that the actual set of DNs contains the expected values.
+  private void assertSetEquals(SortedSet<String> actual, String... expected) {
+    SortedSet<String> values = new TreeSet<String>(TestChildCfgDefn
+        .getInstance().getAggregationPropertyPropertyDefinition());
+    if (expected != null) {
+      for (String value : expected) {
+        values.add(value);
+      }
+    }
+    Assert.assertEquals((Object) actual, (Object) values);
+  }
+
+
+
+  // Deletes the named sub-tree.
+  private void deleteSubtree(String dn) throws Exception {
+    getAdaptor().deleteSubtree(new LdapName(dn));
+  }
+
+
+
+  // Gets the JNDI connection for the test server instance.
+  private synchronized JNDIDirContextAdaptor getAdaptor() throws Exception {
+    if (adaptor == null) {
+      adaptor = JNDIDirContextAdaptor.simpleBind("127.0.0.1", TestCaseUtils
+          .getServerLdapPort(), "cn=directory manager", "password");
+    }
+    return adaptor;
+  }
+
+
+
+  // Gets the named parent configuration.
+  private TestParentCfg getParent(String name) throws IllegalArgumentException,
+      ConfigException {
+    ServerManagementContext ctx = ServerManagementContext.getInstance();
+    ServerManagedObject<RootCfg> root = ctx.getRootConfigurationManagedObject();
+    TestParentCfg parent = root.getChild(
+        TestCfg.getTestOneToManyParentRelationDefinition(), name)
+        .getConfiguration();
+    return parent;
+  }
+}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ConstraintTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ConstraintTest.java
index a182534..a234ff8 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ConstraintTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ConstraintTest.java
@@ -36,11 +36,8 @@
 import org.opends.messages.Message;
 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.TestChildCfg;
-import org.opends.server.admin.TestChildCfgDefn;
 import org.opends.server.admin.TestParentCfg;
 import org.opends.server.admin.client.ldap.JNDIDirContextAdaptor;
 import org.opends.server.admin.std.server.RootCfg;
@@ -153,7 +150,7 @@
   private static final String[] TEST_CHILD_1 = new String[] {
       "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config",
       "objectclass: top",
-      "objectclass: ds-cfg-virtual-attribute",
+      "objectclass: ds-cfg-test-child-dummy",
       "cn: test child 1",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -173,7 +170,7 @@
       // optional-multi-valued-dn-property.
       "dn: cn=test parent 1,cn=test parents,cn=config",
       "objectclass: top",
-      "objectclass: ds-cfg-virtual-attribute",
+      "objectclass: ds-cfg-test-parent-dummy",
       "cn: test parent 1",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -204,7 +201,7 @@
     // This test suite depends on having the schema available, so
     // we'll start the server.
     TestCaseUtils.startServer();
-    LDAPProfile.getInstance().pushWrapper(new MockLDAPProfile());
+    TestCfg.setUp();
 
     // Add test managed objects.
     TestCaseUtils.addEntries(TEST_LDIF);
@@ -220,7 +217,6 @@
    */
   @AfterClass
   public void tearDown() throws Exception {
-    LDAPProfile.getInstance().popWrapper();
     TestCfg.cleanup();
 
     // Remove test entries.
@@ -242,7 +238,7 @@
     parent.addTestChildAddListener(listener);
 
     MockConstraint constraint = new MockConstraint(true, false, false);
-    TestChildCfgDefn.getInstance().addConstraint(constraint);
+    TestCfg.addConstraint(constraint);
 
     try {
       try {
@@ -256,7 +252,7 @@
         }
       }
     } finally {
-      TestChildCfgDefn.getInstance().removeConstraint(constraint);
+      TestCfg.removeConstraint(constraint);
       parent.removeTestChildAddListener(listener);
     }
   }
@@ -276,7 +272,7 @@
     parent.addTestChildAddListener(listener);
 
     MockConstraint constraint = new MockConstraint(false, true, true);
-    TestChildCfgDefn.getInstance().addConstraint(constraint);
+    TestCfg.addConstraint(constraint);
 
     try {
       try {
@@ -290,7 +286,7 @@
         }
       }
     } finally {
-      TestChildCfgDefn.getInstance().removeConstraint(constraint);
+      TestCfg.removeConstraint(constraint);
       parent.removeTestChildAddListener(listener);
     }
   }
@@ -310,7 +306,7 @@
     parent.addTestChildDeleteListener(listener);
 
     MockConstraint constraint = new MockConstraint(false, false, true);
-    TestChildCfgDefn.getInstance().addConstraint(constraint);
+    TestCfg.addConstraint(constraint);
 
     try {
       // Add the entry.
@@ -319,7 +315,7 @@
       // Now delete it - this should trigger the constraint.
       deleteSubtree(TEST_CHILD_1_DN);
     } finally {
-      TestChildCfgDefn.getInstance().removeConstraint(constraint);
+      TestCfg.removeConstraint(constraint);
       parent.removeTestChildDeleteListener(listener);
 
       try {
@@ -346,7 +342,7 @@
     parent.addTestChildDeleteListener(listener);
 
     MockConstraint constraint = new MockConstraint(true, true, false);
-    TestChildCfgDefn.getInstance().addConstraint(constraint);
+    TestCfg.addConstraint(constraint);
 
     try {
       // Add the entry.
@@ -361,7 +357,7 @@
         // Ignore - this is the expected exception.
       }
     } finally {
-      TestChildCfgDefn.getInstance().removeConstraint(constraint);
+      TestCfg.removeConstraint(constraint);
       parent.removeTestChildDeleteListener(listener);
 
       try {
@@ -386,7 +382,7 @@
     TestParentCfg parent = getParent("test parent 1");
 
     MockConstraint constraint = new MockConstraint(false, true, false);
-    TestChildCfgDefn.getInstance().addConstraint(constraint);
+    TestCfg.addConstraint(constraint);
 
     try {
       // Add the entry.
@@ -412,7 +408,7 @@
       int result = TestCaseUtils.applyModifications(changes);
       Assert.assertEquals(result, ResultCode.SUCCESS.getIntValue());
     } finally {
-      TestChildCfgDefn.getInstance().removeConstraint(constraint);
+      TestCfg.removeConstraint(constraint);
       try {
         deleteSubtree(TEST_CHILD_1_DN);
       } catch (Exception e) {
@@ -434,7 +430,7 @@
     TestParentCfg parent = getParent("test parent 1");
 
     MockConstraint constraint = new MockConstraint(true, false, true);
-    TestChildCfgDefn.getInstance().addConstraint(constraint);
+    TestCfg.addConstraint(constraint);
 
     try {
       // Add the entry.
@@ -461,7 +457,7 @@
       Assert
           .assertEquals(result, ResultCode.UNWILLING_TO_PERFORM.getIntValue());
     } finally {
-      TestChildCfgDefn.getInstance().removeConstraint(constraint);
+      TestCfg.removeConstraint(constraint);
       try {
         deleteSubtree(TEST_CHILD_1_DN);
       } catch (Exception e) {
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DNBuilderTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DNBuilderTest.java
index a79be3a..de0aa89 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DNBuilderTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DNBuilderTest.java
@@ -36,7 +36,6 @@
 import org.opends.server.admin.ConfigurationClient;
 import org.opends.server.admin.LDAPProfile;
 import org.opends.server.admin.ManagedObjectPath;
-import org.opends.server.admin.MockLDAPProfile;
 import org.opends.server.admin.RelationDefinition;
 import org.opends.server.admin.SingletonRelationDefinition;
 import org.opends.server.admin.TestCfg;
@@ -67,7 +66,7 @@
     // This test suite depends on having the schema available, so
     // we'll start the server.
     TestCaseUtils.startServer();
-    LDAPProfile.getInstance().pushWrapper(new MockLDAPProfile());
+    TestCfg.setUp();
   }
 
 
@@ -77,7 +76,6 @@
    */
   @AfterClass
   public void tearDown() {
-    LDAPProfile.getInstance().popWrapper();
     TestCfg.cleanup();
   }
 
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java
index ea90fae..a6e5511 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/DefaultBehaviorTest.java
@@ -33,11 +33,9 @@
 
 import javax.naming.ldap.LdapName;
 
-import org.opends.server.TestCaseUtils;
 import org.opends.messages.Message;
+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.TestChildCfg;
 import org.opends.server.admin.TestParentCfg;
@@ -181,7 +179,7 @@
   private static final String[] TEST_CHILD_1 = new String[] {
       "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config",
       "objectclass: top",
-      "objectclass: ds-cfg-virtual-attribute",
+      "objectclass: ds-cfg-test-child-dummy",
       "cn: test child 1",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -193,7 +191,7 @@
   private static final String[] TEST_CHILD_2 = new String[] {
       "dn: cn=test child 2,cn=test children,cn=test parent 1,cn=test parents,cn=config",
       "objectclass: top",
-      "objectclass: ds-cfg-virtual-attribute",
+      "objectclass: ds-cfg-test-child-dummy",
       "cn: test child 2",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -207,7 +205,7 @@
   private static final String[] TEST_CHILD_3 = new String[] {
       "dn: cn=test child 3,cn=test children,cn=test parent 1,cn=test parents,cn=config",
       "objectclass: top",
-      "objectclass: ds-cfg-virtual-attribute",
+      "objectclass: ds-cfg-test-child-dummy",
       "cn: test child 3",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -223,7 +221,7 @@
   private static final String[] TEST_CHILD_4 = new String[] {
       "dn: cn=test child 4,cn=test children,cn=test parent 2,cn=test parents,cn=config",
       "objectclass: top",
-      "objectclass: ds-cfg-virtual-attribute",
+      "objectclass: ds-cfg-test-child-dummy",
       "cn: test child 4",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -243,7 +241,7 @@
       // optional-multi-valued-dn-property.
       "dn: cn=test parent 1,cn=test parents,cn=config",
       "objectclass: top",
-      "objectclass: ds-cfg-virtual-attribute",
+      "objectclass: ds-cfg-test-parent-dummy",
       "cn: test parent 1",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -254,7 +252,7 @@
       // optional-multi-valued-dn-property.
       "dn: cn=test parent 2,cn=test parents,cn=config",
       "objectclass: top",
-      "objectclass: ds-cfg-virtual-attribute",
+      "objectclass: ds-cfg-test-parent-dummy",
       "cn: test parent 2",
       "ds-cfg-virtual-attribute-enabled: true",
       "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider",
@@ -292,7 +290,7 @@
     // This test suite depends on having the schema available, so
     // we'll start the server.
     TestCaseUtils.startServer();
-    LDAPProfile.getInstance().pushWrapper(new MockLDAPProfile());
+    TestCfg.setUp();
 
     // Add test managed objects.
     TestCaseUtils.addEntries(TEST_LDIF);
@@ -308,7 +306,6 @@
    */
   @AfterClass
   public void tearDown() throws Exception {
-    LDAPProfile.getInstance().popWrapper();
     TestCfg.cleanup();
 
     // Remove test entries.
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ListenerTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ListenerTest.java
index 7fed672..dfb60db 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ListenerTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/ListenerTest.java
@@ -32,11 +32,9 @@
 
 import java.util.List;
 
-import org.opends.server.TestCaseUtils;
 import org.opends.messages.Message;
+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;
@@ -125,7 +123,7 @@
     // This test suite depends on having the schema available, so
     // we'll start the server.
     TestCaseUtils.startServer();
-    LDAPProfile.getInstance().pushWrapper(new MockLDAPProfile());
+    TestCfg.setUp();
   }
 
 
@@ -135,7 +133,6 @@
    */
   @AfterClass
   public void tearDown() {
-    LDAPProfile.getInstance().popWrapper();
     TestCfg.cleanup();
   }
 

--
Gitblit v1.10.0