From fe6545499558bb95484defd311ed83eced6aedf4 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Thu, 19 Jul 2007 14:54:30 +0000
Subject: [PATCH] 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).

---
 opendj-sdk/opends/resource/admin/metaMO.xsl                                                                  |   28 +
 opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/JEBackendConfiguration.xml                      |    5 
 opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java                         |   72 ++++-
 opendj-sdk/opends/resource/admin/admin-ldap.xsd                                                              |    4 
 opendj-sdk/opends/resource/admin/ldapMOProfile.xsl                                                           |   16 +
 opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java                  |    2 
 opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java                  |   67 ++++
 opendj-sdk/opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java                     |   57 +++-
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.java          |    5 
 opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java                   |   36 ++
 opendj-sdk/opends/resource/admin/preprocessor.xsl                                                            |   54 +++
 opendj-sdk/opends/src/server/org/opends/server/admin/ManagedObjectPath.java                                  |   33 ++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java                    |    3 
 opendj-sdk/opends/resource/admin/clientMO.xsl                                                                |   11 
 opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java                   |    2 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java            |    2 
 opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/BackendConfiguration.xml                        |   14 
 opendj-sdk/opends/src/server/org/opends/server/admin/client/IllegalManagedObjectNameException.java           |  142 ++++++++++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java |    3 
 opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java                     |    2 
 opendj-sdk/opends/resource/admin/admin.xsd                                                                   |   15 +
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgClient.java        |    5 
 opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml                           |    3 
 opendj-sdk/opends/src/server/org/opends/server/admin/LDAPProfile.java                                        |   22 +
 opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java                      |   86 ++++-
 opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java                  |    2 
 opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java                                    |  107 +++++++
 opendj-sdk/opends/src/server/org/opends/server/admin/client/ManagedObject.java                               |    4 
 28 files changed, 700 insertions(+), 102 deletions(-)

diff --git a/opendj-sdk/opends/resource/admin/admin-ldap.xsd b/opendj-sdk/opends/resource/admin/admin-ldap.xsd
index 59e4264..4ebf60d 100644
--- a/opendj-sdk/opends/resource/admin/admin-ldap.xsd
+++ b/opendj-sdk/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>
diff --git a/opendj-sdk/opends/resource/admin/admin.xsd b/opendj-sdk/opends/resource/admin/admin.xsd
index a97b475..b4144a7 100644
--- a/opendj-sdk/opends/resource/admin/admin.xsd
+++ b/opendj-sdk/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>
diff --git a/opendj-sdk/opends/resource/admin/clientMO.xsl b/opendj-sdk/opends/resource/admin/clientMO.xsl
index 2e6197e..c4d166a 100644
--- a/opendj-sdk/opends/resource/admin/clientMO.xsl
+++ b/opendj-sdk/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">
diff --git a/opendj-sdk/opends/resource/admin/ldapMOProfile.xsl b/opendj-sdk/opends/resource/admin/ldapMOProfile.xsl
index 60c8d08..ea0973a 100644
--- a/opendj-sdk/opends/resource/admin/ldapMOProfile.xsl
+++ b/opendj-sdk/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),
diff --git a/opendj-sdk/opends/resource/admin/metaMO.xsl b/opendj-sdk/opends/resource/admin/metaMO.xsl
index c609d89..638fd55 100644
--- a/opendj-sdk/opends/resource/admin/metaMO.xsl
+++ b/opendj-sdk/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>
diff --git a/opendj-sdk/opends/resource/admin/preprocessor.xsl b/opendj-sdk/opends/resource/admin/preprocessor.xsl
index 9b14b13..dee2c1e 100644
--- a/opendj-sdk/opends/resource/admin/preprocessor.xsl
+++ b/opendj-sdk/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="@*" />
       <!--
diff --git a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/BackendConfiguration.xml b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/BackendConfiguration.xml
index 4bf46f8..8dc6d71 100644
--- a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/BackendConfiguration.xml
+++ b/opendj-sdk/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>
diff --git a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/JEBackendConfiguration.xml b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/JEBackendConfiguration.xml
index 7aefce2..fb9e639 100644
--- a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/JEBackendConfiguration.xml
+++ b/opendj-sdk/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>
diff --git a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml
index 4885fba..df30b76 100644
--- a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml
+++ b/opendj-sdk/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>
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java b/opendj-sdk/opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java
index b5898bf..2035206 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java
+++ b/opendj-sdk/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);
-  }
 }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/LDAPProfile.java b/opendj-sdk/opends/src/server/org/opends/server/admin/LDAPProfile.java
index 46e222b..3e2505d 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/LDAPProfile.java
+++ b/opendj-sdk/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());
   }
 
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/ManagedObjectPath.java b/opendj-sdk/opends/src/server/org/opends/server/admin/ManagedObjectPath.java
index ced9e0e8..eb164e1 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/ManagedObjectPath.java
+++ b/opendj-sdk/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>
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/client/IllegalManagedObjectNameException.java b/opendj-sdk/opends/src/server/org/opends/server/admin/client/IllegalManagedObjectNameException.java
new file mode 100644
index 0000000..541015e
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/client/IllegalManagedObjectNameException.java
@@ -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";
+  }
+
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/client/ManagedObject.java b/opendj-sdk/opends/src/server/org/opends/server/admin/client/ManagedObject.java
index 857c634..63eaec6 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/client/ManagedObject.java
+++ b/opendj-sdk/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;
 
 
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java b/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
index 0cb44f8..0c7630f 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
@@ -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);
   }
 
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
index 0e76f19..8c1094a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
+++ b/opendj-sdk/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");
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java b/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
index db45bcc..991106c 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
+++ b/opendj-sdk/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.
    *
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java b/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
index 5aa15c2..47123bc 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
+++ b/opendj-sdk/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;
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java b/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java
index 6878465..426cdf3 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java
+++ b/opendj-sdk/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,
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java b/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java
index b6af6cf..f8ecd19 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java
+++ b/opendj-sdk/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);
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java b/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java
index a37ec83..5bb2598 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java
+++ b/opendj-sdk/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);
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java b/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java
index f489108..fac8445 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java
+++ b/opendj-sdk/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,
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java b/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java
index a393f3d..ad503d5 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java
+++ b/opendj-sdk/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);
   }
 
 
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java
index 7fa2c05..c23bc6a 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/MockLDAPProfile.java
@@ -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();
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java
index 61587d0..86db1df 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java
@@ -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());
-
   }
 
 
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgClient.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgClient.java
index 6bcf604..e574a5c 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgClient.java
+++ b/opendj-sdk/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;
 
 
 
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.java
index 3d88428..2c076a8 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestParentCfgDefn.java
+++ b/opendj-sdk/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();
     }
 
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java
index 1fb6f8f..0bd0390 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/LDAPClientTest.java
@@ -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(),

--
Gitblit v1.10.0