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

matthew_swift
19.55.2007 5ab6bc9651264d936b94e321c4903ef5b104b4f7
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).

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