From b97785a371b09a674dbef8029a99a730ee928e8d Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Wed, 19 Dec 2007 09:55:26 +0000
Subject: [PATCH] Fix for issue 2446 part #1.

---
 opends/resource/admin/preprocessor.xsl                                           |   28 +
 opends/src/server/org/opends/server/admin/RelationDefinitionVisitor.java         |   27 +
 opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java   |    8 
 opends/resource/admin/admin.xsd                                                  |  119 +++++++
 opends/src/server/org/opends/server/admin/OptionalRelationDefinition.java        |   67 +++
 opends/src/server/org/opends/server/admin/client/ldap/JNDIDirContextAdaptor.java |    1 
 opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java     |   15 
 opends/src/server/org/opends/server/admin/client/ManagementContext.java          |    7 
 opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandlerFactory.java |   15 
 opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java            |   19 
 opends/resource/admin/metaMO.xsl                                                 |   60 +++
 opends/src/server/org/opends/server/admin/SingletonRelationDefinition.java       |   68 ++++
 opends/src/server/org/opends/server/admin/client/ldap/LDAPConnection.java        |    4 
 opends/src/server/org/opends/server/admin/RelationDefinition.java                |   14 
 opends/src/server/org/opends/server/admin/client/spi/Driver.java                 |   17 
 opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java    |  101 +++++
 opends/src/server/org/opends/server/admin/DefaultManagedObject.java              |  200 ++++++++++++
 opends/src/server/org/opends/server/admin/client/spi/AbstractManagedObject.java  |  159 +++++++++
 18 files changed, 869 insertions(+), 60 deletions(-)

diff --git a/opends/resource/admin/admin.xsd b/opends/resource/admin/admin.xsd
index 8a8625c..61e07b3 100644
--- a/opends/resource/admin/admin.xsd
+++ b/opends/resource/admin/admin.xsd
@@ -592,6 +592,66 @@
       </xsd:annotation>
     </xsd:attribute>
   </xsd:complexType>
+  <xsd:complexType name="default-managed-object-type">
+    <xsd:annotation>
+      <xsd:documentation>
+        Specifies the configuration of a default managed object which
+        should be created when a parent managed object is created. For
+        example, creation of a back-end could result in default indexes
+        being created.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:element name="property" minOccurs="0"
+        maxOccurs="unbounded">
+        <xsd:annotation>
+          <xsd:documentation>
+            Specifies one or more initial values for a property in the
+            default managed object.
+          </xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexType>
+          <xsd:sequence>
+            <xsd:element name="value" minOccurs="1"
+              maxOccurs="unbounded" type="xsd:string">
+              <xsd:annotation>
+                <xsd:documentation>
+                  The string representation of a value of this property.
+                </xsd:documentation>
+              </xsd:annotation>
+            </xsd:element>
+          </xsd:sequence>
+          <xsd:attribute name="name" type="tns:name-type"
+            use="required">
+            <xsd:annotation>
+              <xsd:documentation>
+                The name of the property.
+              </xsd:documentation>
+            </xsd:annotation>
+          </xsd:attribute>
+        </xsd:complexType>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="managed-object-name" type="tns:name-type"
+      use="optional">
+      <xsd:annotation>
+        <xsd:documentation>
+          The type of default managed object to be created. This must be
+          either the type of the managed object referenced by this
+          relation (this is the default behavior) or a sub-type.
+        </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 default managed object definition
+          if it is not the same as this managed object's package.
+        </xsd:documentation>
+      </xsd:annotation>
+    </xsd:attribute>
+  </xsd:complexType>
   <xsd:complexType name="relation-type">
     <xsd:annotation>
       <xsd:documentation>
@@ -657,7 +717,20 @@
               another type of managed object.
             </xsd:documentation>
           </xsd:annotation>
-          <xsd:complexType />
+          <xsd:complexType>
+            <xsd:sequence>
+              <xsd:element name="default-managed-object"
+                type="tns:default-managed-object-type" minOccurs="0">
+                <xsd:annotation>
+                  <xsd:documentation>
+                    Defines a default managed object configuration which
+                    should be automatically created when the parent
+                    managed object is created.
+                  </xsd:documentation>
+                </xsd:annotation>
+              </xsd:element>
+            </xsd:sequence>
+          </xsd:complexType>
         </xsd:element>
         <xsd:element name="one-to-zero-or-one">
           <xsd:annotation>
@@ -666,7 +739,20 @@
               with another type of managed object.
             </xsd:documentation>
           </xsd:annotation>
-          <xsd:complexType />
+          <xsd:complexType>
+            <xsd:sequence>
+              <xsd:element name="default-managed-object"
+                type="tns:default-managed-object-type" minOccurs="0">
+                <xsd:annotation>
+                  <xsd:documentation>
+                    Defines a default managed object configuration which
+                    should be automatically created when the parent
+                    managed object is created.
+                  </xsd:documentation>
+                </xsd:annotation>
+              </xsd:element>
+            </xsd:sequence>
+          </xsd:complexType>
         </xsd:element>
         <xsd:element name="one-to-many">
           <xsd:annotation>
@@ -676,6 +762,35 @@
             </xsd:documentation>
           </xsd:annotation>
           <xsd:complexType>
