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

matthew_swift
19.54.2007 00786b8f6e90c1a848c9c09d8b82e73a56042a0a
Fix issues 1943 (unable to create je-index), 1996 (exception when creating components with empty names), and 1998 (exception when creating components with blank names).

This change allows one-to-many relations to use a property of the referenced component for naming the component. For example, a je-index has an attribute called "index-attribute" which is the attribute type indexed by the index. There is no need for the je-indexes to have a naming attribute since the value of the "index-attribute" property is sufficient. With this change it is possible to specify a "naming property" for one-to-many relations. In the case of je-indexes, the je-backend je-index relation is now defined as follows:

<adm:relation name="je-index">
<adm:one-to-many naming-property="index-attribute"/>
<adm:profile name="ldap">
<ldap:rdn-sequence>
cn=Index
</ldap:rdn-sequence>
</adm:profile>
<adm:profile name="cli">
<cli:relation>
<cli:default-property name="index-type" />
</cli:relation>
</adm:profile>
</adm:relation>

Note that the one-to-many element now has a "naming-property" attribute which identifies the je-index property which should be used for naming. Also note that the LDAP profile no longer needs a naming-attribute element, since the naming attribute will be the one associated with the index-attribute property.
1 files added
27 files modified
802 ■■■■ changed files
opends/resource/admin/admin-ldap.xsd 4 ●●● patch | view | raw | blame | history
opends/resource/admin/admin.xsd 15 ●●●●● patch | view | raw | blame | history
opends/resource/admin/clientMO.xsl 11 ●●●● patch | view | raw | blame | history
opends/resource/admin/ldapMOProfile.xsl 16 ●●●●● patch | view | raw | blame | history
opends/resource/admin/metaMO.xsl 28 ●●●●● patch | view | raw | blame | history
opends/resource/admin/preprocessor.xsl 54 ●●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/BackendConfiguration.xml 14 ●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/JEBackendConfiguration.xml 5 ●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml 3 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java 57 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/LDAPProfile.java 22 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/ManagedObjectPath.java 33 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/IllegalManagedObjectNameException.java 142 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/ManagedObject.java 4 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java 86 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/ToolMessages.java 107 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java 67 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java 36 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java 72 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java 2 ●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java 3 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgClient.java 5 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.java 5 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java 3 ●●●● patch | view | raw | blame | history
opends/resource/admin/admin-ldap.xsd
@@ -97,7 +97,9 @@
      <xsd:documentation>
        Defines which LDAP attribute should be used to name child
        managed objects referenced by a relation. When not specified,
        "cn" is used by default.
        "cn" is used by default. When the relation uses a naming
        property this element is not required, instead the LDAP
        attribute associated with the naming property will be used.
      </xsd:documentation>
    </xsd:annotation>
  </xsd:element>
opends/resource/admin/admin.xsd
@@ -593,6 +593,21 @@
                </xsd:documentation>
              </xsd:annotation>
            </xsd:attribute>
            <xsd:attribute name="naming-property" type="tns:name-type"
              use="optional">
              <xsd:annotation>
                <xsd:documentation>
                  Specifies the name of a property in the referenced
                  managed object which should be used for naming
                  instances. For example, an attribute index managed
                  object could be named according to the attribute that
                  it indexes. If present, the naming property must
                  reference a single-valued, mandatory, read-only
                  property. If it is not present, the administration
                  framework will use the default naming mechanism.
                </xsd:documentation>
              </xsd:annotation>
            </xsd:attribute>
          </xsd:complexType>
        </xsd:element>
      </xsd:choice>
opends/resource/admin/clientMO.xsl
@@ -306,11 +306,13 @@
                       '{@link DefaultBehaviorException}s that occurred whilst ',
                       'attempting to determine the default values of the ', $ufn,
                       '. This argument can be &lt;code&gt;null&lt;code&gt;.&#xa;',
                       '@return Returns a new ', $ufn,' configuration instance.&#xa;')" />
                       '@return Returns a new ', $ufn,' configuration instance.&#xa;',
                       '@throws IllegalManagedObjectNameException&#xa;',
                       '         If the name of the new ', $ufn,' is invalid.&#xa;')" />
        </xsl:call-template>
        <xsl:value-of
          select="concat('  &lt;C extends ', $java-class-name,'CfgClient&gt; C create', $java-relation-name, '(&#xa;',
                           '      ManagedObjectDefinition&lt;C, ?&gt; d, String name, Collection&lt;DefaultBehaviorException&gt; exceptions);&#xa;')" />
                           '      ManagedObjectDefinition&lt;C, ?&gt; d, String name, Collection&lt;DefaultBehaviorException&gt; exceptions) throws IllegalManagedObjectNameException;&#xa;')" />
        <xsl:text>&#xa;</xsl:text>
        <xsl:text>&#xa;</xsl:text>
        <xsl:text>&#xa;</xsl:text>
@@ -404,6 +406,11 @@
            org.opends.server.admin.client.OperationRejectedException
          </import>
        </xsl:if>
        <xsl:if test="$this-local-relations/adm:one-to-many">
          <import>
            org.opends.server.admin.client.IllegalManagedObjectNameException
          </import>
        </xsl:if>
        <xsl:choose>
          <xsl:when test="$this/@extends">
            <xsl:if test="$parent-package != $this-package">
opends/resource/admin/ldapMOProfile.xsl
@@ -80,6 +80,22 @@
      <xsl:choose>
        <xsl:when
          test="adm:profile[@name='ldap']/ldap:naming-attribute">
          <xsl:if test="not(adm:one-to-many)">
            <xsl:message terminate="yes">
              <xsl:value-of
                select="concat('Naming attribute specified for relation ',
                               @name, ' in managed object definition ',
                               $this-name, ' which is not a one-to-many relation.')" />
            </xsl:message>
          </xsl:if>
          <xsl:if test="adm:one-to-many/@naming-property">
            <xsl:message terminate="yes">
              <xsl:value-of
                select="concat('Naming attribute specified for one-to-many relation ',
                               @name, ' in managed object definition ',
                               $this-name, ' which uses a naming property.')" />
            </xsl:message>
          </xsl:if>
          <xsl:value-of
            select="concat('naming-attribute.',
                       normalize-space(@name),
