mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

matthew_swift
19.55.2007 b97785a371b09a674dbef8029a99a730ee928e8d
Fix for issue 2446 part #1.

Add support to the admin framework for specifying one or more "default" managed objects which should be created automatically when a parent managed object is created. The XML mark-up is provided as part of the parent managed object's relation definition as follows (the sample is taken from the LocalDBBackend XML definition):

<adm:relation name="local-db-index">
<adm:one-to-many naming-property="attribute">

<adm:default-managed-object name="aci">
<adm:property name="index-type">
<adm:value>presence</adm:value>
</adm:property>
<adm:property name="attribute">
<adm:value>aci</adm:value>
</adm:property>
</adm:default-managed-object>

<adm:default-managed-object name="entryUUID">
<adm:property name="index-type">
<adm:value>equality</adm:value>
</adm:property>
<adm:property name="attribute">
<adm:value>entryUUID</adm:value>
</adm:property>
</adm:default-managed-object>

<adm:default-managed-object name="objectClass">
<adm:property name="index-type">
<adm:value>equality</adm:value>
</adm:property>
<adm:property name="attribute">
<adm:value>objectClass</adm:value>
</adm:property>
</adm:default-managed-object>
</adm:one-to-many>

The functionality is implemented on the client-side API in a generic manner so that it is independent of the underlying driver implementation (so the default indexes would be created if we had an offline direct to file driver as well).

1 files added
17 files modified
929 ■■■■■ changed files
opends/resource/admin/admin.xsd 119 ●●●●● patch | view | raw | blame | history
opends/resource/admin/metaMO.xsl 60 ●●●●● patch | view | raw | blame | history
opends/resource/admin/preprocessor.xsl 28 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java 8 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java 15 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/DefaultManagedObject.java 200 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java 101 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/OptionalRelationDefinition.java 67 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/RelationDefinition.java 14 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/RelationDefinitionVisitor.java 27 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/SingletonRelationDefinition.java 68 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/ManagementContext.java 7 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/ldap/JNDIDirContextAdaptor.java 1 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/ldap/LDAPConnection.java 4 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/ldap/LDAPDriver.java 19 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/spi/AbstractManagedObject.java 159 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/spi/Driver.java 17 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandlerFactory.java 15 ●●●●● patch | view | raw | blame | history
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>
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>
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">
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();
    }
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) {
opends/src/server/org/opends/server/admin/DefaultManagedObject.java
New file
@@ -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);
    }
  }
}
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();
    }
  }
}
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();
    }
  }
}
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.
  }
}
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);
}
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();
    }
  }
}
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();
  }
opends/src/server/org/opends/server/admin/client/ldap/JNDIDirContextAdaptor.java
@@ -243,6 +243,7 @@
  }
  /**
   * {@inheritDoc}
   */
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();
}
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}
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;
    }
  }
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.
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));