+            <xsd:sequence>
+              <xsd:element name="default-managed-object" minOccurs="0"
+                maxOccurs="unbounded">
+                <xsd:annotation>
+                  <xsd:documentation>
+                    Defines one or more default managed object
+                    configurations which should be automatically created
+                    when the parent managed object is created.
+                  </xsd:documentation>
+                </xsd:annotation>
+                <xsd:complexType>
+                  <xsd:complexContent>
+                    <xsd:extension
+                      base="tns:default-managed-object-type">
+                      <xsd:attribute name="name" type="xsd:string"
+                        use="required">
+                        <xsd:annotation>
+                          <xsd:documentation>
+                            Specifies the name that should be used to
+                            identify this default managed object
+                            instance.
+                          </xsd:documentation>
+                        </xsd:annotation>
+                      </xsd:attribute>
+                    </xsd:extension>
+                  </xsd:complexContent>
+                </xsd:complexType>
+              </xsd:element>
+            </xsd:sequence>
             <xsd:attribute name="plural-name" type="tns:name-type"
               use="optional">
               <xsd:annotation>
diff --git a/opends/resource/admin/metaMO.xsl b/opends/resource/admin/metaMO.xsl
index 31341fd..cb23507 100644
--- a/opends/resource/admin/metaMO.xsl
+++ b/opends/resource/admin/metaMO.xsl
@@ -943,6 +943,41 @@
                            'CfgDefn.getInstance().get',
                            $java-property-name, 'PropertyDefinition());&#xa;')" />
     </xsl:if>
+    <xsl:for-each select="*/adm:default-managed-object">
+      <xsl:variable name="dmo-java-name">
+        <xsl:call-template name="name-to-java">
+          <xsl:with-param name="value" select="@managed-object-name" />
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:value-of select="'    {&#xa;'" />
+      <xsl:value-of
+        select="concat('      DefaultManagedObject.Builder&lt;',
+                                   $dmo-java-name, 'CfgClient, ',
+                                   $dmo-java-name, 'Cfg&gt; dmoBuilder = new DefaultManagedObject.Builder&lt;',
+                                   $dmo-java-name, 'CfgClient, ',
+                                   $dmo-java-name, 'Cfg&gt;(',
+                                   $dmo-java-name, 'CfgDefn.getInstance());&#xa;')" />
+      <xsl:for-each select="adm:property">
+        <xsl:value-of
+          select="concat('      dmoBuilder.setPropertyValues(&quot;', @name, '&quot;')" />
+        <xsl:for-each select="adm:value">
+          <xsl:value-of
+            select="concat(', &quot;', normalize-space(), '&quot;')" />
+        </xsl:for-each>
+        <xsl:value-of select="');&#xa;'" />
+      </xsl:for-each>
+      <xsl:choose>
+        <xsl:when test="@name">
+          <xsl:value-of
+            select="concat('      builder.setDefaultManagedObject(&quot;', @name, '&quot;, dmoBuilder.getInstance());&#xa;')" />
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of
+            select="'      builder.setDefaultManagedObject(dmoBuilder.getInstance());&#xa;'" />
+        </xsl:otherwise>
+      </xsl:choose>
+      <xsl:value-of select="'    }&#xa;'" />
+    </xsl:for-each>
     <xsl:if test="@advanced='true'">
       <xsl:value-of
         select="'    builder.setOption(RelationOption.ADVANCED);&#xa;'" />
@@ -1788,6 +1823,31 @@
           </xsl:element>
         </xsl:for-each>
         <xsl:if
+          test="$this-local-relations/*/adm:default-managed-object">
+          <import>org.opends.server.admin.DefaultManagedObject</import>
+        </xsl:if>
+        <xsl:for-each
+          select="$this-local-relations/*/adm:default-managed-object">
+          <xsl:variable name="java-class-name">
+            <xsl:call-template name="name-to-java">
+              <xsl:with-param name="value"
+                select="@managed-object-name" />
+            </xsl:call-template>
+          </xsl:variable>
+          <xsl:element name="import">
+            <xsl:value-of
+              select="concat(@managed-object-package, '.client.', $java-class-name, 'CfgClient')" />
+          </xsl:element>
+          <xsl:element name="import">
+            <xsl:value-of
+              select="concat(@managed-object-package, '.server.', $java-class-name, 'Cfg')" />
+          </xsl:element>
+          <xsl:element name="import">
+            <xsl:value-of
+              select="concat(@managed-object-package, '.meta.', $java-class-name, 'CfgDefn')" />
+          </xsl:element>
+        </xsl:for-each>
+        <xsl:if
           test="$this-local-relations[@advanced='true' or @hidden='true']">
           <import>org.opends.server.admin.RelationOption</import>
         </xsl:if>
diff --git a/opends/resource/admin/preprocessor.xsl b/opends/resource/admin/preprocessor.xsl
index cb2f35c..5e5a57f 100644
--- a/opends/resource/admin/preprocessor.xsl
+++ b/opends/resource/admin/preprocessor.xsl
@@ -852,6 +852,34 @@
     </xsl:copy>
   </xsl:template>
   <!--
+    Merge a default managed object.
+  -->
+  <xsl:template match="adm:default-managed-object" mode="merge-relation">
+    <xsl:param name="managed-object" select="/.." />
+    <xsl:copy>
+      <xsl:copy-of select="@*" />
+      <!--
+        Add missing attribute managed-object-name if it is not provided.
+      -->
+      <xsl:if test="not(@managed-object-name)">
+        <xsl:attribute name="managed-object-name">
+          <xsl:value-of select="$managed-object/@name" />
+        </xsl:attribute>
+      </xsl:if>
+      <!--
+        Add missing attribute managed-object-package if it is not provided.
+      -->
+      <xsl:if test="not(@managed-object-package)">
+        <xsl:attribute name="managed-object-package">
+          <xsl:value-of select="$managed-object/@package" />
+        </xsl:attribute>
+      </xsl:if>
+      <xsl:apply-templates mode="merge-relation">
+        <xsl:with-param name="managed-object" select="$managed-object" />
+      </xsl:apply-templates>
+    </xsl:copy>
+  </xsl:template>
+  <!--
     Merge a one-to-many relation.
   -->
   <xsl:template match="adm:one-to-many" mode="merge-relation">