opends/resource/admin/metaMO.xsl
@@ -822,7 +822,28 @@
        select="concat('&quot;', adm:one-to-many/@plural-name, '&quot;, ')" />
    </xsl:if>
    <xsl:value-of
      select="concat($java-managed-object-name, 'CfgDefn.getInstance());&#xa;')" />
      select="concat($java-managed-object-name, 'CfgDefn.getInstance()')" />
    <xsl:if test="adm:one-to-many">
      <xsl:value-of select="', '" />
      <xsl:choose>
        <xsl:when test="adm:one-to-many/@naming-property">
          <xsl:variable name="java-property-name">
            <xsl:call-template name="name-to-java">
              <xsl:with-param name="value"
                select="adm:one-to-many/@naming-property" />
            </xsl:call-template>
          </xsl:variable>
          <xsl:value-of
            select="concat($java-managed-object-name,
                           'CfgDefn.getInstance().get',
                           $java-property-name, 'PropertyDefinition()')" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="'null'" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:if>
    <xsl:value-of select="');&#xa;'" />
    <xsl:value-of
      select="concat('    INSTANCE.registerRelationDefinition(RD_', $java-relation-name,');&#xa;')" />
    <xsl:value-of select="'  }&#xa;'" />
@@ -1237,7 +1258,7 @@
                         '     * {@inheritDoc}&#xa;',
                         '     */&#xa;',
                         '    public &lt;M extends ', $java-class-name, 'CfgClient&gt; M create', $java-relation-name, '(&#xa;',
                         '        ManagedObjectDefinition&lt;M, ?&gt; d, String name, Collection&lt;DefaultBehaviorException&gt; exceptions) {&#xa;',
                         '        ManagedObjectDefinition&lt;M, ?&gt; d, String name, Collection&lt;DefaultBehaviorException&gt; exceptions) throws IllegalManagedObjectNameException {&#xa;',
                         '      return impl.createChild(INSTANCE.get', $java-relation-plural-name,'RelationDefinition(), d, name, exceptions).getConfiguration();&#xa;',
                         '    }&#xa;')" />
        <xsl:text>&#xa;</xsl:text>
@@ -1793,6 +1814,9 @@
            <xsl:if test="$this-all-relations/adm:one-to-many">
              <import>java.util.Collection</import>
              <import>
                org.opends.server.admin.client.IllegalManagedObjectNameException
              </import>
              <import>
                org.opends.server.admin.DefaultBehaviorException
              </import>
              <import>
opends/resource/admin/preprocessor.xsl
@@ -827,6 +827,60 @@
  -->
  <xsl:template match="adm:one-to-many" mode="merge-relation">
    <xsl:param name="managed-object" select="/.." />
    <!--
      Make sure that if this relation uses a naming property that the
      naming property exists, is single-valued, mandatory, and read-only.
    -->
    <xsl:if test="@naming-property">
      <xsl:variable name="naming-property-name"
        select="@naming-property" />
      <!--
        FIXME: this does not cope with the situation where the property
        is inherited, referenced, or overridden.
      -->
      <xsl:variable name="naming-property"
        select="$managed-object/adm:property[@name=$naming-property-name]" />
      <xsl:if test="not($naming-property)">
        <xsl:message terminate="yes">
          <xsl:value-of
            select="concat('Relation ', ../@name,
                           ' references an unknown naming property ',
                           $naming-property-name, ' in ',
                           $managed-object/@name, '.')" />
        </xsl:message>
      </xsl:if>
      <xsl:if test="not($naming-property/@read-only='true')">
        <xsl:message terminate="yes">
          <xsl:value-of
            select="concat('Relation ', ../@name,
                           ' references the naming property ',
                           $naming-property-name, ' in ',
                           $managed-object/@name, ' which is not read-only. ',
                           'Naming properties must be read-only.')" />
        </xsl:message>
      </xsl:if>
      <xsl:if test="not($naming-property/@mandatory='true')">
        <xsl:message terminate="yes">
          <xsl:value-of
            select="concat('Relation ', ../@name,
                           ' references the naming property ',
                           $naming-property-name, ' in ',
                           $managed-object/@name, ' which is not mandatory. ',
                           'Naming properties must be mandatory.')" />
        </xsl:message>
      </xsl:if>
      <xsl:if test="$naming-property/@multi-valued='true'">
        <xsl:message terminate="yes">
          <xsl:value-of
            select="concat('Relation ', ../@name,
                           ' references the naming property ',
                           $naming-property-name, ' in ',
                           $managed-object/@name, ' which is multi-valued. ',
                           'Naming properties must be single-valued.')" />
        </xsl:message>
      </xsl:if>
    </xsl:if>
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <!--
opends/src/admin/defn/org/opends/server/admin/std/BackendConfiguration.xml
@@ -94,23 +94,15 @@
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property name="backend-id"
    mandatory="true"
  <adm:property name="backend-id" mandatory="true" read-only="true"
    multi-valued="false">
    <adm:synopsis>
      Provides a name that will be used to identify the associated backend.
      Provides a name that will be used to identify the associated
      backend.
    </adm:synopsis>
    <adm:description>
      The name must be unique among all backends in the server.
    </adm:description>
    <adm:requires-admin-action>
      <adm:other>
        <adm:synopsis>
          The backend ID may not be altered after the backend is created in
          the server.
        </adm:synopsis>
      </adm:other>
    </adm:requires-admin-action>
    <adm:syntax>
      <adm:string />
    </adm:syntax>
opends/src/admin/defn/org/opends/server/admin/std/JEBackendConfiguration.xml
@@ -54,14 +54,11 @@
    </ldap:object-class>
  </adm:profile>
  <adm:relation name="je-index">
    <adm:one-to-many />
    <adm:one-to-many naming-property="index-attribute"/>
     <adm:profile name="ldap">
      <ldap:rdn-sequence>
        cn=Index
      </ldap:rdn-sequence>
      <ldap:naming-attribute>
        ds-cfg-index-attribute
      </ldap:naming-attribute>
    </adm:profile>
    <adm:profile name="cli">
      <cli:relation>
opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml
@@ -230,10 +230,9 @@
    </adm:profile>
  </adm:relation>
  <adm:relation name="backend">
    <adm:one-to-many />
    <adm:one-to-many naming-property="backend-id"/>
    <adm:profile name="ldap">
      <ldap:rdn-sequence>cn=Backends,cn=config</ldap:rdn-sequence>
      <ldap:naming-attribute>ds-cfg-backend-id</ldap:naming-attribute>
    </adm:profile>
    <adm:profile name="cli">
      <cli:relation>
opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java
@@ -27,6 +27,8 @@
package org.opends.server.admin;
import java.util.Locale;
@@ -46,6 +48,9 @@
    <C extends ConfigurationClient, S extends Configuration>
    extends RelationDefinition<C, S> {
  // The optional naming property definition.
  private final PropertyDefinition<?> namingPropertyDefinition;
  // The plural name of the relation.
  private final String pluralName;
@@ -62,12 +67,43 @@
   *          The plural name of the relation.
   * @param cd
   *          The child managed object definition.
   * @param namingPropertyDefinition
   *          The property of the child managed object definition
   *          which should be used for naming, or <code>null</code>
   *          if this relation does not use a property for naming.
   */
  public InstantiableRelationDefinition(
      AbstractManagedObjectDefinition<?, ?> pd, String name, String pluralName,
      AbstractManagedObjectDefinition<C, S> cd) {
      AbstractManagedObjectDefinition<C, S> cd,
      PropertyDefinition<?> namingPropertyDefinition) {
    super(pd, name, cd);
    this.pluralName = pluralName;
    this.namingPropertyDefinition = namingPropertyDefinition;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p) {
    return v.visitInstantiable(this, p);
  }
  /**
   * Get the property of the child managed object definition which
   * should be used for naming children.
   *
   * @return Returns the property of the child managed object
   *         definition which should be used for naming, or
   *         <code>null</code> if this relation does not use a
   *         property for naming.
   */
  public final PropertyDefinition<?> getNamingPropertyDefinition() {
    return namingPropertyDefinition;
  }
@@ -106,10 +142,9 @@
   *         definition in the specified locale.
   */
  public final String getUserFriendlyPluralName(Locale locale) {
    String property = "relation." + getName()
        + ".user-friendly-plural-name";
    return ManagedObjectDefinitionI18NResource.getInstance()
        .getMessage(getParentDefinition(), property, locale);
    String property = "relation." + getName() + ".user-friendly-plural-name";
    return ManagedObjectDefinitionI18NResource.getInstance().getMessage(
        getParentDefinition(), property, locale);
  }
@@ -125,16 +160,8 @@
    builder.append(getParentDefinition().getName());
    builder.append(" child=");
    builder.append(getChildDefinition().getName());
    builder.append(" child=");
    builder.append(getChildDefinition().getName());
    builder.append(" minOccurs=0");
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p) {
    return v.visitInstantiable(this, p);
  }
}
opends/src/server/org/opends/server/admin/LDAPProfile.java
@@ -83,7 +83,7 @@
     *         if the property definition is not handled by this LDAP
     *         profile wrapper.
     */
    public String getAttributeName(ManagedObjectDefinition<?, ?> d,
    public String getAttributeName(AbstractManagedObjectDefinition<?, ?> d,
        PropertyDefinition<?> pd) {
      return null;
    }
@@ -192,7 +192,7 @@
   *           If the LDAP profile properties file associated with the
   *           provided managed object definition could not be loaded.
   */
  public String getAttributeName(ManagedObjectDefinition<?, ?> d,
  public String getAttributeName(AbstractManagedObjectDefinition<?, ?> d,
      PropertyDefinition<?> pd) throws MissingResourceException {
    for (Wrapper profile : profiles) {
      String attributeName = profile.getAttributeName(d, pd);
@@ -219,14 +219,20 @@
   */
  public String getInstantiableRelationChildRDNType(
      InstantiableRelationDefinition<?, ?> r) throws MissingResourceException {
    for (Wrapper profile : profiles) {
      String rdnType = profile.getInstantiableRelationChildRDNType(r);
      if (rdnType != null) {
        return rdnType;
    if (r.getNamingPropertyDefinition() != null) {
      // Use the attribute associated with the naming property.
      return getAttributeName(r.getChildDefinition(), r
          .getNamingPropertyDefinition());
    } else {
      for (Wrapper profile : profiles) {
        String rdnType = profile.getInstantiableRelationChildRDNType(r);
        if (rdnType != null) {
          return rdnType;
        }
      }
      return resource.getString(r.getParentDefinition(), "naming-attribute."
          + r.getName());
    }
    return resource.getString(r.getParentDefinition(), "naming-attribute."
        + r.getName());
  }
opends/src/server/org/opends/server/admin/ManagedObjectPath.java
@@ -926,6 +926,39 @@
  /**
   * Creates a new managed object path which has the same structure as
   * this path except that the final path element is renamed. The
   * final path element must comprise of an instantiable relation.
   *
   * @param newName
   *          The new name of the final path element.
   * @return Returns a new managed object path which has the same
   *         structure as this path except that the final path element
   *         is renamed.
   * @throws IllegalStateException
   *           If this managed object path is empty or if its final
   *           path element does not comprise of an instantiable
   *           relation.
   */
  @SuppressWarnings("unchecked")
  public ManagedObjectPath<C, S> rename(String newName)
      throws IllegalStateException {
    if (elements.size() == 0) {
      throw new IllegalStateException("Cannot rename an empty path");
    }
    if (r instanceof InstantiableRelationDefinition) {
      InstantiableRelationDefinition<? super C, ? super S> ir =
        (InstantiableRelationDefinition<? super C, ? super S>) r;
      return parent().child(ir, d, newName);
    } else {
      throw new IllegalStateException("Not an instantiable relation");
    }
  }
  /**
   * Serialize this managed object path using the provided
   * serialization strategy.
   * <p>
opends/src/server/org/opends/server/admin/client/IllegalManagedObjectNameException.java
New file
@@ -0,0 +1,142 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.admin.client;
import org.opends.server.admin.IllegalPropertyValueStringException;
import org.opends.server.admin.OperationsException;
import org.opends.server.admin.PropertyDefinition;
import org.opends.server.admin.PropertyDefinitionUsageBuilder;
/**
 * Thrown when an attempt is made to create a new managed object with
 * an illegal name.
 * <p>
 * This exception can occur when a new managed object is given a name
 * which is either an empty string, a string containing just
 * white-spaces, or a string which is invalid according to the managed
 * object's naming property (if it has one).
 */
public class IllegalManagedObjectNameException extends OperationsException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = 7491748228684293291L;
  // The illegal name.
  private final String illegalName;
  // The naming property definition if applicable.
  private final PropertyDefinition<?> namingPropertyDefinition;
  /**
   * Create a new illegal name exception and no naming property
   * definition.
   *
   * @param illegalName
   *          The illegal managed object name.
   */
  public IllegalManagedObjectNameException(String illegalName) {
    this(illegalName, null);
  }
  /**
   * Create a new illegal name exception and a naming property
   * definition.
   *
   * @param illegalName
   *          The illegal managed object name.
   * @param namingPropertyDefinition
   *          The naming property definition.
   */
  public IllegalManagedObjectNameException(String illegalName,
      PropertyDefinition<?> namingPropertyDefinition) {
    this.illegalName = illegalName;
    this.namingPropertyDefinition = namingPropertyDefinition;
  }
  /**
   * Get the illegal managed object name.
   *
   * @return Returns the illegal managed object name.
   */
  public String getIllegalName() {
    return illegalName;
  }
  /**
   * Get the naming property definition if applicable.
   *
   * @return Returns naming property definition, or <code>null</code>
   *         if none was specified.
   */
  public PropertyDefinition<?> getNamingPropertyDefinition() {
    return namingPropertyDefinition;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String getMessage() {
    if (illegalName.length() == 0) {
      return "Empty managed object names are not permitted";
    } else if (illegalName.trim().length() == 0) {
      return "Blank managed object names are not permitted";
    } else if (namingPropertyDefinition != null) {
      try {
        namingPropertyDefinition.decodeValue(illegalName);
      } catch (IllegalPropertyValueStringException e) {
        String msg = "The managed object name \"%s\" is not a valid value "
            + "for the naming property \"%s\", which must have the following "
            + "syntax: %s";
        PropertyDefinitionUsageBuilder builder =
          new PropertyDefinitionUsageBuilder(true);
        return String.format(msg, illegalName, namingPropertyDefinition
            .getName(), builder.getUsage(namingPropertyDefinition));
      }
    }
    return "The managed object name \"" + illegalName + "\" is not permitted";
  }
}
opends/src/server/org/opends/server/admin/client/ManagedObject.java
@@ -157,6 +157,8 @@
   *          values.
   * @return Returns a new child managed object bound to the specified
   *         instantiable relation.
   * @throws IllegalManagedObjectNameException
   *           If the name of the child managed object is invalid.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
@@ -164,7 +166,7 @@
  <M extends ConfigurationClient, N extends M> ManagedObject<N> createChild(
      InstantiableRelationDefinition<M, ?> r, ManagedObjectDefinition<N, ?> d,
      String name, Collection<DefaultBehaviorException> exceptions)
      throws IllegalArgumentException;
      throws IllegalManagedObjectNameException, IllegalArgumentException;
opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
@@ -83,6 +83,7 @@
import org.opends.server.admin.client.AuthorizationException;
import org.opends.server.admin.client.CommunicationException;
import org.opends.server.admin.client.ConcurrentModificationException;
import org.opends.server.admin.client.IllegalManagedObjectNameException;
import org.opends.server.admin.client.ManagedObject;
import org.opends.server.admin.client.ManagedObjectDecodingException;
import org.opends.server.admin.client.MissingMandatoryPropertiesException;
@@ -394,7 +395,8 @@
  static ManagedObject<RootCfgClient> getRootManagedObject(
      LDAPManagementContext context) {
    return new LDAPManagedObject<RootCfgClient>(context, RootCfgDefn
        .getInstance(), ManagedObjectPath.emptyPath(), new PropertySet(), true);
        .getInstance(), ManagedObjectPath.emptyPath(), new PropertySet(), true,
        null);
  }
@@ -454,8 +456,11 @@
  // committed).
  private boolean existsOnServer;
  // Optional naming property definition.
  private final PropertyDefinition<?> namingPropertyDefinition;
  // The path associated with this managed object.
  private final ManagedObjectPath<?, ?> path;
  private ManagedObjectPath<?, ?> path;
  // The managed object's properties.
  private final PropertySet properties;
@@ -465,12 +470,14 @@
  // Create an new LDAP managed object with the provided JNDI context.
  private LDAPManagedObject(LDAPManagementContext context,
      ManagedObjectDefinition<C, ?> d, ManagedObjectPath path,
      PropertySet properties, boolean existsOnServer) {
      PropertySet properties, boolean existsOnServer,
      PropertyDefinition<?> namingPropertyDefinition) {
    this.definition = d;
    this.context = context;
    this.path = path;
    this.properties = properties;
    this.existsOnServer = existsOnServer;
    this.namingPropertyDefinition = namingPropertyDefinition;
  }
@@ -515,10 +522,27 @@
      ManagedObject<N> createChild(
      InstantiableRelationDefinition<M, ?> r, ManagedObjectDefinition<N, ?> d,
      String name, Collection<DefaultBehaviorException> exceptions)
      throws IllegalArgumentException {
      throws IllegalManagedObjectNameException, IllegalArgumentException {
    validateRelationDefinition(r);
    // Empty names are not allowed.
    if (name.trim().length() == 0) {
      throw new IllegalManagedObjectNameException(name);
    }
    // If the relation uses a naming property definition then it must
    // be a valid value.
    PropertyDefinition<?> pd = r.getNamingPropertyDefinition();
    if (pd != null) {
      try {
        pd.decodeValue(name);
      } catch (IllegalPropertyValueStringException e) {
        throw new IllegalManagedObjectNameException(name, pd);
      }
    }
    ManagedObjectPath childPath = path.child(r, name);
    return createNewManagedObject(d, childPath, exceptions);
    return createNewManagedObject(d, childPath, pd, name, exceptions);
  }
@@ -534,7 +558,7 @@
      throws IllegalArgumentException {
    validateRelationDefinition(r);
    ManagedObjectPath childPath = path.child(r);
    return createNewManagedObject(d, childPath, exceptions);
    return createNewManagedObject(d, childPath, null, null, exceptions);
  }
@@ -713,15 +737,11 @@
  public <T> void setPropertyValue(PropertyDefinition<T> d, T value)
      throws IllegalPropertyValueException, PropertyIsReadOnlyException,
      PropertyIsMandatoryException, IllegalArgumentException {
    if (d.hasOption(PropertyOption.MONITORING)) {
      throw new PropertyIsReadOnlyException(d);
    if (value == null) {
      setPropertyValues(d, Collections.<T> emptySet());
    } else {
      setPropertyValues(d, Collections.singleton(value));
    }
    if (existsOnServer && d.hasOption(PropertyOption.READ_ONLY)) {
      throw new PropertyIsReadOnlyException(d);
    }
    properties.setPropertyValue(d, value);
  }
@@ -742,10 +762,15 @@
    }
    properties.setPropertyValues(d, values);
    // If this is a naming property then update the name.
    if (d.equals(namingPropertyDefinition)) {
      // The property must be single-valued and mandatory.
      String newName = d.encodeValue(values.iterator().next());
      path = path.rename(newName);
    }
  }
  // Adapts a naming exception to an appropriate admin client
  // exception.
  private void adaptNamingException(NamingException ne)
@@ -871,9 +896,11 @@
    }
    attributes.put(oc);
    // Create the naming attribute.
    Rdn rdn = dn.getRdn(dn.size() - 1);
    attributes.put(rdn.getType(), rdn.getValue().toString());
    // Create the naming attribute if there is not naming property.
    if (namingPropertyDefinition == null) {
      Rdn rdn = dn.getRdn(dn.size() - 1);
      attributes.put(rdn.getType(), rdn.getValue().toString());
    }
    // Create the remaining attributes.
    for (PropertyDefinition<?> pd : definition.getAllPropertyDefinitions()) {
@@ -910,16 +937,24 @@
      ManagedObject<M> createExistingManagedObject(
      ManagedObjectDefinition<M, ?> d, ManagedObjectPath p,
      PropertySet properties) {
    return new LDAPManagedObject<M>(context, d, p, properties, true);
    RelationDefinition<?, ?> rd = p.getRelationDefinition();
    PropertyDefinition<?> pd = null;
    if (rd instanceof InstantiableRelationDefinition) {
      InstantiableRelationDefinition<?, ?> ird =
        (InstantiableRelationDefinition) rd;
      pd = ird.getNamingPropertyDefinition();
    }
    return new LDAPManagedObject<M>(context, d, p, properties, true, pd);
  }
  // Creates a new managed object with no active values, just default
  // values.
  private <M extends ConfigurationClient>
  private <M extends ConfigurationClient, T>
      ManagedObject<M> createNewManagedObject(
      ManagedObjectDefinition<M, ?> d, ManagedObjectPath p,
      PropertyDefinition<T> namingPropertyDefinition, String name,
      Collection<DefaultBehaviorException> exceptions) {
    PropertySet childProperties = new PropertySet();
    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
@@ -933,7 +968,14 @@
      }
    }
    return new LDAPManagedObject<M>(context, d, p, childProperties, false);
    // Set the naming property if there is one.
    if (namingPropertyDefinition != null) {
      T value = namingPropertyDefinition.decodeValue(name);
      childProperties.setPropertyValue(namingPropertyDefinition, value);
    }
    return new LDAPManagedObject<M>(context, d, p, childProperties, false,
        namingPropertyDefinition);
  }
opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -9063,6 +9063,89 @@
  /**
   * The message ID for the message that will be used if the user
   * attempts create a new managed object having a name which is
   * invalid according to the managed object's naming property. This
   * takes three arguments which are the illegal name, the user
   * friendly name of the associated managed object, and the syntax.
   */
  public static final int MSGID_DSCFG_ERROR_ILLEGAL_NAME_SYNTAX =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1204;
  /**
   * The message ID for the message that will be used if the user
   * attempts create a new managed object having an empty name. This
   * takes a single argument which is the user friendly plural name of
   * the associated managed object.
   */
  public static final int MSGID_DSCFG_ERROR_ILLEGAL_NAME_EMPTY =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1205;
  /**
   * The message ID for the message that will be used if the user
   * attempts create a new managed object having a blank name. This
   * takes a single argument which is the user friendly plural name of
   * the associated managed object.
   */
  public static final int MSGID_DSCFG_ERROR_ILLEGAL_NAME_BLANK =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1206;
  /**
   * The message ID for the message that will be used if the user
   * attempts create a new managed object having a name which is
   * invalid for an unspecified reason. This takes two arguments which
   * are the illegal name and the user friendly name of the associated
   * managed object.
   */
  public static final int MSGID_DSCFG_ERROR_ILLEGAL_NAME_UNKNOWN =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1207;
  /**
   * The message ID for the message that will be used as the
   * description of the a naming argument in create-xxx sub-commands
   * which do not have a naming property. This takes a single argument
   * which is the user friendly name for the type of managed objects
   * being named.
   */
  public static final int MSGID_DSCFG_DESCRIPTION_NAME_CREATE =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1208;
  /**
   * The message ID for the message that will be used as the
   * description of the a naming argument in create-xxx sub-commands
   * which do have a naming property. This takes three arguments which
   * are the user friendly name for the type of managed objects being
   * named, the name of the naming property, and the naming property's
   * synopsis.
   */
  public static final int MSGID_DSCFG_DESCRIPTION_NAME_CREATE_EXT =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1209;
  /**
   * The message ID for the message that will be used if the user
   * attempts set a value for the naming property when creating a new
   * managed object. This takes two arguments, which are the the name
   * of the naming property, and the user friendly name of the type of
   * managed object being created.
   */
  public static final int MSGID_DSCFG_ERROR_UNABLE_TO_SET_NAMING_PROPERTY =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1210;
  /**
   * Associates a set of generic messages with the message IDs defined in this
   * class.
   */
@@ -11374,6 +11457,13 @@
    registerMessage(MSGID_DSCFG_DESCRIPTION_NAME,
                    "The name of the %s");
    registerMessage(MSGID_DSCFG_DESCRIPTION_NAME_CREATE,
                    "The name of the new %s");
    registerMessage(MSGID_DSCFG_DESCRIPTION_NAME_CREATE_EXT,
                    "The name of the new %s which will also be used as the " +
                    "value of the \"%s\" property: %s");
    registerMessage(MSGID_DSCFG_DESCRIPTION_HELP_TYPE,
                    "The type(s) of components whose properties should be " +
                    "described");
@@ -11457,6 +11547,10 @@
                    "The %s property \"%s\" is mandatory cannot be reset. " +
                    "Use the \"%s\" option to specify a new value");
    registerMessage(MSGID_DSCFG_ERROR_UNABLE_TO_SET_NAMING_PROPERTY,
                    "The property \"%s\" cannot be set as it is defined " +
                    "implicitly by the name of the %s");
    registerMessage(MSGID_DSCFG_ERROR_PROPERTY_SINGLE_VALUED,
                    "It is not possible to specify multiple values for the " +
                    "%s property \"%s\" as it is single-valued");
@@ -11473,6 +11567,19 @@
                    "The inherited default value(s) of the %s property " +
                    "\"%s\" could not be determined");
    registerMessage(MSGID_DSCFG_ERROR_ILLEGAL_NAME_EMPTY,
                    "Empty names are not permitted for %s");
    registerMessage(MSGID_DSCFG_ERROR_ILLEGAL_NAME_BLANK,
                    "Blank names are not permitted for %s");
    registerMessage(MSGID_DSCFG_ERROR_ILLEGAL_NAME_SYNTAX,
                    "The name \"%s\" is not a valid name for the %s " +
                    "which has the following syntax: %s");
    registerMessage(MSGID_DSCFG_ERROR_ILLEGAL_NAME_UNKNOWN,
                    "The name \"%s\" is not a valid name for the %s");
    registerMessage(MSGID_DSCFG_HEADING_MANAGED_OBJECT_NAME,
                    "Component");
opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
@@ -36,12 +36,14 @@
import org.opends.server.admin.IllegalPropertyValueException;
import org.opends.server.admin.IllegalPropertyValueStringException;
import org.opends.server.admin.ManagedObjectDefinition;
import org.opends.server.admin.PropertyDefinition;
import org.opends.server.admin.PropertyDefinitionUsageBuilder;
import org.opends.server.admin.PropertyException;
import org.opends.server.admin.PropertyIsMandatoryException;
import org.opends.server.admin.PropertyIsReadOnlyException;
import org.opends.server.admin.PropertyIsSingleValuedException;
import org.opends.server.admin.RelationDefinition;
import org.opends.server.admin.client.IllegalManagedObjectNameException;
import org.opends.server.admin.client.MissingMandatoryPropertiesException;
import org.opends.server.util.args.ArgumentException;
@@ -54,6 +56,51 @@
final class ArgumentExceptionFactory {
  /**
   * Creates an argument exception from an illegal managed object name
   * exception.
   *
   * @param e
   *          The illegal managed object name exception.
   * @param d
   *          The managed object definition.
   * @return Returns an argument exception.
   */
  public static ArgumentException adaptIllegalManagedObjectNameException(
      IllegalManagedObjectNameException e, AbstractManagedObjectDefinition d) {
    String illegalName = e.getIllegalName();
    PropertyDefinition<?> pd = e.getNamingPropertyDefinition();
    if (illegalName.length() == 0) {
      int msgID = MSGID_DSCFG_ERROR_ILLEGAL_NAME_EMPTY;
      String message = getMessage(msgID, d.getUserFriendlyPluralName());
      return new ArgumentException(msgID, message);
    } else if (illegalName.trim().length() == 0) {
      int msgID = MSGID_DSCFG_ERROR_ILLEGAL_NAME_BLANK;
      String message = getMessage(msgID, d.getUserFriendlyPluralName());
      return new ArgumentException(msgID, message);
    } else if (pd != null) {
      try {
        pd.decodeValue(illegalName);
      } catch (IllegalPropertyValueStringException e1) {
        PropertyDefinitionUsageBuilder b = new PropertyDefinitionUsageBuilder(
            true);
        String syntax = b.getUsage(pd);
        int msgID = MSGID_DSCFG_ERROR_ILLEGAL_NAME_SYNTAX;
        String message = getMessage(msgID, illegalName,
            d.getUserFriendlyName(), pd.getName(), syntax);
        return new ArgumentException(msgID, message);
      }
    }
    int msgID = MSGID_DSCFG_ERROR_ILLEGAL_NAME_UNKNOWN;
    String message = getMessage(msgID, illegalName, d.getUserFriendlyName());
    return new ArgumentException(msgID, message);
  }
  /**
   * Creates an argument exception from a missing mandatory properties
   * exception.
   *
@@ -262,6 +309,26 @@
  /**
   * Creates an argument exception which should be used when an
   * attempt is made to set the naming property for a managed object
   * during creation.
   *
   * @param d
   *          The managed object definition.
   * @param pd
   *          The naming property definition.
   * @return Returns an argument exception.
   */
  public static ArgumentException unableToSetNamingProperty(
      AbstractManagedObjectDefinition d, PropertyDefinition<?> pd) {
    int msgID = MSGID_DSCFG_ERROR_UNABLE_TO_SET_NAMING_PROPERTY;
    String message = getMessage(msgID, pd.getName(), d.getUserFriendlyName());
    return new ArgumentException(msgID, message);
  }
  /**
   * Creates an argument exception which should be used when the bind
   * password could not be read from the standard input.
   *
opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
@@ -62,6 +62,7 @@
import org.opends.server.admin.client.AuthorizationException;
import org.opends.server.admin.client.CommunicationException;
import org.opends.server.admin.client.ConcurrentModificationException;
import org.opends.server.admin.client.IllegalManagedObjectNameException;
import org.opends.server.admin.client.ManagedObject;
import org.opends.server.admin.client.ManagedObjectDecodingException;
import org.opends.server.admin.client.ManagementContext;
@@ -105,13 +106,16 @@
     *
     * @param d
     *          The managed object definition.
     * @param namingPropertyDefinition
     *          The naming property definition if there is one.
     * @param args
     *          The property value arguments.
     * @throws ArgumentException
     *           If the property value arguments could not be parsed.
     */
    public MyPropertyProvider(ManagedObjectDefinition<?, ?> d,
        List<String> args) throws ArgumentException {
        PropertyDefinition<?> namingPropertyDefinition, List<String> args)
        throws ArgumentException {
      for (String s : args) {
        // Parse the property "property:value".
        int sep = s.indexOf(':');
@@ -138,6 +142,12 @@
          throw ArgumentExceptionFactory.unknownProperty(d, propertyName);
        }
        // Make sure that the user is not attempting to set the naming
        // property.
        if (pd.equals(namingPropertyDefinition)) {
          throw ArgumentExceptionFactory.unableToSetNamingProperty(d, pd);
        }
        // Add the value.
        addPropertyValue(d, pd, value);
      }
@@ -247,7 +257,8 @@
  public static <C extends ConfigurationClient> CreateSubCommandHandler create(
      SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
      InstantiableRelationDefinition<C, ?> r) throws ArgumentException {
    return new CreateSubCommandHandler<C>(parser, p, r, p.child(r, "DUMMY"));
    return new CreateSubCommandHandler<C>(parser, p, r, r
        .getNamingPropertyDefinition(), p.child(r, "DUMMY"));
  }
@@ -270,12 +281,15 @@
  public static <C extends ConfigurationClient> CreateSubCommandHandler create(
      SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
      OptionalRelationDefinition<C, ?> r) throws ArgumentException {
    return new CreateSubCommandHandler<C>(parser, p, r, p.child(r));
    return new CreateSubCommandHandler<C>(parser, p, r, null, p.child(r));
  }
  // The sub-commands naming arguments.
  private final List<StringArgument> namingArgs;
  // The optional naming property definition.
  private final PropertyDefinition<?> namingPropertyDefinition;
  // The path of the parent managed object.
  private final ManagedObjectPath<?, ?> path;
@@ -306,9 +320,11 @@
  // Common constructor.
  private CreateSubCommandHandler(SubCommandArgumentParser parser,
      ManagedObjectPath<?, ?> p, RelationDefinition<C, ?> r,
      ManagedObjectPath<?, ?> c) throws ArgumentException {
      PropertyDefinition<?> pd, ManagedObjectPath<?, ?> c)
      throws ArgumentException {
    this.path = p;
    this.relation = r;
    this.namingPropertyDefinition = pd;
    // Create the sub-command.
    String name = "create-" + r.getName();
@@ -321,7 +337,7 @@
    this.types = getSubTypes(r.getChildDefinition());
    // Create the naming arguments.
    this.namingArgs = createNamingArgs(subCommand, c);
    this.namingArgs = createNamingArgs(subCommand, c, true);
    // Create the --property argument which is used to specify
    // property values.
@@ -392,7 +408,8 @@
    // Encode the provided properties.
    List<String> propertyArgs = propertySetArgument.getValues();
    MyPropertyProvider provider = new MyPropertyProvider(d, propertyArgs);
    MyPropertyProvider provider = new MyPropertyProvider(d,
        namingPropertyDefinition, propertyArgs);
    // Add the child managed object.
    ManagementContext context = app.getManagementContext();
@@ -439,7 +456,12 @@
        InstantiableRelationDefinition<C, ?> irelation =
          (InstantiableRelationDefinition<C, ?>) relation;
        String name = names.get(names.size() - 1);
        child = parent.createChild(irelation, d, name, exceptions);
        try {
          child = parent.createChild(irelation, d, name, exceptions);
        } catch (IllegalManagedObjectNameException e) {
          throw ArgumentExceptionFactory
              .adaptIllegalManagedObjectNameException(e, d);
        }
      } else {
        OptionalRelationDefinition<C, ?> orelation =
          (OptionalRelationDefinition<C, ?>) relation;
opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java
@@ -151,7 +151,7 @@
        descriptionID, ufpn);
    // Create the naming arguments.
    this.namingArgs = createNamingArgs(subCommand, c);
    this.namingArgs = createNamingArgs(subCommand, c, false);
    // Create the --force argument which is used to force deletion.
    this.forceArgument = new BooleanArgument(OPTION_DSCFG_LONG_FORCE,
opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java
@@ -162,7 +162,7 @@
        descriptionID, r.getChildDefinition().getUserFriendlyName());
    // Create the naming arguments.
    this.namingArgs = createNamingArgs(subCommand, path);
    this.namingArgs = createNamingArgs(subCommand, path, false);
    // Register common arguments.
    registerPropertyNameArgument(this.subCommand);
opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java
@@ -142,7 +142,7 @@
        descriptionID, rufn);
    // Create the naming arguments.
    this.namingArgs = createNamingArgs(subCommand, path);
    this.namingArgs = createNamingArgs(subCommand, path, false);
    // Register arguments.
    registerPropertyNameArgument(this.subCommand);
opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java
@@ -242,7 +242,7 @@
        descriptionID, r.getChildDefinition().getUserFriendlyName());
    // Create the naming arguments.
    this.namingArgs = createNamingArgs(subCommand, path);
    this.namingArgs = createNamingArgs(subCommand, path, false);
    // Create the --set argument.
    this.propertySetArgument = new StringArgument(OPTION_DSCFG_LONG_SET,
opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java
@@ -52,6 +52,8 @@
import org.opends.server.admin.ManagedObjectPath;
import org.opends.server.admin.ManagedObjectPathSerializer;
import org.opends.server.admin.OptionalRelationDefinition;
import org.opends.server.admin.PropertyDefinition;
import org.opends.server.admin.PropertyDefinitionUsageBuilder;
import org.opends.server.admin.SingletonRelationDefinition;
import org.opends.server.admin.SizeUnit;
import org.opends.server.admin.Tag;
@@ -344,14 +346,20 @@
     *          The sub-command.
     * @param path
     *          The managed object path.
     * @param isCreate
     *          Indicates whether the sub-command is a create-xxx
     *          sub-command, in which case the final path element will
     *          have different usage information.
     * @return Returns the naming arguments.
     * @throws ArgumentException
     *           If one or more naming arguments could not be
     *           registered.
     */
    public static List<StringArgument> create(SubCommand subCommand,
        ManagedObjectPath<?, ?> path) throws ArgumentException {
      NamingArgumentBuilder builder = new NamingArgumentBuilder(subCommand);
        ManagedObjectPath<?, ?> path, boolean isCreate)
        throws ArgumentException {
      NamingArgumentBuilder builder = new NamingArgumentBuilder(subCommand,
          path.size(), isCreate);
      path.serialize(builder);
      if (builder.e != null) {
@@ -372,16 +380,22 @@
    // The sub-command.
    private final SubCommand subCommand;
    // Indicates whether the sub-command is a create-xxx
    // sub-command, in which case the final path element will
    // have different usage information.
    private final boolean isCreate;
    // The number of path elements to expect.
    private int sz;
    /**
     * Creates a new naming argument builder.
     *
     * @param subCommand
     *          Add the naming arguments to this sub-command.
     */
    public NamingArgumentBuilder(SubCommand subCommand) {
    // Private constructor.
    private NamingArgumentBuilder(SubCommand subCommand, int sz,
        boolean isCreate) {
      this.subCommand = subCommand;
      this.sz = sz;
      this.isCreate = isCreate;
    }
@@ -393,6 +407,8 @@
        void appendManagedObjectPathElement(
        InstantiableRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d, String name) {
      sz--;
      // Use the last word in the managed object name as the argument
      // prefix.
      StringBuilder builder = new StringBuilder();
@@ -406,12 +422,32 @@
      }
      builder.append("-name");
      String argName = builder.toString();
      StringArgument arg;
      try {
        StringArgument arg = new StringArgument(argName, null, argName, true,
            true, "{NAME}", MSGID_DSCFG_DESCRIPTION_NAME, d
                .getUserFriendlyName());
        if (isCreate && sz == 0) {
          // The final path element in create-xxx sub-commands should
          // have a different usage.
          PropertyDefinition<?> pd = r.getNamingPropertyDefinition();
          if (pd != null) {
            // Use syntax and description from naming property.
            PropertyDefinitionUsageBuilder b =
              new PropertyDefinitionUsageBuilder(false);
            String usage = "{" + b.getUsage(pd) + "}";
            arg = new StringArgument(argName, null, argName, true, true, usage,
                MSGID_DSCFG_DESCRIPTION_NAME_CREATE_EXT, d
                    .getUserFriendlyName(), pd.getName(), pd.getSynopsis());
          } else {
            arg = new StringArgument(argName, null, argName, true, true,
                "{NAME}", MSGID_DSCFG_DESCRIPTION_NAME_CREATE, d
                    .getUserFriendlyName());
          }
        } else {
          // A normal naming argument.
          arg = new StringArgument(argName, null, argName, true, true,
              "{NAME}", MSGID_DSCFG_DESCRIPTION_NAME, d.getUserFriendlyName());
        }
        subCommand.addArgument(arg);
        arguments.add(arg);
      } catch (ArgumentException e) {
@@ -428,7 +464,7 @@
        void appendManagedObjectPathElement(
        OptionalRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d) {
      // No implementation required.
      sz--;
    }
@@ -440,7 +476,7 @@
        void appendManagedObjectPathElement(
        SingletonRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d) {
      // No implementation required.
      sz--;
    }
  }
@@ -601,14 +637,18 @@
   *          The sub-command.
   * @param p
   *          The managed object path.
   * @param isCreate
   *          Indicates whether the sub-command is a create-xxx
   *          sub-command, in which case the final path element will
   *          have different usage information.
   * @return Returns the naming arguments.
   * @throws ArgumentException
   *           If one or more naming arguments could not be
   *           registered.
   */
  protected final List<StringArgument> createNamingArgs(SubCommand subCommand,
      ManagedObjectPath<?, ?> p) throws ArgumentException {
    return NamingArgumentBuilder.create(subCommand, p);
      ManagedObjectPath<?, ?> p, boolean isCreate) throws ArgumentException {
    return NamingArgumentBuilder.create(subCommand, p, isCreate);
  }
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java
@@ -46,7 +46,7 @@
   * {@inheritDoc}
   */
  @Override
  public String getAttributeName(ManagedObjectDefinition<?, ?> d,
  public String getAttributeName(AbstractManagedObjectDefinition<?, ?> d,
      PropertyDefinition<?> pd) {
    if (d == TestParentCfgDefn.getInstance()) {
      TestParentCfgDefn td = TestParentCfgDefn.getInstance();
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java
@@ -53,7 +53,7 @@
  static {
    RD_TEST_ONE_TO_MANY_PARENT = new InstantiableRelationDefinition<TestParentCfgClient, TestParentCfg>(
        RootCfgDefn.getInstance(), "test-one-to-many-parent",
        "test-one-to-many-parents", TestParentCfgDefn.getInstance());
        "test-one-to-many-parents", TestParentCfgDefn.getInstance(), null);
  }
  // Create a one-to-many relation for test-parent components.
@@ -61,7 +61,6 @@
    RD_TEST_ONE_TO_ZERO_OR_ONE_PARENT = new OptionalRelationDefinition<TestParentCfgClient, TestParentCfg>(
        RootCfgDefn.getInstance(), "test-one-to-zero-or-one-parent",
        TestParentCfgDefn.getInstance());
  }
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgClient.java
@@ -33,6 +33,7 @@
import org.opends.server.admin.client.AuthorizationException;
import org.opends.server.admin.client.CommunicationException;
import org.opends.server.admin.client.ConcurrentModificationException;
import org.opends.server.admin.client.IllegalManagedObjectNameException;
import org.opends.server.admin.client.ManagedObjectDecodingException;
import org.opends.server.admin.client.OperationRejectedException;
import org.opends.server.admin.ConfigurationClient;
@@ -239,9 +240,11 @@
   *          attempting to determine the default values of the
   *          Test Child. This argument can be <code>null<code>.
   * @return Returns a new Test Child configuration instance.
   * @throws IllegalManagedObjectNameException
   *          If the name is invalid.
   */
  <C extends TestChildCfgClient> C createTestChild(
      ManagedObjectDefinition<C, ?> d, String name, Collection<DefaultBehaviorException> exceptions);
      ManagedObjectDefinition<C, ?> d, String name, Collection<DefaultBehaviorException> exceptions) throws IllegalManagedObjectNameException;
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.java
@@ -37,6 +37,7 @@
import org.opends.server.admin.client.AuthorizationException;
import org.opends.server.admin.client.CommunicationException;
import org.opends.server.admin.client.ConcurrentModificationException;
import org.opends.server.admin.client.IllegalManagedObjectNameException;
import org.opends.server.admin.client.ManagedObject;
import org.opends.server.admin.client.ManagedObjectDecodingException;
import org.opends.server.admin.client.MissingMandatoryPropertiesException;
@@ -164,7 +165,7 @@
  // Build the "test-children" relation definition.
  static {
    RD_TEST_CHILDREN = new InstantiableRelationDefinition<TestChildCfgClient, TestChildCfg>(
        INSTANCE, "multiple-children", "test-children", TestChildCfgDefn.getInstance());
        INSTANCE, "multiple-children", "test-children", TestChildCfgDefn.getInstance(), null);
    INSTANCE.registerRelationDefinition(RD_TEST_CHILDREN);
  }
@@ -421,7 +422,7 @@
     * {@inheritDoc}
     */
    public <M extends TestChildCfgClient> M createTestChild(
        ManagedObjectDefinition<M, ?> d, String name, Collection<DefaultBehaviorException> exceptions) {
        ManagedObjectDefinition<M, ?> d, String name, Collection<DefaultBehaviorException> exceptions) throws IllegalManagedObjectNameException {
      return impl.createChild(INSTANCE.getTestChildrenRelationDefinition(), d, name, exceptions).getConfiguration();
    }
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java
@@ -53,6 +53,7 @@
import org.opends.server.admin.client.AuthorizationException;
import org.opends.server.admin.client.CommunicationException;
import org.opends.server.admin.client.ConcurrentModificationException;
import org.opends.server.admin.client.IllegalManagedObjectNameException;
import org.opends.server.admin.client.ManagedObject;
import org.opends.server.admin.client.ManagedObjectDecodingException;
import org.opends.server.admin.client.ManagementContext;
@@ -813,7 +814,7 @@
      String name) throws ManagedObjectDecodingException,
      AuthorizationException, ManagedObjectAlreadyExistsException,
      ConcurrentModificationException, OperationRejectedException,
      CommunicationException {
      CommunicationException, IllegalManagedObjectNameException {
    ManagedObject<RootCfgClient> root = context
        .getRootConfigurationManagedObject();
    return root.createChild(TestCfg.getTestOneToManyParentRelationDefinition(),