diff --git a/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java b/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
index 10fbd64..a4b5f79 100644
--- a/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
+++ b/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
@@ -749,8 +749,8 @@
 
 
   /**
-   * Initializes all of the property definitions associated with this
-   * managed object definition.
+   * Initializes all of the components associated with this managed
+   * object definition.
    *
    * @throws Exception
    *           If this managed object definition could not be
@@ -762,6 +762,10 @@
       pd.getDefaultBehaviorProvider().initialize();
     }
 
+    for (RelationDefinition<?, ?> rd : getAllRelationDefinitions()) {
+      rd.initialize();
+    }
+
     for (Constraint constraint : getAllConstraints()) {
       constraint.initialize();
     }
diff --git a/opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java b/opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java
index d93c0ac..006504e 100644
--- a/opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java
+++ b/opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java
@@ -681,8 +681,9 @@
       /**
        * {@inheritDoc}
        */
-      public Void visitInstantiable(InstantiableRelationDefinition<?, ?> rd,
-          ManagedObject<?> p) {
+      public <CC extends ConfigurationClient, SS extends Configuration>
+          Void visitInstantiable(
+          InstantiableRelationDefinition<CC, SS> rd, ManagedObject<?> p) {
         try {
           for (String childName : p.listChildren(rd)) {
             find(p.getChild(rd, childName));
@@ -702,8 +703,9 @@
       /**
        * {@inheritDoc}
        */
-      public Void visitOptional(OptionalRelationDefinition<?, ?> rd,
-          ManagedObject<?> p) {
+      public <CC extends ConfigurationClient, SS extends Configuration>
+          Void visitOptional(
+          OptionalRelationDefinition<CC, SS> rd, ManagedObject<?> p) {
         try {
           find(p.getChild(rd));
         } catch (AuthorizationException e) {
@@ -721,8 +723,9 @@
       /**
        * {@inheritDoc}
        */
-      public Void visitSingleton(SingletonRelationDefinition<?, ?> rd,
-          ManagedObject<?> p) {
+      public <CC extends ConfigurationClient, SS extends Configuration>
+          Void visitSingleton(
+          SingletonRelationDefinition<CC, SS> rd, ManagedObject<?> p) {
         try {
           find(p.getChild(rd));
         } catch (AuthorizationException e) {
diff --git a/opends/src/server/org/opends/server/admin/DefaultManagedObject.java b/opends/src/server/org/opends/server/admin/DefaultManagedObject.java
new file mode 100644
index 0000000..374657a
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/DefaultManagedObject.java
@@ -0,0 +1,200 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+
+
+/**
+ * A default managed object which should be created when a parent
+ * managed object is created. Default managed objects are associated
+ * with a {@link RelationDefinition}.
+ *
+ * @param <C>
+ *          The type of client default managed object configuration.
+ * @param <S>
+ *          The type of server default managed object configuration.
+ */
+public final class DefaultManagedObject
+    <C extends ConfigurationClient, S extends Configuration>
+    implements PropertyProvider {
+
+  /**
+   * An interface for incrementally constructing default managed
+   * objects.
+   *
+   * @param <C>
+   *          The type of client default managed object configuration.
+   * @param <S>
+   *          The type of server default managed object configuration.
+   */
+  public static final class Builder
+      <C extends ConfigurationClient, S extends Configuration> {
+
+    // The default managed object's definition.
+    private final ManagedObjectDefinition<C, S> definition;
+
+    // The string encoded default managed object's properties.
+    private final Map<String, List<String>> propertyStringValues =
+      new HashMap<String, List<String>>();
+
+
+
+    /**
+     * Creates a new default managed object builder.
+     *
+     * @param definition
+     *          The default managed object's definition.
+     */
+    public Builder(ManagedObjectDefinition<C, S> definition) {
+      this.definition = definition;
+    }
+
+
+
+    /**
+     * Construct a default managed object based on the properties of
+     * this builder.
+     *
+     * @return Returns the new default managed object.
+     */
+    public DefaultManagedObject<C, S> getInstance() {
+      return new DefaultManagedObject<C, S>(definition, propertyStringValues);
+    }
+
+
+
+    /**
+     * Defines a property's values for the default managed object.
+     *
+     * @param name
+     *          The name of the property.
+     * @param values
+     *          One or more property values in the string
+     *          representation.
+     */
+    public void setPropertyValues(String name, String... values) {
+      if (values == null || values.length == 0) {
+        throw new IllegalArgumentException(
+            "null or empty values specified for property " + name);
+      }
+
+      propertyStringValues.put(name, Arrays.asList(values));
+    }
+  }
+
+  // The default managed object's definition.
+  private final ManagedObjectDefinition<C, S> definition;
+
+  // The string encoded default managed object's properties.
+  private final Map<String, List<String>> propertyStringValues;
+
+
+
+  // Private constructor.
+  private DefaultManagedObject(ManagedObjectDefinition<C, S> definition,
+      Map<String, List<String>> propertyStringValues) {
+    this.definition = definition;
+    this.propertyStringValues = propertyStringValues;
+  }
+
+
+
+  /**
+   * Gets the managed object definition associated with this default
+   * managed object.
+   *
+   * @return Returns the managed object definition associated with
+   *         this default managed object.
+   */
+  public ManagedObjectDefinition<C, S> getManagedObjectDefinition() {
+    return definition;
+  }
+
+
+
+  /**
+   * Gets a mutable copy of the set of property values for the
+   * specified property.
+   *
+   * @param <T>
+   *          The type of the property to be retrieved.
+   * @param pd
+   *          The property to be retrieved.
+   * @return Returns a newly allocated set containing a copy of the
+   *         property's values. An empty set indicates that the
+   *         property has no values defined and any default behavior
+   *         is applicable.
+   * @throws IllegalArgumentException
+   *           If the property definition is not associated with this
+   *           managed object's definition.
+   */
+  public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> pd)
+      throws IllegalArgumentException {
+    // Validate the property definition.
+    definition.getPropertyDefinition(pd.getName());
+
+    // Do a defensive copy.
+    SortedSet<T> values = new TreeSet<T>(pd);
+    List<String> stringValues = propertyStringValues.get(pd.getName());
+    if (stringValues != null) {
+      for (String stringValue : stringValues) {
+        values.add(pd.decodeValue(stringValue));
+      }
+    }
+    return values;
+  }
+
+
+
+  /**
+   * Performs run-time initialization of properties.
+   *
+   * @throws Exception
+   *           If this default managed object could not be
+   *           initialized.
+   */
+  void initialize() throws Exception {
+    // FIXME: it would be nice if we could decode all property values
+    // at this point. However this is not possible on the server side
+    // since some properties will be determined to be invalid since
+    // the schema is not loaded.
+
+    // Validate provided property names.
+    for (String name : propertyStringValues.keySet()) {
+      definition.getPropertyDefinition(name);
+    }
+  }
+}
diff --git a/opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java b/opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java
index 229ca16..7097e52 100644
--- a/opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java
+++ b/opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java
@@ -32,7 +32,11 @@
 
 import static org.opends.server.util.Validator.*;
 
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
 
 
 
@@ -62,16 +66,21 @@
    *          The type of server managed object configuration that
    *          this relation definition refers to.
    */
-  public static class Builder
+  public static final class Builder
       <C extends ConfigurationClient, S extends Configuration>
       extends AbstractBuilder<C, S, InstantiableRelationDefinition<C, S>> {
 
     // The optional naming property definition.
-    private PropertyDefinition<?> namingPropertyDefinition;
+    private PropertyDefinition<?> namingPropertyDefinition = null;
 
     // The plural name of the relation.
     private final String pluralName;
 
+    // The optional default managed objects associated with this
+    // instantiable relation definition.
+    private final Map<String, DefaultManagedObject<? extends C, ? extends S>>
+      defaultManagedObjects = new HashMap<String,
+        DefaultManagedObject<? extends C, ? extends S>>();
 
 
     /**
@@ -96,6 +105,22 @@
 
 
     /**
+     * Adds the named default managed object to this instantiable
+     * relation definition.
+     *
+     * @param name
+     *          The name of the default managed object.
+     * @param defaultManagedObject
+     *          The default managed object.
+     */
+    public void setDefaultManagedObject(String name,
+        DefaultManagedObject<? extends C, ? extends S> defaultManagedObject) {
+      this.defaultManagedObjects.put(name, defaultManagedObject);
+    }
+
+
+
+    /**
      * Sets the naming property for the instantiable relation
      * definition.
      *
@@ -104,7 +129,7 @@
      *          which should be used for naming, or <code>null</code>
      *          if this relation does not use a property for naming.
      */
-    public final void setNamingProperty(
+    public void setNamingProperty(
         PropertyDefinition<?> namingPropertyDefinition) {
       ensureNotNull(namingPropertyDefinition);
       this.namingPropertyDefinition = namingPropertyDefinition;
@@ -119,7 +144,7 @@
     protected InstantiableRelationDefinition<C, S> buildInstance(
         Common<C, S> common) {
       return new InstantiableRelationDefinition<C, S>(common, pluralName,
-          namingPropertyDefinition);
+          namingPropertyDefinition, defaultManagedObjects);
     }
 
   }
@@ -130,14 +155,23 @@
   // The plural name of the relation.
   private final String pluralName;
 
+  // The optional default managed objects associated with this
+  // instantiable relation definition.
+  private final Map<String, DefaultManagedObject<? extends C, ? extends S>>
+    defaultManagedObjects;
+
 
 
   // Private constructor.
   private InstantiableRelationDefinition(Common<C, S> common,
-      String pluralName, PropertyDefinition<?> namingPropertyDefinition) {
+      String pluralName,
+      PropertyDefinition<?> namingPropertyDefinition,
+      Map<String, DefaultManagedObject<? extends C, ? extends S>>
+        defaultManagedObjects) {
     super(common);
     this.pluralName = pluralName;
     this.namingPropertyDefinition = namingPropertyDefinition;
+    this.defaultManagedObjects = defaultManagedObjects;
   }
 
 
@@ -153,6 +187,41 @@
 
 
   /**
+   * Gets the named default managed object associated with this
+   * instantiable relation definition.
+   *
+   * @param name
+   *          The name of the default managed object.
+   * @return Returns the named default managed object.
+   * @throws IllegalArgumentException
+   *           If there is no default managed object associated with
+   *           the provided name.
+   */
+  public DefaultManagedObject<? extends C, ? extends S> getDefaultManagedObject(
+      String name) throws IllegalArgumentException {
+    if (!defaultManagedObjects.containsKey(name)) {
+      throw new IllegalArgumentException(
+          "unrecognized default managed object \"" + name + "\"");
+    }
+    return defaultManagedObjects.get(name);
+  }
+
+
+
+  /**
+   * Gets the names of the default managed objects associated with
+   * this instantiable relation definition.
+   *
+   * @return Returns an unmodifiable set containing the names of the
+   *         default managed object.
+   */
+  public Set<String> getDefaultManagedObjectNames() {
+    return Collections.unmodifiableSet(defaultManagedObjects.keySet());
+  }
+
+
+
+  /**
    * Get the property of the child managed object definition which
    * should be used for naming children.
    *
@@ -161,7 +230,7 @@
    *         <code>null</code> if this relation does not use a
    *         property for naming.
    */
-  public final PropertyDefinition<?> getNamingPropertyDefinition() {
+  public PropertyDefinition<?> getNamingPropertyDefinition() {
     return namingPropertyDefinition;
   }
 
@@ -172,7 +241,7 @@
    *
    * @return Returns the plural name of the relation.
    */
-  public final String getPluralName() {
+  public String getPluralName() {
     return pluralName;
   }
 
@@ -185,7 +254,7 @@
    * @return Returns the user friendly plural name of this relation
    *         definition in the default locale.
    */
-  public final Message getUserFriendlyPluralName() {
+  public Message getUserFriendlyPluralName() {
     return getUserFriendlyPluralName(Locale.getDefault());
   }
 
@@ -200,7 +269,7 @@
    * @return Returns the user friendly plural name of this relation
    *         definition in the specified locale.
    */
-  public final Message getUserFriendlyPluralName(Locale locale) {
+  public Message getUserFriendlyPluralName(Locale locale) {
     String property = "relation." + getName() + ".user-friendly-plural-name";
     return ManagedObjectDefinitionI18NResource.getInstance().getMessage(
         getParentDefinition(), property, locale);
@@ -212,7 +281,7 @@
    * {@inheritDoc}
    */
   @Override
-  public final void toString(StringBuilder builder) {
+  public void toString(StringBuilder builder) {
     builder.append("name=");
     builder.append(getName());
     builder.append(" type=composition parent=");
@@ -223,4 +292,16 @@
     builder.append(getChildDefinition().getName());
     builder.append(" minOccurs=0");
   }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected void initialize() throws Exception {
+    for (DefaultManagedObject<?, ?> dmo : defaultManagedObjects.values()) {
+      dmo.initialize();
+    }
+  }
 }
diff --git a/opends/src/server/org/opends/server/admin/OptionalRelationDefinition.java b/opends/src/server/org/opends/server/admin/OptionalRelationDefinition.java
index 7a5a6c5..dbf0c18 100644
--- a/opends/src/server/org/opends/server/admin/OptionalRelationDefinition.java
+++ b/opends/src/server/org/opends/server/admin/OptionalRelationDefinition.java
@@ -56,10 +56,17 @@
    *          The type of server managed object configuration that
    *          this relation definition refers to.
    */
-  public static class Builder
+  public static final class Builder
       <C extends ConfigurationClient, S extends Configuration>
       extends AbstractBuilder<C, S, OptionalRelationDefinition<C, S>> {
 
+    // The optional default managed object associated with this
+    // optional relation.
+    private DefaultManagedObject<? extends C, ? extends S>
+      defaultManagedObject = null;
+
+
+
     /**
      * Creates a new builder which can be used to incrementally build
      * an optional relation definition.
@@ -79,21 +86,46 @@
 
 
     /**
+     * Sets the optional default managed object associated with this
+     * optional relation definition.
+     *
+     * @param defaultManagedObject
+     *          The default managed object or <code>null</code> if
+     *          there is no default managed object defined for this
+     *          relation definition.
+     */
+    public void setDefaultManagedObject(
+        DefaultManagedObject<? extends C, ? extends S> defaultManagedObject) {
+      this.defaultManagedObject = defaultManagedObject;
+    }
+
+
+
+    /**
      * {@inheritDoc}
      */
     @Override
     protected OptionalRelationDefinition<C, S> buildInstance(
         Common<C, S> common) {
-      return new OptionalRelationDefinition<C, S>(common);
+      return new OptionalRelationDefinition<C, S>(common, defaultManagedObject);
     }
 
   }
 
 
 
+  // The optional default managed object associated with this
+  // optional relation.
+  private final DefaultManagedObject<? extends C, ? extends S>
+    defaultManagedObject;
+
+
+
   // Private constructor.
-  private OptionalRelationDefinition(Common<C, S> common) {
+  private OptionalRelationDefinition(Common<C, S> common,
+      DefaultManagedObject<? extends C, ? extends S> defaultManagedObject) {
     super(common);
+    this.defaultManagedObject = defaultManagedObject;
   }
 
 
@@ -109,10 +141,25 @@
 
 
   /**
+   * Gets the optional default managed object associated with this
+   * optional relation definition.
+   *
+   * @return Returns the default managed object or <code>null</code>
+   *         if there is no default managed object defined for this
+   *         relation definition.
+   */
+  public DefaultManagedObject<? extends C, ? extends S>
+      getDefaultManagedObject() {
+    return defaultManagedObject;
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   @Override
-  public final void toString(StringBuilder builder) {
+  public void toString(StringBuilder builder) {
     builder.append("name=");
     builder.append(getName());
     builder.append(" type=composition parent=");
@@ -122,4 +169,16 @@
     builder.append(" minOccurs=0 maxOccurs=1");
   }
 
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected void initialize() throws Exception {
+    if (defaultManagedObject != null) {
+      defaultManagedObject.initialize();
+    }
+  }
+
 }
diff --git a/opends/src/server/org/opends/server/admin/RelationDefinition.java b/opends/src/server/org/opends/server/admin/RelationDefinition.java
index 0b7cfb3..80e982c 100644
--- a/opends/src/server/org/opends/server/admin/RelationDefinition.java
+++ b/opends/src/server/org/opends/server/admin/RelationDefinition.java
@@ -400,4 +400,18 @@
    *          should be appended.
    */
   public abstract void toString(StringBuilder builder);
+
+
+
+  /**
+   * Performs any run-time initialization required by this relation
+   * definition. This may include resolving managed object paths and
+   * property names.
+   *
+   * @throws Exception
+   *           If this relation definition could not be initialized.
+   */
+  protected void initialize() throws Exception {
+    // No implementation required.
+  }
 }
diff --git a/opends/src/server/org/opends/server/admin/RelationDefinitionVisitor.java b/opends/src/server/org/opends/server/admin/RelationDefinitionVisitor.java
index 1b41411..e3db527 100644
--- a/opends/src/server/org/opends/server/admin/RelationDefinitionVisitor.java
+++ b/opends/src/server/org/opends/server/admin/RelationDefinitionVisitor.java
@@ -52,38 +52,59 @@
   /**
    * Visit an instantiable relation definition.
    *
+   * @param <C>
+   *          The type of client managed object configuration that the
+   *          relation definition refers to.
+   * @param <S>
+   *          The type of server managed object configuration that the
+   *          relation definition refers to.
    * @param rd
    *          The instantiable relation definition to visit.
    * @param p
    *          A visitor specified parameter.
    * @return Returns a visitor specified result.
    */
-  R visitInstantiable(InstantiableRelationDefinition<?, ?> rd, P p);
+  <C extends ConfigurationClient, S extends Configuration> R visitInstantiable(
+      InstantiableRelationDefinition<C, S> rd, P p);
 
 
 
   /**
    * Visit an optional relation definition.
    *
+   * @param <C>
+   *          The type of client managed object configuration that the
+   *          relation definition refers to.
+   * @param <S>
+   *          The type of server managed object configuration that the
+   *          relation definition refers to.
    * @param rd
    *          The optional relation definition to visit.
    * @param p
    *          A visitor specified parameter.
    * @return Returns a visitor specified result.
    */
-  R visitOptional(OptionalRelationDefinition<?, ?> rd, P p);
+  <C extends ConfigurationClient, S extends Configuration> R visitOptional(
+      OptionalRelationDefinition<C, S> rd, P p);
 
 
 
   /**
    * Visit a singleton relation definition.
    *
+   * @param <C>
+   *          The type of client managed object configuration that the
+   *          relation definition refers to.
+   * @param <S>
+   *          The type of server managed object configuration that the
+   *          relation definition refers to.
    * @param rd
    *          The singleton relation definition to visit.
    * @param p
    *          A visitor specified parameter.
    * @return Returns a visitor specified result.
    */
-  R visitSingleton(SingletonRelationDefinition<?, ?> rd, P p);
+  <C extends ConfigurationClient, S extends Configuration> R visitSingleton(
+      SingletonRelationDefinition<C, S> rd, P p);
 
 }
diff --git a/opends/src/server/org/opends/server/admin/SingletonRelationDefinition.java b/opends/src/server/org/opends/server/admin/SingletonRelationDefinition.java
index a2eccaa..27a3b78 100644
--- a/opends/src/server/org/opends/server/admin/SingletonRelationDefinition.java
+++ b/opends/src/server/org/opends/server/admin/SingletonRelationDefinition.java
@@ -56,10 +56,17 @@
    *          The type of server managed object configuration that
    *          this relation definition refers to.
    */
-  public static class Builder
+  public static final class Builder
       <C extends ConfigurationClient, S extends Configuration>
       extends AbstractBuilder<C, S, SingletonRelationDefinition<C, S>> {
 
+    // The optional default managed object associated with this
+    // singleton relation.
+    private DefaultManagedObject<? extends C, ? extends S>
+      defaultManagedObject = null;
+
+
+
     /**
      * Creates a new builder which can be used to incrementally build
      * an singleton relation definition.
@@ -79,21 +86,47 @@
 
 
     /**
+     * Sets the optional default managed object associated with this
+     * singleton relation definition.
+     *
+     * @param defaultManagedObject
+     *          The default managed object or <code>null</code> if
+     *          there is no default managed object defined for this
+     *          relation definition.
+     */
+    public void setDefaultManagedObject(
+        DefaultManagedObject<? extends C, ? extends S> defaultManagedObject) {
+      this.defaultManagedObject = defaultManagedObject;
+    }
+
+
+
+    /**
      * {@inheritDoc}
      */
     @Override
     protected SingletonRelationDefinition<C, S> buildInstance(
         Common<C, S> common) {
-      return new SingletonRelationDefinition<C, S>(common);
+      return new SingletonRelationDefinition<C, S>(common,
+          defaultManagedObject);
     }
 
   }
 
 
 
+  // The optional default managed object associated with this
+  // singleton relation.
+  private final DefaultManagedObject<? extends C, ? extends S>
+    defaultManagedObject;
+
+
+
   // Private constructor.
-  private SingletonRelationDefinition(Common<C, S> common) {
+  private SingletonRelationDefinition(Common<C, S> common,
+      DefaultManagedObject<? extends C, ? extends S> defaultManagedObject) {
     super(common);
+    this.defaultManagedObject = defaultManagedObject;
   }
 
 
@@ -109,10 +142,25 @@
 
 
   /**
+   * Gets the optional default managed object associated with this
+   * singleton relation definition.
+   *
+   * @return Returns the default managed object or <code>null</code>
+   *         if there is no default managed object defined for this
+   *         relation definition.
+   */
+  public DefaultManagedObject<? extends C, ? extends S>
+      getDefaultManagedObject() {
+    return defaultManagedObject;
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   @Override
-  public final void toString(StringBuilder builder) {
+  public void toString(StringBuilder builder) {
     builder.append("name=");
     builder.append(getName());
     builder.append(" type=composition parent=");
@@ -122,4 +170,16 @@
     builder.append(" minOccurs=1 maxOccurs=1");
   }
 
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected void initialize() throws Exception {
+    if (defaultManagedObject != null) {
+      defaultManagedObject.initialize();
+    }
+  }
+
 }
diff --git a/opends/src/server/org/opends/server/admin/client/ManagementContext.java b/opends/src/server/org/opends/server/admin/client/ManagementContext.java
index 1849260..72d9bae 100644
--- a/opends/src/server/org/opends/server/admin/client/ManagementContext.java
+++ b/opends/src/server/org/opends/server/admin/client/ManagementContext.java
@@ -425,11 +425,10 @@
 
 
 
- /**
-   * Close the associated management context.
-   *
+  /**
+   * Closes this management context.
    */
-  public void close() {
+  public final void close() {
     this.getDriver().close();
   }
 
diff --git a/opends/src/server/org/opends/server/admin/client/ldap/JNDIDirContextAdaptor.java b/opends/src/server/org/opends/server/admin/client/ldap/JNDIDirContextAdaptor.java
index 8cd4c5b..65fbed3 100644
--- a/opends/src/server/org/opends/server/admin/client/ldap/JNDIDirContextAdaptor.java
+++ b/opends/src/server/org/opends/server/admin/client/ldap/JNDIDirContextAdaptor.java
@@ -243,6 +243,7 @@
   }
 
 
+
   /**
    * {@inheritDoc}
    */
diff --git a/opends/src/server/org/opends/server/admin/client/ldap/LDAPConnection.java b/opends/src/server/org/opends/server/admin/client/ldap/LDAPConnection.java
index 5e1f207..8a2592e 100644
--- a/opends/src/server/org/opends/server/admin/client/ldap/LDAPConnection.java
+++ b/opends/src/server/org/opends/server/admin/client/ldap/LDAPConnection.java
@@ -141,9 +141,9 @@
       throws NamingException;
 
 
+
   /**
-   * Close the associated management context.
-   *
+   * Closes the LDAP connection.
    */
   public abstract void unbind();
 }
diff --git a/opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java b/opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java
index 7f790ec..48e8064 100644
--- a/opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java
+++ b/opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java
@@ -192,6 +192,16 @@
    * {@inheritDoc}
    */
   @Override
+  public void close() {
+    connection.unbind();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
   public <C extends ConfigurationClient, S extends Configuration>
   ManagedObject<? extends C> getManagedObject(
       ManagedObjectPath<C, S> path) throws DefinitionDecodingException,
@@ -408,15 +418,6 @@
   }
 
 
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public void close() {
-    connection.unbind();
-  }
-
-
 
   /**
    * {@inheritDoc}
diff --git a/opends/src/server/org/opends/server/admin/client/spi/AbstractManagedObject.java b/opends/src/server/org/opends/server/admin/client/spi/AbstractManagedObject.java
index f7fc2a9..c9a729f 100644
--- a/opends/src/server/org/opends/server/admin/client/spi/AbstractManagedObject.java
+++ b/opends/src/server/org/opends/server/admin/client/spi/AbstractManagedObject.java
@@ -42,6 +42,7 @@
 import org.opends.server.admin.ConfigurationClient;
 import org.opends.server.admin.Constraint;
 import org.opends.server.admin.DefaultBehaviorException;
+import org.opends.server.admin.DefaultManagedObject;
 import org.opends.server.admin.DefinitionDecodingException;
 import org.opends.server.admin.IllegalPropertyValueException;
 import org.opends.server.admin.IllegalPropertyValueStringException;
@@ -57,6 +58,7 @@
 import org.opends.server.admin.PropertyIsSingleValuedException;
 import org.opends.server.admin.PropertyOption;
 import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.RelationDefinitionVisitor;
 import org.opends.server.admin.SingletonRelationDefinition;
 import org.opends.server.admin.client.AuthorizationException;
 import org.opends.server.admin.client.ClientConstraintHandler;
@@ -82,6 +84,150 @@
 public abstract class AbstractManagedObject<T extends ConfigurationClient>
     implements ManagedObject<T> {
 
+  /**
+   * Creates any default managed objects associated with a relation
+   * definition.
+   */
+  private final class DefaultManagedObjectFactory implements
+      RelationDefinitionVisitor<Void, Void> {
+
+    // Possible exceptions.
+    private AuthorizationException ae = null;
+
+    private ManagedObjectAlreadyExistsException moaee = null;
+
+    private MissingMandatoryPropertiesException mmpe = null;
+
+    private ConcurrentModificationException cme = null;
+
+    private OperationRejectedException ore = null;
+
+    private CommunicationException ce = null;
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <C extends ConfigurationClient, S extends Configuration>
+        Void visitInstantiable(
+        InstantiableRelationDefinition<C, S> rd, Void p) {
+      for (String name : rd.getDefaultManagedObjectNames()) {
+        DefaultManagedObject<? extends C, ? extends S> dmo = rd
+            .getDefaultManagedObject(name);
+        ManagedObjectDefinition<? extends C, ? extends S> d = dmo
+            .getManagedObjectDefinition();
+        ManagedObject<? extends C> child;
+        try {
+          child = createChild(rd, d, name, null);
+        } catch (IllegalManagedObjectNameException e) {
+          // This should not happen.
+          throw new RuntimeException(e);
+        }
+        createDefaultManagedObject(d, child, dmo);
+      }
+      return null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <C extends ConfigurationClient, S extends Configuration>
+        Void visitOptional(
+        OptionalRelationDefinition<C, S> rd, Void p) {
+      if (rd.getDefaultManagedObject() != null) {
+        DefaultManagedObject<? extends C, ? extends S> dmo = rd
+            .getDefaultManagedObject();
+        ManagedObjectDefinition<? extends C, ? extends S> d = dmo
+            .getManagedObjectDefinition();
+        ManagedObject<? extends C> child = createChild(rd, d, null);
+        createDefaultManagedObject(d, child, dmo);
+      }
+      return null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <C extends ConfigurationClient, S extends Configuration>
+        Void visitSingleton(
+        SingletonRelationDefinition<C, S> rd, Void p) {
+      // Do nothing - not possible to create singletons
+      // dynamically.
+      return null;
+    }
+
+
+
+    // Create the child managed object.
+    private void createDefaultManagedObject(ManagedObjectDefinition<?, ?> d,
+        ManagedObject<?> child, DefaultManagedObject<?, ?> dmo) {
+      for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
+        setPropertyValues(child, pd, dmo);
+      }
+
+      try {
+        child.commit();
+      } catch (AuthorizationException e) {
+        ae = e;
+      } catch (ManagedObjectAlreadyExistsException e) {
+        moaee = e;
+      } catch (MissingMandatoryPropertiesException e) {
+        mmpe = e;
+      } catch (ConcurrentModificationException e) {
+        cme = e;
+      } catch (OperationRejectedException e) {
+        ore = e;
+      } catch (CommunicationException e) {
+        ce = e;
+      }
+    }
+
+
+
+    /**
+     * Creates the default managed objects associated with the
+     * provided relation definition.
+     *
+     * @param rd
+     *          The relation definition.
+     */
+    private void createDefaultManagedObjects(RelationDefinition<?, ?> rd)
+        throws AuthorizationException, CommunicationException,
+        ConcurrentModificationException, MissingMandatoryPropertiesException,
+        ManagedObjectAlreadyExistsException, OperationRejectedException {
+      rd.accept(this, null);
+
+      if (ae != null) {
+        throw ae;
+      } else if (ce != null) {
+        throw ce;
+      } else if (cme != null) {
+        throw cme;
+      } else if (mmpe != null) {
+        throw mmpe;
+      } else if (moaee != null) {
+        throw moaee;
+      } else if (ore != null) {
+        throw ore;
+      }
+    }
+
+
+
+    // Set property values.
+    private <PD> void setPropertyValues(ManagedObject<?> mo,
+        PropertyDefinition<PD> pd, DefaultManagedObject<?, ?> dmo) {
+      mo.setPropertyValues(pd, dmo.getPropertyValues(pd));
+    }
+  }
+
+
+
   // The managed object definition associated with this managed
   // object.
   private final ManagedObjectDefinition<T, ? extends Configuration> definition;
@@ -191,11 +337,22 @@
       modifyExistingManagedObject();
     } else {
       addNewManagedObject();
-      existsOnServer = true;
     }
 
     // Make all pending property values active.
     properties.commit();
+
+    // If the managed object was created make sure that any default
+    // subordinate managed objects are also created.
+    if (!existsOnServer) {
+      DefaultManagedObjectFactory factory = new DefaultManagedObjectFactory();
+      for (RelationDefinition<?, ?> rd :
+          definition.getAllRelationDefinitions()) {
+        factory.createDefaultManagedObjects(rd);
+      }
+
+      existsOnServer = true;
+    }
   }
 
 
diff --git a/opends/src/server/org/opends/server/admin/client/spi/Driver.java b/opends/src/server/org/opends/server/admin/client/spi/Driver.java
index c4ae4ea..32201bc 100644
--- a/opends/src/server/org/opends/server/admin/client/spi/Driver.java
+++ b/opends/src/server/org/opends/server/admin/client/spi/Driver.java
@@ -295,6 +295,16 @@
 
 
   /**
+   * Closes any context associated with this management context
+   * driver.
+   */
+  public void close() {
+    // do nothing by default
+  }
+
+
+
+  /**
    * Deletes the named instantiable child managed object from the
    * named parent managed object.
    *
@@ -656,13 +666,6 @@
       CommunicationException;
 
 
-  /**
-   * Close the associated management context.
-   *
-   */
-  public void close() {
-    // do nothing by default
-  }
 
   /**
    * Deletes the named managed object.
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandlerFactory.java b/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandlerFactory.java
index d9b00e1..82b1f12 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandlerFactory.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandlerFactory.java
@@ -62,8 +62,9 @@
     /**
      * {@inheritDoc}
      */
-    public Void visitInstantiable(InstantiableRelationDefinition<?, ?> rd,
-        ManagedObjectPath<?, ?> p) {
+    public <C extends ConfigurationClient, S extends Configuration>
+        Void visitInstantiable(
+        InstantiableRelationDefinition<C, S> rd, ManagedObjectPath<?, ?> p) {
       try {
         // Create the sub-commands.
         createHandlers.add(CreateSubCommandHandler.create(parser, p, rd));
@@ -87,8 +88,9 @@
     /**
      * {@inheritDoc}
      */
-    public Void visitOptional(OptionalRelationDefinition<?, ?> rd,
-        ManagedObjectPath<?, ?> p) {
+    public <C extends ConfigurationClient, S extends Configuration>
+        Void visitOptional(
+        OptionalRelationDefinition<C, S> rd, ManagedObjectPath<?, ?> p) {
       try {
         // Create the sub-commands.
         createHandlers.add(CreateSubCommandHandler.create(parser, p, rd));
@@ -112,8 +114,9 @@
     /**
      * {@inheritDoc}
      */
-    public Void visitSingleton(SingletonRelationDefinition<?, ?> rd,
-        ManagedObjectPath<?, ?> p) {
+    public <C extends ConfigurationClient, S extends Configuration>
+        Void visitSingleton(
+        SingletonRelationDefinition<C, S> rd, ManagedObjectPath<?, ?> p) {
       try {
         // Create the sub-commands.
         getPropHandlers.add(GetPropSubCommandHandler.create(parser, p, rd));

--
Gitblit v1.10.0