From 183388b40ccc4e02a3299d0c78b5510011679c8a Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Fri, 22 Jun 2007 16:02:43 +0000
Subject: [PATCH] Initial commit of dsconfig the directory server administration tool.

---
 opends/src/server/org/opends/server/tools/dsconfig/PropertyValuePrinter.java             |  207 +
 opends/src/server/org/opends/server/tools/dsconfig/LDAPManagementContextFactory.java     |  212 +
 opends/src/server/org/opends/server/tools/dsconfig/messages.properties                   |   38 
 opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java         |  513 +++
 opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java         |  387 +++
 opends/src/server/org/opends/server/tools/dsconfig/CLIProfile.java                       |  105 
 opends/src/server/org/opends/server/tools/dsconfig/SubCommandBuilder.java                |  294 ++
 opends/src/server/org/opends/server/tools/dsconfig/Messages.java                         |   72 
 opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java          |  260 ++
 opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java            |  913 +++++++
 opends/src/server/org/opends/server/tools/dsconfig/ManagementContextFactory.java         |   93 
 opends/src/server/org/opends/server/messages/ToolMessages.java                           | 1360 ++++++++++
 opends/src/server/org/opends/server/tools/dsconfig/package-info.java                     |   35 
 opends/build.xml                                                                         |   12 
 opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java            |  415 +++
 opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java         |  568 ++++
 opends/resource/bin/dsconfig.bat                                                         |   33 
 opends/src/server/org/opends/server/tools/dsconfig/InternalManagementContextFactory.java |   90 
 opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java                |  858 ++++++
 opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java          |  560 ++++
 opends/resource/bin/dsconfig                                                             |   37 
 opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java                         |  666 +++++
 22 files changed, 7,692 insertions(+), 36 deletions(-)

diff --git a/opends/build.xml b/opends/build.xml
index 486c89e..961bf32 100644
--- a/opends/build.xml
+++ b/opends/build.xml
@@ -446,6 +446,10 @@
         </fileset>
       </classpath>
     </javac>
+
+    <copy todir="${classes.dir}">
+      <fileset dir="${src.dir}" includes="**/*.properties" />
+    </copy>
   </target>
 
 
@@ -608,6 +612,10 @@
       </classpath>
     </javac>
 
+    <copy todir="${classes.dir}">
+      <fileset dir="${src.dir}" includes="**/*.properties" />
+    </copy>
+
     <!-- Generate the OpenDS.jar file -->
     <jar jarfile="${pdir}/lib/OpenDS.jar"
          basedir="${classes.dir}" compress="true" index="true" />
@@ -735,10 +743,10 @@
 
     <antcall target="example-plugin" />
 
-    <fixcrlf srcDir="${scripts.dir}" destDir="${pdir}/bin" excludes="*.bat,_client-script.sh,_server-script.sh" eol="lf" />
+    <fixcrlf srcDir="${scripts.dir}" destDir="${pdir}/bin" excludes="*.bat,_client-script.sh,_server-script.sh,dsconfig" eol="lf" />
     <fixcrlf srcDir="${scripts.dir}" destDir="${pdir}/lib" includes="_client-script.sh,_server-script.sh" eol="lf" />
     <fixcrlf srcDir="${scripts.dir}" destDir="${pdir}/bin" includes="README_WINDOWS.txt" eol="crlf" />
-    <fixcrlf srcDir="${scripts.dir}" destDir="${pdir}/bat" excludes="_client-script.bat,_server-script.bat,setcp.bat" includes="*.bat" eol="crlf" />
+    <fixcrlf srcDir="${scripts.dir}" destDir="${pdir}/bat" excludes="_client-script.bat,_server-script.bat,setcp.bat,dsconfig.bat" includes="*.bat" eol="crlf" />
     <fixcrlf srcDir="${scripts.dir}" destDir="${pdir}/lib" includes="_client-script.bat,_server-script.bat,setcp.bat" eol="crlf" />
 
     <copy todir="${pdir}/config">
diff --git a/opends/resource/bin/dsconfig b/opends/resource/bin/dsconfig
new file mode 100755
index 0000000..992b0dd
--- /dev/null
+++ b/opends/resource/bin/dsconfig
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# 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 2006-2007 Sun Microsystems, Inc.
+
+
+# This script may be used to perform LDAP search operations.
+OPENDS_INVOKE_CLASS="org.opends.server.tools.dsconfig.DSConfig"
+export OPENDS_INVOKE_CLASS
+
+SCRIPT_NAME_ARG="-Dorg.opends.server.scriptName=dsconfig"
+export SCRIPT_NAME_ARG
+
+SCRIPT_DIR=`dirname "${0}"`
+"${SCRIPT_DIR}/../lib/_client-script.sh" "${@}"
diff --git a/opends/resource/bin/dsconfig.bat b/opends/resource/bin/dsconfig.bat
new file mode 100644
index 0000000..d2ea99f
--- /dev/null
+++ b/opends/resource/bin/dsconfig.bat
@@ -0,0 +1,33 @@
+
+@echo off
+rem CDDL HEADER START
+rem
+rem The contents of this file are subject to the terms of the
+rem Common Development and Distribution License, Version 1.0 only
+rem (the "License").  You may not use this file except in compliance
+rem with the License.
+rem
+rem You can obtain a copy of the license at
+rem trunk/opends/resource/legal-notices/OpenDS.LICENSE
+rem or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+rem See the License for the specific language governing permissions
+rem and limitations under the License.
+rem
+rem When distributing Covered Code, include this CDDL HEADER in each
+rem file and include the License file at
+rem trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+rem add the following below this CDDL HEADER, with the fields enclosed
+rem by brackets "[]" replaced with your own identifying information:
+rem      Portions Copyright [yyyy] [name of copyright owner]
+rem
+rem CDDL HEADER END
+rem
+rem
+rem      Portions Copyright 2006-2007 Sun Microsystems, Inc.
+
+setlocal
+
+set OPENDS_INVOKE_CLASS="org.opends.server.tools.dsconfig.DSConfig"
+set SCRIPT_NAME_ARG="-Dorg.opends.server.scriptName=dsconfig"
+call "%~dP0\..\lib\_client-script.bat" %*
+
diff --git a/opends/src/server/org/opends/server/messages/ToolMessages.java b/opends/src/server/org/opends/server/messages/ToolMessages.java
index d9c4338..24e71bd 100644
--- a/opends/src/server/org/opends/server/messages/ToolMessages.java
+++ b/opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -28,13 +28,13 @@
 
 
 
-import org.opends.server.extensions.ConfigFileHandler;
-
 import static org.opends.server.messages.MessageHandler.*;
 import static org.opends.server.tools.ToolConstants.*;
 import static org.opends.server.util.DynamicConstants.*;
 import static org.opends.server.util.ServerConstants.*;
 
+import org.opends.server.extensions.ConfigFileHandler;
+
 
 
 /**
@@ -7067,38 +7067,964 @@
   public static final int MSGID_LDIFIMPORT_CANNOT_READ_FILE =
        CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 887;
 
-/**
-  * The message ID for the message that will be used as the description of the
-  * geteffectiverights control authzid argument.  This does not take any
-  * arguments.
-  */
- public static final int MSGID_DESCRIPTION_EFFECTIVERIGHTS_USER =
-      CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 888;
 
 
- /**
-  * The message ID for the message that will be used as the description of the
-  * geteffectiverights control specific attribute list argument.  This does
-  * not take any arguments.
-  */
- public static final int MSGID_DESCRIPTION_EFFECTIVERIGHTS_ATTR =
-      CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 889;
+  /**
+   * The message ID for the message that will be used as the description of the
+   * geteffectiverights control authzid argument.  This does not take any
+   * arguments.
+   */
+  public static final int MSGID_DESCRIPTION_EFFECTIVERIGHTS_USER =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 888;
 
 
- /**
-  * The message ID for the message that will be used as the description of the
-  * geteffectiverights authzid when it does not start with the required string
-  * "dn:". This takes a single argument, which is the authzid string.
-  */
- public static final int MSGID_EFFECTIVERIGHTS_INVALID_AUTHZID =
-      CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 890;
 
- /**
-  * The message ID for the message that will be used as the description of the
-  * version argument.  This does not take any arguments.
-  */
- public static final int MSGID_DESCRIPTION_PRODUCT_VERSION =
-      CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 891;
+  /**
+   * The message ID for the message that will be used as the description of the
+   * geteffectiverights control specific attribute list argument.  This does
+   * not take any arguments.
+   */
+  public static final int MSGID_DESCRIPTION_EFFECTIVERIGHTS_ATTR =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 889;
+
+
+
+  /**
+   * The message ID for the message that will be used as the description of the
+   * geteffectiverights authzid when it does not start with the required string
+   * "dn:". This takes a single argument, which is the authzid string.
+   */
+  public static final int MSGID_EFFECTIVERIGHTS_INVALID_AUTHZID =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 890;
+
+
+
+  /**
+   * The message ID for the message that will be used as the description of the
+   * version argument.  This does not take any arguments.
+   */
+  public static final int MSGID_DESCRIPTION_PRODUCT_VERSION =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 891;
+
+
+
+  /**
+   * The message ID for the message that will be used if dscfg cannot
+   * read the LDAP bind password. This takes a single argument, which
+   * is a message explaining the problem that occurred.
+   */
+  public static final int MSGID_DSCFG_ERROR_CANNOT_READ_LDAP_BIND_PASSWORD =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1000;
+
+
+
+  /**
+   * The message ID for the message that will be used if dscfg cannot
+   * bind to the directory server. This takes a single argument, which
+   * is the bind DN.
+   */
+  public static final int MSGID_DSCFG_ERROR_LDAP_SIMPLE_BIND_FAILED =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1001;
+
+
+
+  /**
+   * The message ID for the message that will be used if dscfg cannot
+   * connect to the directory server. This takes a two arguments,
+   * which are the host and port.
+   */
+  public static final int MSGID_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1002;
+
+
+
+  /**
+   * The message ID for the message that will be used if dscfg cannot
+   * bind to the directory server because it does not allow simple
+   * authentication. This does not take any arguments.
+   */
+  public static final int MSGID_DSCFG_ERROR_LDAP_SIMPLE_BIND_NOT_SUPPORTED =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1003;
+
+
+
+  /**
+   * The message ID for the message that will be used to describe a
+   * dscfg create-xxx sub-command. This takes a single argument, which
+   * is the type of component that can be created.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_SUBCMD_CREATE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1004;
+
+
+
+  /**
+   * The message ID for the message that will be used to describe a
+   * dscfg delete-xxx sub-command. This takes a single argument, which
+   * is the type of component that can be delete.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_SUBCMD_DELETE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1005;
+
+
+
+  /**
+   * The message ID for the message that will be used to describe a
+   * dscfg list-xxx sub-command. This takes a single argument, which
+   * is the type of component that can be list.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_SUBCMD_LIST =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1006;
+
+
+
+  /**
+   * The message ID for the message that will be used to describe a
+   * dscfg get-xxx-prop sub-command. This takes a single argument, which
+   * is the type of component that can be queried.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_SUBCMD_GETPROP =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1007;
+
+
+
+  /**
+   * The message ID for the message that will be used to describe a
+   * dscfg set-xxx-prop sub-command. This takes a single argument, which
+   * is the type of component that can be modified.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_SUBCMD_SETPROP =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1008;
+
+
+
+  /**
+   * The message ID for the message that will be used if the user fails
+   * to specify a sub-command. No message arguments are required.
+   */
+  public static final int MSGID_DSCFG_ERROR_MISSING_SUBCOMMAND =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1009;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of the create-xxx type argument when it is mandatory.
+   * This takes a single argument which is the user friendly name for
+   * the type of managed objects being created.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_TYPE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1010;
+
+
+
+  /**
+   * The message ID for the message that will be used if the user
+   * fails to provide an admistrator password. This takes a single
+   * argument which is the name of the administrator.
+   */
+  public static final int MSGID_DSCFG_ERROR_NO_PASSWORD =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1011;
+
+
+
+  /**
+   * The message ID for the message that will be used if the user
+   * attempts to access a property which is not part of the associated
+   * managed object. This takes two arguments which are the name of
+   * the invalid property and the user friendly plural name of the
+   * associated managed object.
+   */
+  public static final int MSGID_DSCFG_ERROR_PROPERTY_UNRECOGNIZED =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1012;
+
+
+
+  /**
+   * The message ID for the message that will be used if the user
+   * attempts to set a property using a value which is invalid
+   * according to the property's definition. This takes four arguments
+   * which are the invalid value, the user friendly name of the
+   * associated managed object, the name of the property, and the
+   * property's syntax.
+   */
+  public static final int MSGID_DSCFG_ERROR_PROPERTY_INVALID_VALUE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1013;
+
+
+
+  /**
+   * The message ID for the message that will be used if the user
+   * attempts to modify a read-only property. This takes two arguments
+   * which are the user friendly name of the associated managed
+   * object, and the name of the property.
+   */
+  public static final int MSGID_DSCFG_ERROR_PROPERTY_READ_ONLY =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1014;
+
+
+
+  /**
+   * The message ID for the message that will be used if the user
+   * fails to specify a value for a mandatory property. This takes two
+   * arguments which are the user friendly name of the associated
+   * managed object, and the name of the property.
+   */
+  public static final int MSGID_DSCFG_ERROR_PROPERTY_MANDATORY =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1015;
+
+
+
+  /**
+   * The message ID for the message that will be used if the user
+   * attempts to specify more than one value for a single-valued
+   * property. This takes two arguments which are the user friendly
+   * name of the associated managed object, and the name of the
+   * property.
+   */
+  public static final int MSGID_DSCFG_ERROR_PROPERTY_SINGLE_VALUED =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1016;
+
+
+
+  /**
+   * The message ID for the message that will be used to describe the
+   * dscfg help-properties sub-command. This does not take any
+   * arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_SUBCMD_HELPPROP =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1017;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * heading of the managed object type column in tables.
+   */
+  public static final int MSGID_DSCFG_HEADING_MANAGED_OBJECT_NAME =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1018;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * heading of the property name column in tables.
+   */
+  public static final int MSGID_DSCFG_HEADING_PROPERTY_NAME =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1019;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * heading of the property value column in tables.
+   */
+  public static final int MSGID_DSCFG_HEADING_PROPERTY_VALUE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1020;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * heading of the property syntax column in tables.
+   */
+  public static final int MSGID_DSCFG_HEADING_PROPERTY_SYNTAX =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1021;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * heading of the property options column in tables.
+   */
+  public static final int MSGID_DSCFG_HEADING_PROPERTY_OPTIONS =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1022;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * heading of the property default column in tables.
+   */
+  public static final int MSGID_DSCFG_HEADING_PROPERTY_DEFAULT =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1023;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * heading of the property description column in tables.
+   */
+  public static final int MSGID_DSCFG_HEADING_PROPERTY_DESCRIPTION =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1024;
+
+
+
+  /**
+   * The message ID for the message that will be used when a
+   * property's syntax usage is too big to be displayed.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_PROPERTY_SYNTAX_HELP =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1025;
+
+
+
+  /**
+   * The message ID for the message that will be used when a parent
+   * managed object cannot be retrieved due to a definition decoding
+   * problem.
+   */
+  public static final int MSGID_DSCFG_ERROR_GET_PARENT_DDE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1026;
+
+
+
+  /**
+   * The message ID for the message that will be used when a parent
+   * managed object cannot be retrieved due to a managed object
+   * decoding problem.
+   */
+  public static final int MSGID_DSCFG_ERROR_GET_PARENT_MODE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1027;
+
+
+
+  /**
+   * The message ID for the message that will be used when a parent
+   * managed object cannot be found.
+   */
+  public static final int MSGID_DSCFG_ERROR_GET_PARENT_MONFE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1028;
+
+
+
+  /**
+   * The message ID for the message that will be used when a parent
+   * managed object cannot be retrieved due to an authorization problem.
+   */
+  public static final int MSGID_DSCFG_ERROR_GET_PARENT_AUTHZ =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1029;
+
+
+
+  /**
+   * The message ID for the message that will be used when a parent
+   * managed object cannot be retrieved due to a communications error.
+   */
+  public static final int MSGID_DSCFG_ERROR_GET_PARENT_CE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1030;
+
+
+
+  /**
+   * The message ID for the message that will be used when a parent
+   * managed object cannot be retrieved due to conflicting concurrent
+   * modification by another client.
+   */
+  public static final int MSGID_DSCFG_ERROR_GET_PARENT_CME =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1031;
+
+
+
+  /**
+   * The message ID for the message that will be used when a child
+   * managed object cannot be created because one or more of its
+   * mandatory properties are missing.
+   */
+  public static final int MSGID_DSCFG_ERROR_CREATE_MMPE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1032;
+
+
+
+  /**
+   * The message ID for the message that will be used when a child
+   * managed object cannot be created because there is already a
+   * managed object with the same name.
+   */
+  public static final int MSGID_DSCFG_ERROR_CREATE_MOAEE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1033;
+
+
+
+  /**
+   * The message ID for the message that will be used when a managed
+   * object cannot be created due to an authorization problem.
+   */
+  public static final int MSGID_DSCFG_ERROR_CREATE_AUTHZ =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1034;
+
+
+
+  /**
+   * The message ID for the message that will be used when a managed
+   * object cannot be created due to a communications error.
+   */
+  public static final int MSGID_DSCFG_ERROR_CREATE_CE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1035;
+
+
+
+  /**
+   * The message ID for the message that will be used when a
+   * managed object cannot be created due to conflicting concurrent
+   * modification by another client.
+   */
+  public static final int MSGID_DSCFG_ERROR_CREATE_CME =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1036;
+
+
+
+  /**
+   * The message ID for the message that will be used when the server
+   * prevents a managed object from being created due to some
+   * server-side constraint that has not been satisfied.
+   */
+  public static final int MSGID_DSCFG_ERROR_CREATE_ORE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1037;
+
+
+
+  /**
+   * The message ID for the message that will be used when a child
+   * managed object cannot be deleted because it could not be found.
+   */
+  public static final int MSGID_DSCFG_ERROR_DELETE_MONFE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1038;
+
+
+
+  /**
+   * The message ID for the message that will be used when a managed
+   * object cannot be deleted due to an authorization problem.
+   */
+  public static final int MSGID_DSCFG_ERROR_DELETE_AUTHZ =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1039;
+
+
+
+  /**
+   * The message ID for the message that will be used when the server
+   * prevents a managed object from being deleted due to some
+   * server-side constraint that has not been satisfied.
+   */
+  public static final int MSGID_DSCFG_ERROR_DELETE_ORE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1040;
+
+
+
+  /**
+   * The message ID for the message that will be used when a managed
+   * object cannot be deleted due to a communications error.
+   */
+  public static final int MSGID_DSCFG_ERROR_DELETE_CE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1041;
+
+
+
+  /**
+   * The message ID for the message that will be used when a
+   * managed object cannot be deleted due to conflicting concurrent
+   * modification by another client.
+   */
+  public static final int MSGID_DSCFG_ERROR_DELETE_CME =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1042;
+
+
+
+  /**
+   * The message ID for the message that will be used when a child
+   * managed object cannot be retrieved due to a definition decoding
+   * problem.
+   */
+  public static final int MSGID_DSCFG_ERROR_GET_CHILD_DDE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1043;
+
+
+
+  /**
+   * The message ID for the message that will be used when a child
+   * managed object cannot be retrieved due to a managed object
+   * decoding problem.
+   */
+  public static final int MSGID_DSCFG_ERROR_GET_CHILD_MODE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1044;
+
+
+
+  /**
+   * The message ID for the message that will be used when a child
+   * managed object cannot be found.
+   */
+  public static final int MSGID_DSCFG_ERROR_GET_CHILD_MONFE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1045;
+
+
+
+  /**
+   * The message ID for the message that will be used when a child
+   * managed object cannot be retrieved due to an authorization problem.
+   */
+  public static final int MSGID_DSCFG_ERROR_GET_CHILD_AUTHZ =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1046;
+
+
+
+  /**
+   * The message ID for the message that will be used when a child
+   * managed object cannot be retrieved due to a communications error.
+   */
+  public static final int MSGID_DSCFG_ERROR_GET_CHILD_CE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1047;
+
+
+
+  /**
+   * The message ID for the message that will be used when a child
+   * managed object cannot be retrieved due to conflicting concurrent
+   * modification by another client.
+   */
+  public static final int MSGID_DSCFG_ERROR_GET_CHILD_CME =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1048;
+
+
+
+  /**
+   * The message ID for the message that will be used when a child
+   * managed object cannot be modified because it could not be found.
+   */
+  public static final int MSGID_DSCFG_ERROR_MODIFY_MONFE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1049;
+
+
+
+  /**
+   * The message ID for the message that will be used when a managed
+   * object cannot be modified due to an authorization problem.
+   */
+  public static final int MSGID_DSCFG_ERROR_MODIFY_AUTHZ =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1050;
+
+
+
+  /**
+   * The message ID for the message that will be used when a managed
+   * object cannot be modified due to a communications error.
+   */
+  public static final int MSGID_DSCFG_ERROR_MODIFY_CE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1051;
+
+
+
+  /**
+   * The message ID for the message that will be used when a
+   * managed object cannot be modified due to conflicting concurrent
+   * modification by another client.
+   */
+  public static final int MSGID_DSCFG_ERROR_MODIFY_CME =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1052;
+
+
+
+  /**
+   * The message ID for the message that will be used when the server
+   * prevents a managed object from being modified due to some
+   * server-side constraint that has not been satisfied.
+   */
+  public static final int MSGID_DSCFG_ERROR_MODIFY_ORE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1053;
+
+
+
+  /**
+   * The message ID for the message that will be used when an optional
+   * child managed object cannot be listed due to a definition
+   * decoding problem.
+   */
+  public static final int MSGID_DSCFG_ERROR_LIST_DDE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1054;
+
+
+
+  /**
+   * The message ID for the message that will be used when an optional
+   * child managed object cannot be listed due to a managed object
+   * decoding problem.
+   */
+  public static final int MSGID_DSCFG_ERROR_LIST_MODE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1055;
+
+
+
+  /**
+   * The message ID for the message that will be used when an optional
+   * child managed object cannot be listed because it does not exist.
+   */
+  public static final int MSGID_DSCFG_ERROR_LIST_MONFE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1056;
+
+
+
+  /**
+   * The message ID for the message that will be used when managed
+   * objects cannot be listed due to an authorization problem.
+   */
+  public static final int MSGID_DSCFG_ERROR_LIST_AUTHZ =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1057;
+
+
+
+  /**
+   * The message ID for the message that will be used when managed
+   * object cannot be listed due to a communications error.
+   */
+  public static final int MSGID_DSCFG_ERROR_LIST_CE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1058;
+
+
+
+  /**
+   * The message ID for the message that will be used when
+   * managed object cannot be listed due to conflicting concurrent
+   * modification by another client.
+   */
+  public static final int MSGID_DSCFG_ERROR_LIST_CME =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1059;
+
+
+
+  /**
+   * The message ID for the message that will be used if a property
+   * value(s) cannot be determined due to some unknown reason. This
+   * takes three arguments which are the user friendly name of the
+   * associated managed object, the name of the property, and the
+   * cause.
+   */
+  public static final int MSGID_DSCFG_ERROR_PROPERTY_UNKNOWN_ERROR =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1060;
+
+
+  /**
+   * The message ID for the message that will be used if a property's
+   * default values cannot be determined. This takes three arguments
+   * which are the user friendly name of the associated managed
+   * object, the name of the property, and the cause.
+   */
+  public static final int MSGID_DSCFG_ERROR_PROPERTY_DEFAULT_BEHAVIOR =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1061;
+
+
+  /**
+   * The message ID for the message that will be used if a property's
+   * inherited default values cannot be determined. This takes two
+   * arguments which are the user friendly name of the associated
+   * managed object, and the name of the property.
+   */
+  public static final int
+    MSGID_DSCFG_ERROR_PROPERTY_INHERITED_DEFAULT_BEHAVIOR =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1062;
+
+
+  /**
+   * The message ID for the message that will be used if a property
+   * argument did not contain a name/value separator. This takes a
+   * single arguments which is the invalid property value argument.
+   */
+  public static final int MSGID_DSCFG_ERROR_NO_SEPARATOR_IN_PROPERTY_VALUE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1063;
+
+
+  /**
+   * The message ID for the message that will be used if a property
+   * argument did not contain a property name. This takes a single
+   * arguments which is the invalid property value argument.
+   */
+  public static final int MSGID_DSCFG_ERROR_NO_NAME_IN_PROPERTY_VALUE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1064;
+
+
+  /**
+   * The message ID for the message that will be used if a property
+   * argument did not contain a property value. This takes a single
+   * arguments which is the invalid property value argument.
+   */
+  public static final int MSGID_DSCFG_ERROR_NO_VALUE_IN_PROPERTY_VALUE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1065;
+
+
+
+  /**
+   * The message ID for the message that will be used if the user
+   * attempts to create a managed object but specifies an unknown type
+   * name. This takes three arguments which are the invalid argument,
+   * the user friendly name of the managed object, and the supported types.
+   */
+  public static final int MSGID_DSCFG_ERROR_SUB_TYPE_UNRECOGNIZED =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1066;
+
+
+
+  /**
+   * The message ID for the message that will be used if the user
+   * requests help for a managed object but specifies an unknown type
+   * name. This takes a single argument which is the invalid argument.
+   */
+  public static final int MSGID_DSCFG_ERROR_TYPE_UNRECOGNIZED =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1067;
+
+
+  /**
+   * The message ID for the message that will be used if a property
+   * modification did not contain a name/value separator. This takes a
+   * single arguments which is the invalid property value argument.
+   */
+  public static final int MSGID_DSCFG_ERROR_NO_SEPARATOR_IN_PROPERTY_MOD =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1068;
+
+
+  /**
+   * The message ID for the message that will be used if a property
+   * modification did not contain a property name. This takes a single
+   * arguments which is the invalid property value argument.
+   */
+  public static final int MSGID_DSCFG_ERROR_NO_NAME_IN_PROPERTY_MOD =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1069;
+
+
+  /**
+   * The message ID for the message that will be used if a property
+   * modification did not contain a property value. This takes a
+   * single arguments which is the invalid property value argument.
+   */
+  public static final int MSGID_DSCFG_ERROR_NO_VALUE_IN_PROPERTY_MOD =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1070;
+
+
+  /**
+   * The message ID for the message that will be used if an attempt is
+   * made to apply incompatible property modifications. This takes a
+   * single arguments which is the invalid property value argument.
+   */
+  public static final int MSGID_DSCFG_ERROR_INCOMPATIBLE_PROPERTY_MOD =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1071;
+
+
+
+  /**
+   * The message ID for the message that will be used if a managed
+   * object is retrieved whilst processing a sub-command but the
+   * retrieved object is not the correct type of object required in
+   * order to perform the operation. This takes two arguments which
+   * are the relation definition user friendly name and the user
+   * friendly name of the definition of the object that was retrieved.
+   */
+  public static final int MSGID_DSCFG_ERROR_WRONG_MANAGED_OBJECT_TYPE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1072;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of the create-xxx type argument when it is optional.
+   * This takes two arguments which are the user friendly name for the
+   * type of managed objects being created and the default value.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_TYPE_DEFAULT =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1073;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of the get-xxx-prop record argument. This takes no
+   * arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_RECORD =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1074;
+
+
+
+  /**
+   * The message ID for the message that will be used as the description of the
+   * quiet argument.  This does not take any arguments.
+   */
+  public static final int MSGID_DESCRIPTION_QUIET =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1075;
+
+
+
+  /**
+   * The message ID for the message that will be used as the description of the
+   * script-friendly argument.  This does not take any arguments.
+   */
+  public static final int MSGID_DESCRIPTION_SCRIPT_FRIENDLY =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1076;
+
+
+
+  /**
+   * The message ID for the message that will be used as the description of the
+   * interactive argument.  This does not take any arguments.
+   */
+  public static final int MSGID_DESCRIPTION_INTERACTIVE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1077;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of the unit-time argument. This takes no arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_UNIT_TIME =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1078;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of the unit-size argument. This takes no arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_UNIT_SIZE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1079;
+
+
+
+  /**
+   * The message ID for the message that will be used when the user
+   * provides an invalid parameter to the unit-time argument. This
+   * takes a single argument which is the invalid parameter.
+   */
+  public static final int MSGID_DSCFG_ERROR_TIME_UNIT_UNRECOGNIZED =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1080;
+
+
+
+  /**
+   * The message ID for the message that will be used when the user
+   * provides an invalid parameter to the unit-size argument. This
+   * takes a single argument which is the invalid parameter.
+   */
+  public static final int MSGID_DSCFG_ERROR_SIZE_UNIT_UNRECOGNIZED =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1081;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * heading of the managed object type column in list tables.
+   */
+  public static final int MSGID_DSCFG_HEADING_MANAGED_OBJECT_TYPE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1082;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of a --help-xxx argument. This takes a single
+   * argument which is the synopsis of the group.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1083;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of a --help-all argument. This does not take any
+   * arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_ALL =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1084;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of a --help argument. This does not take any
+   * arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_SUMMARY =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1085;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of the a naming argument. 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 =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1086;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of the property name argument. This does not take any
+   * arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_PROP =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1087;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of the property value argument. This does not take
+   * any arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_PROP_VAL =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1088;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of the add property value argument. This does not
+   * take any arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_ADD_PROP_VAL =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1089;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of the remove property value argument. This does not
+   * take any arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_REMOVE_PROP_VAL =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1090;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of the reset property argument. This does not take
+   * any arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_RESET_PROP =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1091;
+
+
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of the list-properties type argument. This does not
+   * take any arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_HELP_TYPE =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1092;
+
+
+
+  /**
+   * The message ID for the message that will be used if dscfg cannot
+   * read the LDAP bind password interactively.
+   */
+  public static final int MSGID_DSCFG_ERROR_BIND_PASSWORD_NONINTERACTIVE =
+    CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1093;
+
 
 
   /**
@@ -7468,6 +8394,12 @@
                     "# You have %d grace logins remaining");
     registerMessage(MSGID_DESCRIPTION_VERBOSE,
                     "Use verbose mode");
+    registerMessage(MSGID_DESCRIPTION_QUIET,
+                    "Use quiet mode");
+    registerMessage(MSGID_DESCRIPTION_INTERACTIVE,
+                    "Use interactive mode");
+    registerMessage(MSGID_DESCRIPTION_SCRIPT_FRIENDLY,
+                    "Use script-friendly mode");
     registerMessage(MSGID_DESCRIPTION_KEYSTOREPATH,
                     "Certificate keystore path");
     registerMessage(MSGID_DESCRIPTION_TRUSTSTOREPATH,
@@ -9327,7 +10259,7 @@
     registerMessage(MSGID_LDIFIMPORT_CANNOT_READ_FILE,
                     "The specified LDIF file %s cannot be read");
 
-   registerMessage(MSGID_DESCRIPTION_EFFECTIVERIGHTS_USER,
+    registerMessage(MSGID_DESCRIPTION_EFFECTIVERIGHTS_USER,
                     "Use geteffectiverights control with the provided " +
                     "authzid");
 
@@ -9335,13 +10267,373 @@
                     "Specifies geteffectiverights control specific " +
                     "attribute list");
 
-   registerMessage(MSGID_EFFECTIVERIGHTS_INVALID_AUTHZID,
+    registerMessage(MSGID_EFFECTIVERIGHTS_INVALID_AUTHZID,
                     "The authorization ID \"%s\" contained in the " +
-                     "geteffectiverights control is invalid because it does" +
-                     " not start with \"dn:\" to indicate a user DN");
+                    "geteffectiverights control is invalid because it does" +
+                    " not start with \"dn:\" to indicate a user DN");
 
-   registerMessage(MSGID_DESCRIPTION_PRODUCT_VERSION,
+    registerMessage(MSGID_DESCRIPTION_PRODUCT_VERSION,
                    "Display Directory Server version information");
+
+    registerMessage(MSGID_DSCFG_ERROR_CANNOT_READ_LDAP_BIND_PASSWORD,
+                    "The LDAP bind password could not be read due to the" +
+                    " following error: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_BIND_PASSWORD_NONINTERACTIVE,
+                    "The LDAP bind password was not specified and " +
+                    "cannot be read interactively");
+
+    registerMessage(MSGID_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT,
+                    "Unable to connect to the server at %s on port %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_LDAP_SIMPLE_BIND_FAILED,
+                    "Unable to authenticate to the server as %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_LDAP_SIMPLE_BIND_NOT_SUPPORTED,
+                    "Unable to authenticate using simple authentication");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_SUBCMD_CREATE,
+                    "Creates %s");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_SUBCMD_DELETE,
+                    "Deletes %s");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_SUBCMD_LIST,
+                    "Lists existing %s");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_SUBCMD_GETPROP,
+                    "Shows %s properties");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_SUBCMD_SETPROP,
+                    "Modifies %s properties");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_SUBCMD_HELPPROP,
+                    "Describes managed objects and their properties");
+
+    registerMessage(MSGID_DSCFG_ERROR_MISSING_SUBCOMMAND,
+                    "A sub-command must be specified");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_NAME,
+                    "The name of the %s");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_HELP_TYPE,
+                    "The type(s) of components whose properties should be " +
+                    "described");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_TYPE,
+                    "The type of %s which should be created. The value " +
+                    "for TYPE can be one of: %s");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_TYPE_DEFAULT,
+                    "The type of %s which should be created (Default: %s). " +
+                    "The value for TYPE can be one of: %s");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_PROP,
+                    "The name of a property to be displayed");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_PROP_VAL,
+                    "Assigns a value to a property where PROP is the name of " +
+                    "the property and VAL is the single value to be " +
+                    "assigned. Specify the same property multiple times " +
+                    "in order to assign more than one value to it");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_REMOVE_PROP_VAL,
+                    "Removes a single value from a property where PROP is " +
+                    "the name of the property and VAL is the single value " +
+                    "to be removed");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_ADD_PROP_VAL,
+                    "Adds a single value to a property where PROP is " +
+                    "the name of the property and VAL is the single value " +
+                    "to be added");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_RESET_PROP,
+                    "Resets a property back to its default values where PROP " +
+                    "is the name of the property to be reset");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_RECORD,
+                    "Modifies the display output to show one property " +
+                    "value per line");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_UNIT_TIME,
+                    "Display time data using the specified unit. The value " +
+                    "for UNIT can be one of ms, s, m, h, d, or w " +
+                    "(milliseconds, seconds, minutes, hours, days, or weeks)");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_UNIT_SIZE,
+                    "Display size data using the specified unit. The value " +
+                    "for UNIT can be one of b, kb, mb, gb, or tb (bytes, " +
+                    "kilobytes, megabytes, gigabytes, or terabytes)");
+
+    registerMessage(MSGID_DSCFG_ERROR_TIME_UNIT_UNRECOGNIZED,
+                    "The time unit \"%s\" is invalid. The valid time units " +
+                    "are ms, s, m, h, d, or w (milliseconds, seconds, " +
+                    "minutes, hours, days, or weeks)");
+
+    registerMessage(MSGID_DSCFG_ERROR_SIZE_UNIT_UNRECOGNIZED,
+                    "The size unit \"%s\" is invalid. The valid size units " +
+                    "are b, kb, mb, gb, or tb (bytes, kilobytes, " +
+                    "megabytes, gigabytes, or terabytes)");
+
+    registerMessage(MSGID_DSCFG_ERROR_NO_PASSWORD,
+                    "No password was specified for administrator \"%s\"");
+
+    registerMessage(MSGID_DSCFG_ERROR_PROPERTY_UNRECOGNIZED,
+                    "The property \"%s\" is not a recognized property of %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_PROPERTY_INVALID_VALUE,
+                    "The value \"%s\" is not a valid value for the %s " +
+                    "property \"%s\" which has the following syntax: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_PROPERTY_READ_ONLY,
+                    "The %s property \"%s\" is read-only and cannot " +
+                    "be modified");
+
+    registerMessage(MSGID_DSCFG_ERROR_PROPERTY_MANDATORY,
+                    "The %s property \"%s\" is mandatory and must " +
+                    "be specified");
+
+    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");
+
+    registerMessage(MSGID_DSCFG_ERROR_PROPERTY_UNKNOWN_ERROR,
+                    "The value(s) of the %s property \"%s\" could not be " +
+                    "determined due to an unknown error: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_PROPERTY_DEFAULT_BEHAVIOR,
+                    "The default value(s) of the %s property \"%s\" could " +
+                    "not be determined due to the following reason: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_PROPERTY_INHERITED_DEFAULT_BEHAVIOR,
+                    "The inherited default value(s) of the %s property " +
+                    "\"%s\" could not be determined");
+
+    registerMessage(MSGID_DSCFG_HEADING_MANAGED_OBJECT_NAME,
+                    "Component");
+
+    registerMessage(MSGID_DSCFG_HEADING_MANAGED_OBJECT_TYPE,
+                    "Type");
+
+    registerMessage(MSGID_DSCFG_HEADING_PROPERTY_NAME,
+                    "Property");
+
+    registerMessage(MSGID_DSCFG_HEADING_PROPERTY_VALUE,
+                    "Value(s)");
+
+    registerMessage(MSGID_DSCFG_HEADING_PROPERTY_SYNTAX,
+                    "Syntax");
+
+    registerMessage(MSGID_DSCFG_HEADING_PROPERTY_OPTIONS,
+                    "Options");
+
+    registerMessage(MSGID_DSCFG_HEADING_PROPERTY_DEFAULT,
+                    "Default");
+
+    registerMessage(MSGID_DSCFG_HEADING_PROPERTY_DESCRIPTION,
+                    "Description");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_PROPERTY_SYNTAX_HELP,
+                    "See detailed help");
+
+    registerMessage(MSGID_DSCFG_ERROR_CREATE_MOAEE,
+                    "The %s could not be created because there is " +
+                    "already an existing one with the same name");
+
+    registerMessage(MSGID_DSCFG_ERROR_CREATE_MMPE,
+                    "The %s could not be created because the " +
+                    "following mandatory properties must be defined: %s");
+
+
+    registerMessage(MSGID_DSCFG_ERROR_CREATE_AUTHZ,
+                    "The %s could not be created because you do " +
+                    "not have the correct authorization");
+
+    registerMessage(MSGID_DSCFG_ERROR_CREATE_CE,
+                    "The %s could not be created due to a " +
+                    "communications problem: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_CREATE_CME,
+                    "The %s could not be created because another " +
+                    "client is currently making conflicting configuration " +
+                    "changes");
+
+    registerMessage(MSGID_DSCFG_ERROR_CREATE_ORE,
+                    "The server prevented the %s from being created " +
+                    "because of the following reason: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_DELETE_MONFE,
+                    "The %s could not be deleted because it does not exist");
+
+
+    registerMessage(MSGID_DSCFG_ERROR_DELETE_AUTHZ,
+                    "The %s could not be deleted because you do " +
+                    "not have the correct authorization");
+
+    registerMessage(MSGID_DSCFG_ERROR_DELETE_ORE,
+                    "The server prevented the %s from being deleted " +
+                    "because of the following reason: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_DELETE_CE,
+                    "The %s could not be deleted due to a " +
+                    "communications problem: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_DELETE_CME,
+                    "The %s could not be deleted because another " +
+                    "client is currently making conflicting configuration " +
+                    "changes");
+
+    registerMessage(MSGID_DSCFG_ERROR_LIST_DDE,
+                    "The %s could not be retrieved because its type could " +
+                    "not be determined. This is probably due to the %s " +
+                    "having an invalid LDAP entry. Check that the %s " +
+                    "object classes are correct");
+
+    registerMessage(MSGID_DSCFG_ERROR_LIST_MODE,
+                    "The %s could not be retrieved because of the " +
+                    "reasons listed below:");
+
+    registerMessage(MSGID_DSCFG_ERROR_LIST_MONFE,
+                    "The %s does not exist");
+
+    registerMessage(MSGID_DSCFG_ERROR_LIST_AUTHZ,
+                    "The %s could not be listed because you do " +
+                    "not have the correct authorization");
+
+    registerMessage(MSGID_DSCFG_ERROR_LIST_CE,
+                    "The %s could not be listed due to a " +
+                    "communications problem: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_LIST_CME,
+                    "The %s could not be listed because another " +
+                    "client is currently making conflicting configuration " +
+                    "changes");
+
+    registerMessage(MSGID_DSCFG_ERROR_MODIFY_MONFE,
+                    "The %s could not be modified because it does not exist");
+
+    registerMessage(MSGID_DSCFG_ERROR_MODIFY_AUTHZ,
+                    "The %s could not be modified because you do " +
+                    "not have the correct authorization");
+
+    registerMessage(MSGID_DSCFG_ERROR_MODIFY_CE,
+                    "The %s could not be modified due to a " +
+                    "communications problem: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_MODIFY_CME,
+                    "The %s could not be modified because another " +
+                    "client is currently making conflicting configuration " +
+                    "changes");
+
+    registerMessage(MSGID_DSCFG_ERROR_MODIFY_ORE,
+                    "The server prevented the %s from being modified " +
+                    "because of the following reason: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_GET_CHILD_DDE,
+                    "The %s could not be retrieved because its type could " +
+                    "not be determined. This is probably due to the %s " +
+                    "having an invalid LDAP entry. Check that the %s " +
+                    "object classes are correct");
+
+    registerMessage(MSGID_DSCFG_ERROR_GET_CHILD_MODE,
+                    "The %s could not be retrieved because of the " +
+                    "reasons listed below:");
+
+    registerMessage(MSGID_DSCFG_ERROR_GET_CHILD_MONFE,
+                    "The %s does not exist");
+
+    registerMessage(MSGID_DSCFG_ERROR_GET_CHILD_AUTHZ,
+                    "The %s could not be accessed because you do " +
+                    "not have the correct authorization");
+
+    registerMessage(MSGID_DSCFG_ERROR_GET_CHILD_CE,
+                    "The %s could not be accessed due to a " +
+                    "communications problem: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_GET_CHILD_CME,
+                    "The %s could not be accessed because another " +
+                    "client is currently making conflicting configuration " +
+                    "changes");
+
+    registerMessage(MSGID_DSCFG_ERROR_GET_PARENT_DDE,
+                    "The parent %s could not be retrieved because its " +
+                    "type could not be determined. This is probably due " +
+                    "to the %s having an invalid LDAP entry. Check that " +
+                    "the %s has the correct object classes");
+
+    registerMessage(MSGID_DSCFG_ERROR_GET_PARENT_MODE,
+                    "The parent %s could not be retrieved because of the " +
+                    "reasons listed below:");
+
+    registerMessage(MSGID_DSCFG_ERROR_GET_PARENT_MONFE,
+                    "The parent %s does not exist");
+
+    registerMessage(MSGID_DSCFG_ERROR_GET_PARENT_AUTHZ,
+                    "The parent %s could not be retrieved because you do " +
+                    "not have the correct authorization");
+
+    registerMessage(MSGID_DSCFG_ERROR_GET_PARENT_CE,
+                    "The parent %s could not be retrieved due to a " +
+                    "communications problem: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_GET_PARENT_CME,
+                    "The parent %s could not be retrieved because another " +
+                    "client is currently making conflicting configuration " +
+                    "changes");
+
+    registerMessage(MSGID_DSCFG_ERROR_NO_SEPARATOR_IN_PROPERTY_VALUE,
+                    "The property argument \"%s\" does not contain a " +
+                    "name/value separator. The argument should have the " +
+                    "following syntax: property:value");
+
+    registerMessage(MSGID_DSCFG_ERROR_NO_NAME_IN_PROPERTY_VALUE,
+                    "The property argument \"%s\" does not contain a " +
+                    "property name. The argument should have the " +
+                    "following syntax: property:value");
+
+    registerMessage(MSGID_DSCFG_ERROR_NO_VALUE_IN_PROPERTY_VALUE,
+                    "The property argument \"%s\" does not contain a " +
+                    "property value. The argument should have the " +
+                    "following syntax: property:value");
+
+    registerMessage(MSGID_DSCFG_ERROR_NO_SEPARATOR_IN_PROPERTY_MOD,
+                    "The property modification \"%s\" does not contain a " +
+                    "name/value separator. The argument should have the " +
+                    "following syntax: property[+|-]:value");
+
+    registerMessage(MSGID_DSCFG_ERROR_NO_NAME_IN_PROPERTY_MOD,
+                    "The property modification \"%s\" does not contain a " +
+                    "property name. The argument should have the " +
+                    "following syntax: property[+|-]:value");
+
+    registerMessage(MSGID_DSCFG_ERROR_NO_VALUE_IN_PROPERTY_MOD,
+                    "The property modification \"%s\" does not contain a " +
+                    "property value. The argument should have the " +
+                    "following syntax: property[+|-]:value");
+
+    registerMessage(MSGID_DSCFG_ERROR_INCOMPATIBLE_PROPERTY_MOD,
+                    "The property modification \"%s\" is incompatible" +
+                    " with a previous modification to the same property");
+
+    registerMessage(MSGID_DSCFG_ERROR_SUB_TYPE_UNRECOGNIZED,
+                    "The sub-type \"%s\" is not a recognized type of %s. " +
+                    "It should be one of: %s");
+
+    registerMessage(MSGID_DSCFG_ERROR_TYPE_UNRECOGNIZED,
+                    "\"%s\" is not a recognized type of managed object");
+
+    registerMessage(MSGID_DSCFG_ERROR_WRONG_MANAGED_OBJECT_TYPE,
+                    "The %s could not be retrieved because it was the " +
+                    "wrong type of managed object: %s ");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE,
+                    "Display subcommands relating to %s");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_ALL,
+                    "Display all subcommands");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_SUMMARY,
+                    "Display summary usage information");
   }
 }
 
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java b/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
new file mode 100644
index 0000000..52af844
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
@@ -0,0 +1,513 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.ToolMessages.*;
+
+import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.DefaultBehaviorException;
+import org.opends.server.admin.IllegalPropertyValueException;
+import org.opends.server.admin.IllegalPropertyValueStringException;
+import org.opends.server.admin.ManagedObjectDefinition;
+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.MissingMandatoryPropertiesException;
+import org.opends.server.util.args.ArgumentException;
+
+
+
+/**
+ * A utility class for converting various admin exception types into
+ * argument exceptions.
+ */
+final class ArgumentExceptionFactory {
+
+  /**
+   * Creates an argument exception from a missing mandatory properties
+   * exception.
+   *
+   * @param e
+   *          The missing mandatory properties exception.
+   * @param d
+   *          The managed object definition.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException adaptMissingMandatoryPropertiesException(
+      MissingMandatoryPropertiesException e,
+      AbstractManagedObjectDefinition d) {
+    int msgID = MSGID_DSCFG_ERROR_CREATE_MMPE;
+    StringBuilder builder = new StringBuilder();
+    boolean isFirst = true;
+    for (PropertyIsMandatoryException pe : e.getCauses()) {
+      if (!isFirst) {
+        builder.append(", ");
+      }
+      builder.append(pe.getPropertyDefinition().getName());
+      isFirst = false;
+    }
+    String msg = getMessage(msgID, d.getUserFriendlyName(), builder.toString());
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception from a property exception.
+   *
+   * @param e
+   *          The property exception.
+   * @param d
+   *          The managed object definition.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException adaptPropertyException(PropertyException e,
+      AbstractManagedObjectDefinition d) {
+    if (e instanceof IllegalPropertyValueException) {
+      IllegalPropertyValueException pe = (IllegalPropertyValueException) e;
+      return adapt(d, pe);
+    } else if (e instanceof IllegalPropertyValueStringException) {
+      IllegalPropertyValueStringException pe =
+        (IllegalPropertyValueStringException) e;
+      return adapt(d, pe);
+    } else if (e instanceof PropertyIsMandatoryException) {
+      PropertyIsMandatoryException pe = (PropertyIsMandatoryException) e;
+      return adapt(d, pe);
+    } else if (e instanceof PropertyIsSingleValuedException) {
+      PropertyIsSingleValuedException pe = (PropertyIsSingleValuedException) e;
+      return adapt(d, pe);
+    } else if (e instanceof PropertyIsReadOnlyException) {
+      PropertyIsReadOnlyException pe = (PropertyIsReadOnlyException) e;
+      return adapt(d, pe);
+    } else if (e instanceof DefaultBehaviorException) {
+      DefaultBehaviorException pe = (DefaultBehaviorException) e;
+      return adapt(d, pe);
+    } else {
+      int msgID = MSGID_DSCFG_ERROR_PROPERTY_UNKNOWN_ERROR;
+      String message = getMessage(msgID, d.getUserFriendlyName(), e
+          .getPropertyDefinition().getName(), e.getMessage());
+      return new ArgumentException(msgID, message);
+    }
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a
+   * property modification argument is incompatible with a previous
+   * modification argument.
+   *
+   * @param arg
+   *          The incompatible argument.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException incompatiblePropertyModification(String arg) {
+    int msgID = MSGID_DSCFG_ERROR_INCOMPATIBLE_PROPERTY_MOD;
+    String msg = getMessage(msgID, arg);
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when the
+   * client has not specified a bind password.
+   *
+   * @param bindDN
+   *          The name of the user requiring a password.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException missingBindPassword(String bindDN) {
+    int msgID = MSGID_DSCFG_ERROR_NO_PASSWORD;
+    String msg = getMessage(msgID, bindDN);
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a
+   * property value argument is invalid because it does not a property
+   * name.
+   *
+   * @param arg
+   *          The argument having the missing property name.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException missingNameInPropertyArgument(String arg) {
+    int msgID = MSGID_DSCFG_ERROR_NO_NAME_IN_PROPERTY_VALUE;
+    String msg = getMessage(msgID, arg);
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a
+   * property modification argument is invalid because it does not a
+   * property name.
+   *
+   * @param arg
+   *          The argument having the missing property name.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException missingNameInPropertyModification(
+      String arg) {
+    int msgID = MSGID_DSCFG_ERROR_NO_NAME_IN_PROPERTY_MOD;
+    String msg = getMessage(msgID, arg);
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a
+   * property value argument is invalid because it does not contain a
+   * separator between the property name and its value.
+   *
+   * @param arg
+   *          The argument having a missing separator.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException missingSeparatorInPropertyArgument(
+      String arg) {
+    int msgID = MSGID_DSCFG_ERROR_NO_SEPARATOR_IN_PROPERTY_VALUE;
+    String msg = getMessage(msgID, arg);
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a
+   * property modification argument is invalid because it does not
+   * contain a separator between the property name and its value.
+   *
+   * @param arg
+   *          The argument having a missing separator.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException missingSeparatorInPropertyModification(
+      String arg) {
+    int msgID = MSGID_DSCFG_ERROR_NO_SEPARATOR_IN_PROPERTY_MOD;
+    String msg = getMessage(msgID, arg);
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a
+   * property value argument is invalid because it does not a property
+   * value.
+   *
+   * @param arg
+   *          The argument having the missing property value.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException missingValueInPropertyArgument(String arg) {
+    int msgID = MSGID_DSCFG_ERROR_NO_VALUE_IN_PROPERTY_VALUE;
+    String msg = getMessage(msgID, arg);
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a
+   * property modification argument is invalid because it does not a
+   * property value.
+   *
+   * @param arg
+   *          The argument having the missing property value.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException missingValueInPropertyModification(
+      String arg) {
+    int msgID = MSGID_DSCFG_ERROR_NO_NAME_IN_PROPERTY_MOD;
+    String msg = getMessage(msgID, arg);
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when the bind
+   * password could not be read from the standard input.
+   *
+   * @param cause
+   *          The reason why the bind password could not be read.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException unableToReadBindPassword(Exception cause) {
+    int msgID = MSGID_DSCFG_ERROR_CANNOT_READ_LDAP_BIND_PASSWORD;
+    String message = getMessage(msgID, cause.getMessage());
+    return new ArgumentException(msgID, message, cause);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when the bind
+   * password could not be read from the standard input because the
+   * application is non-interactive.
+   *
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException unableToReadBindPasswordInteractively() {
+    int msgID = MSGID_DSCFG_ERROR_BIND_PASSWORD_NONINTERACTIVE;
+    String message = getMessage(msgID);
+    return new ArgumentException(msgID, message);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a
+   * property name is not recognized.
+   *
+   * @param d
+   *          The managed object definition.
+   * @param name
+   *          The unrecognized property name.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException unknownProperty(
+      AbstractManagedObjectDefinition d, String name) {
+    int msgID = MSGID_DSCFG_ERROR_PROPERTY_UNRECOGNIZED;
+    String message = getMessage(msgID, name, d.getUserFriendlyPluralName());
+    return new ArgumentException(msgID, message);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a
+   * sub-type argument in a create-xxx sub-command is not recognized.
+   *
+   * @param r
+   *          The relation definition.
+   * @param typeName
+   *          The unrecognized property sub-type.
+   * @param typeUsage
+   *          A usage string describing the allowed sub-types.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException unknownSubType(RelationDefinition r,
+      String typeName, String typeUsage) {
+    int msgID = MSGID_DSCFG_ERROR_SUB_TYPE_UNRECOGNIZED;
+    String msg = getMessage(msgID, typeName, r.getUserFriendlyName(),
+        typeUsage);
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a managed
+   * object type argument is not recognized.
+   *
+   * @param typeName
+   *          The unrecognized property sub-type.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException unknownType(String typeName) {
+    int msgID = MSGID_DSCFG_ERROR_TYPE_UNRECOGNIZED;
+    String msg = getMessage(msgID, typeName);
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a managed
+   * object is retrieved but does not have the correct type
+   * appropriate for the associated sub-command.
+   *
+   * @param r
+   *          The relation definition.
+   * @param d
+   *          The definition of the managed object that was retrieved.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException wrongManagedObjectType(RelationDefinition r,
+      ManagedObjectDefinition d) {
+    int msgID = MSGID_DSCFG_ERROR_TYPE_UNRECOGNIZED;
+    String msg = getMessage(msgID, r.getUserFriendlyName(), d
+        .getUserFriendlyName());
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception from a default behavior exception.
+   *
+   * @param d
+   *          The managed object definition.
+   * @param e
+   *          The default behavior exception.
+   * @return Returns an argument exception.
+   */
+  private static ArgumentException adapt(AbstractManagedObjectDefinition d,
+      DefaultBehaviorException e) {
+    int msgID = MSGID_DSCFG_ERROR_PROPERTY_DEFAULT_BEHAVIOR;
+    String message = getMessage(msgID, d.getUserFriendlyName(), e
+        .getPropertyDefinition().getName(), e.getMessage());
+    return new ArgumentException(msgID, message);
+  }
+
+
+
+  /**
+   * Creates an argument exception from an illegal property value
+   * exception.
+   *
+   * @param d
+   *          The managed object definition.
+   * @param e
+   *          The illegal property value exception.
+   * @return Returns an argument exception.
+   */
+  private static ArgumentException adapt(AbstractManagedObjectDefinition d,
+      IllegalPropertyValueException e) {
+    PropertyDefinitionUsageBuilder b = new PropertyDefinitionUsageBuilder(true);
+    String syntax = b.getUsage(e.getPropertyDefinition());
+
+    if (syntax.length() > 20) {
+      // syntax =
+      // getMessage(MSGID_DSCFG_DESCRIPTION_PROPERTY_SYNTAX_HELP);
+    }
+
+    int msgID = MSGID_DSCFG_ERROR_PROPERTY_INVALID_VALUE;
+    String message = getMessage(msgID, String.valueOf(e.getIllegalValue()), d
+        .getUserFriendlyName(), e.getPropertyDefinition().getName(), syntax);
+    return new ArgumentException(msgID, message);
+  }
+
+
+
+  /**
+   * Creates an argument exception from an illegal property string
+   * value exception.
+   *
+   * @param d
+   *          The managed object definition.
+   * @param e
+   *          The illegal property string value exception.
+   * @return Returns an argument exception.
+   */
+  private static ArgumentException adapt(AbstractManagedObjectDefinition d,
+      IllegalPropertyValueStringException e) {
+    PropertyDefinitionUsageBuilder b = new PropertyDefinitionUsageBuilder(true);
+    String syntax = b.getUsage(e.getPropertyDefinition());
+
+    if (syntax.length() > 20) {
+      // syntax =
+      // getMessage(MSGID_DSCFG_DESCRIPTION_PROPERTY_SYNTAX_HELP);
+    }
+
+    int msgID = MSGID_DSCFG_ERROR_PROPERTY_INVALID_VALUE;
+    String message = getMessage(msgID, String
+        .valueOf(e.getIllegalValueString()), d.getUserFriendlyName(), e
+        .getPropertyDefinition().getName(), syntax);
+    return new ArgumentException(msgID, message);
+  }
+
+
+
+  /**
+   * Creates an argument exception from a property is mandatory
+   * exception.
+   *
+   * @param d
+   *          The managed object definition.
+   * @param e
+   *          The property is mandatory exception.
+   * @return Returns an argument exception.
+   */
+  private static ArgumentException adapt(AbstractManagedObjectDefinition d,
+      PropertyIsMandatoryException e) {
+    int msgID = MSGID_DSCFG_ERROR_PROPERTY_MANDATORY;
+    String message = getMessage(msgID, d.getUserFriendlyName(), e
+        .getPropertyDefinition().getName());
+    return new ArgumentException(msgID, message);
+  }
+
+
+
+  /**
+   * Creates an argument exception from a property is read-only
+   * exception.
+   *
+   * @param d
+   *          The managed object definition.
+   * @param e
+   *          The property is read-only exception.
+   * @return Returns an argument exception.
+   */
+  private static ArgumentException adapt(AbstractManagedObjectDefinition d,
+      PropertyIsReadOnlyException e) {
+    int msgID = MSGID_DSCFG_ERROR_PROPERTY_READ_ONLY;
+    String message = getMessage(msgID, d.getUserFriendlyName(), e
+        .getPropertyDefinition().getName());
+    return new ArgumentException(msgID, message);
+  }
+
+
+
+  /**
+   * Creates an argument exception from a property is single-valued
+   * exception.
+   *
+   * @param d
+   *          The managed object definition.
+   * @param e
+   *          The property is single-valued exception.
+   * @return Returns an argument exception.
+   */
+  private static ArgumentException adapt(AbstractManagedObjectDefinition d,
+      PropertyIsSingleValuedException e) {
+    int msgID = MSGID_DSCFG_ERROR_PROPERTY_SINGLE_VALUED;
+    String message = getMessage(msgID, d.getUserFriendlyName(), e
+        .getPropertyDefinition().getName());
+    return new ArgumentException(msgID, message);
+  }
+
+
+
+  // Prevent instantiation.
+  private ArgumentExceptionFactory() {
+    // No implementation required.
+  }
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/CLIProfile.java b/opends/src/server/org/opends/server/tools/dsconfig/CLIProfile.java
new file mode 100644
index 0000000..0140c49
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/CLIProfile.java
@@ -0,0 +1,105 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectDefinitionResource;
+import org.opends.server.admin.RelationDefinition;
+
+
+
+/**
+ * This class is used to access CLI profile annotations.
+ */
+public class CLIProfile {
+
+  // The singleton instance.
+  private static final CLIProfile INSTANCE = new CLIProfile();
+
+
+
+  /**
+   * Get the CLI profile instance.
+   *
+   * @return Returns the CLI profile instance.
+   */
+  public static CLIProfile getInstance() {
+    return INSTANCE;
+  }
+
+  // The CLI profile property table.
+  private final ManagedObjectDefinitionResource resource;
+
+
+
+  // Private constructor.
+  private CLIProfile() {
+    this.resource = ManagedObjectDefinitionResource.createForProfile("cli");
+  }
+
+
+
+  /**
+   * Gets the default set of properties which should be displayed in a
+   * list-xxx operation.
+   *
+   * @param r
+   *          The relation definition.
+   * @return Returns the default set of properties which should be
+   *         displayed in a list-xxx operation.
+   */
+  public Set<String> getDefaultListPropertyNames(RelationDefinition<?, ?> r) {
+    String s = resource.getString(r.getParentDefinition(), "relation."
+        + r.getName() + ".list-properties");
+    return new LinkedHashSet<String>(Arrays.asList(s.split(",")));
+  }
+
+
+
+  /**
+   * Gets the command line operand name which should be used to
+   * identify the names of managed objects associated with an
+   * instantiable relation.
+   *
+   * @param r
+   *          The instantiable relation definition.
+   * @return Returns the command line operand name which should be
+   *         used to identify the names of managed objects associated
+   *         with an instantiable relation.
+   */
+  public String getOperandName(InstantiableRelationDefinition<?, ?> r) {
+    return resource.getString(r.getParentDefinition(), "relation."
+        + r.getName() + ".operand-name");
+  }
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
new file mode 100644
index 0000000..4f77f99
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
@@ -0,0 +1,560 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.ToolMessages.*;
+
+import java.io.PrintStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.ConfigurationClient;
+import org.opends.server.admin.DefaultBehaviorException;
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.IllegalPropertyValueStringException;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectAlreadyExistsException;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyException;
+import org.opends.server.admin.PropertyIsSingleValuedException;
+import org.opends.server.admin.PropertyOption;
+import org.opends.server.admin.PropertyProvider;
+import org.opends.server.admin.RelationDefinition;
+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.ManagedObject;
+import org.opends.server.admin.client.ManagedObjectDecodingException;
+import org.opends.server.admin.client.ManagementContext;
+import org.opends.server.admin.client.MissingMandatoryPropertiesException;
+import org.opends.server.admin.client.OperationRejectedException;
+import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.opends.server.tools.ClientException;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.StringArgument;
+import org.opends.server.util.args.SubCommand;
+import org.opends.server.util.args.SubCommandArgumentParser;
+
+
+
+/**
+ * A sub-command handler which is used to create new managed objects.
+ * <p>
+ * This sub-command implements the various create-xxx sub-commands.
+ *
+ * @param <C>
+ *          The type of managed object which can be created.
+ */
+final class CreateSubCommandHandler<C extends ConfigurationClient> extends
+    SubCommandHandler {
+
+  /**
+   * A property provider which uses the command-line arguments to
+   * provide initial property values.
+   */
+  private static class MyPropertyProvider implements PropertyProvider {
+
+    // Decoded set of properties.
+    private final Map<PropertyDefinition, Collection> properties =
+      new HashMap<PropertyDefinition, Collection>();
+
+
+
+    /**
+     * Create a new property provider using the provided set of
+     * property value arguments.
+     *
+     * @param d
+     *          The managed object definition.
+     * @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 {
+      for (String s : args) {
+        // Parse the property "property:value".
+        int sep = s.indexOf(':');
+
+        if (sep < 0) {
+          throw ArgumentExceptionFactory.missingSeparatorInPropertyArgument(s);
+        }
+
+        if (sep == 0) {
+          throw ArgumentExceptionFactory.missingNameInPropertyArgument(s);
+        }
+
+        String propertyName = s.substring(0, sep);
+        String value = s.substring(sep + 1, s.length());
+        if (value.length() == 0) {
+          throw ArgumentExceptionFactory.missingValueInPropertyArgument(s);
+        }
+
+        // Check the property definition.
+        PropertyDefinition<?> pd;
+        try {
+          pd = d.getPropertyDefinition(propertyName);
+        } catch (IllegalArgumentException e) {
+          throw ArgumentExceptionFactory.unknownProperty(d, propertyName);
+        }
+
+        // Add the value.
+        addPropertyValue(d, pd, value);
+      }
+    }
+
+
+
+    /**
+     * Get the set of parsed property definitions that have values
+     * specified.
+     *
+     * @return Returns the set of parsed property definitions that
+     *         have values specified.
+     */
+    public Set<PropertyDefinition> getProperties() {
+      return properties.keySet();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    public <T> Collection<T> getPropertyValues(PropertyDefinition<T> d)
+        throws IllegalArgumentException {
+      Collection<T> values = properties.get(d);
+      if (values == null) {
+        return Collections.emptySet();
+      } else {
+        return values;
+      }
+    }
+
+
+
+    // Add a single property value.
+    @SuppressWarnings("unchecked")
+    private <T> void addPropertyValue(ManagedObjectDefinition<?, ?> d,
+        PropertyDefinition<T> pd, String s) throws ArgumentException {
+      T value;
+      try {
+        value = pd.decodeValue(s);
+      } catch (IllegalPropertyValueStringException e) {
+        throw ArgumentExceptionFactory.adaptPropertyException(e, d);
+      }
+
+      Collection<T> values = properties.get(pd);
+      if (values == null) {
+        values = new LinkedList<T>();
+      }
+      values.add(value);
+
+      if (values.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) {
+        PropertyException e = new PropertyIsSingleValuedException(pd);
+        throw ArgumentExceptionFactory.adaptPropertyException(e, d);
+      }
+
+      properties.put(pd, values);
+    }
+  }
+
+  /**
+   * The value for the -t argument which will be used for the most
+   * generic managed object when it is instantiable.
+   */
+  private static final String GENERIC_TYPE = "generic";
+
+  /**
+   * The value for the long option set.
+   */
+  private static final String OPTION_DSCFG_LONG_SET = "set";
+
+  /**
+   * The value for the long option type.
+   */
+  private static final String OPTION_DSCFG_LONG_TYPE = "type";
+
+  /**
+   * The value for the short option property.
+   */
+  private static final Character OPTION_DSCFG_SHORT_SET = null;
+
+  /**
+   * The value for the short option type.
+   */
+  private static final Character OPTION_DSCFG_SHORT_TYPE = 't';
+
+
+
+  /**
+   * Creates a new create-xxx sub-command for an instantiable
+   * relation.
+   *
+   * @param <C>
+   *          The type of managed object which can be created.
+   * @param parser
+   *          The sub-command argument parser.
+   * @param p
+   *          The parent managed object path.
+   * @param r
+   *          The instantiable relation.
+   * @return Returns the new create-xxx sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  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"));
+  }
+
+
+
+  /**
+   * Creates a new create-xxx sub-command for an optional relation.
+   *
+   * @param <C>
+   *          The type of managed object which can be created.
+   * @param parser
+   *          The sub-command argument parser.
+   * @param p
+   *          The parent managed object path.
+   * @param r
+   *          The optional relation.
+   * @return Returns the new create-xxx sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  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));
+  }
+
+  // The sub-commands naming arguments.
+  private final List<StringArgument> namingArgs;
+
+  // The path of the parent managed object.
+  private final ManagedObjectPath<?, ?> path;
+
+  // The argument which should be used to specify zero or more
+  // property values.
+  private final StringArgument propertySetArgument;
+
+  // The relation which should be used for creating children.
+  private final RelationDefinition<C, ?> relation;
+
+  // The sub-command associated with this handler.
+  private final SubCommand subCommand;
+
+  // The argument which should be used to specify the type of managed
+  // object to be created.
+  private final StringArgument typeArgument;
+
+  // The set of instantiable managed object definitions and their
+  // associated type option value.
+  private final SortedMap<String,
+    ManagedObjectDefinition<? extends C, ?>> types;
+
+  // The syntax of the type argument.
+  private final String typeUsage;
+
+
+
+  // Common constructor.
+  private CreateSubCommandHandler(SubCommandArgumentParser parser,
+      ManagedObjectPath<?, ?> p, RelationDefinition<C, ?> r,
+      ManagedObjectPath<?, ?> c) throws ArgumentException {
+    this.path = p;
+    this.relation = r;
+
+    // Create the sub-command.
+    String name = "create-" + r.getName();
+    int descriptionID = MSGID_DSCFG_DESCRIPTION_SUBCMD_CREATE;
+    this.subCommand = new SubCommand(parser, name, false, 0, 0, null,
+        descriptionID, r.getChildDefinition().getUserFriendlyPluralName());
+
+    // Create the -t argument which is used to specify the type of
+    // managed object to be created.
+    this.types = getSubTypes(r.getChildDefinition());
+
+    // Create the naming arguments.
+    this.namingArgs = createNamingArgs(subCommand, c);
+
+    // Create the --property argument which is used to specify
+    // property values.
+    this.propertySetArgument = new StringArgument(OPTION_DSCFG_LONG_SET,
+        OPTION_DSCFG_SHORT_SET, OPTION_DSCFG_LONG_SET, false, true,
+        true, "{PROP:VALUE}", null, null, MSGID_DSCFG_DESCRIPTION_PROP_VAL);
+    this.subCommand.addArgument(this.propertySetArgument);
+
+    // Build the -t option usage.
+    StringBuilder builder = new StringBuilder();
+    boolean isFirst = true;
+    for (String s : types.keySet()) {
+      if (!isFirst) {
+        builder.append(" | ");
+      }
+      builder.append(s);
+      isFirst = false;
+    }
+    this.typeUsage = builder.toString();
+
+    if (!types.containsKey(GENERIC_TYPE)) {
+      // The option is mandatory.
+      this.typeArgument = new StringArgument("type", OPTION_DSCFG_SHORT_TYPE,
+          OPTION_DSCFG_LONG_TYPE, true, false, true, "{TYPE}", null, null,
+          MSGID_DSCFG_DESCRIPTION_TYPE, r.getChildDefinition()
+              .getUserFriendlyName(), typeUsage);
+    } else {
+      // The option has a sensible default "generic".
+      this.typeArgument = new StringArgument("type", OPTION_DSCFG_SHORT_TYPE,
+          OPTION_DSCFG_LONG_TYPE, false, false, true, "{TYPE}", GENERIC_TYPE,
+          null, MSGID_DSCFG_DESCRIPTION_TYPE_DEFAULT, r.getChildDefinition()
+              .getUserFriendlyName(), GENERIC_TYPE, typeUsage);
+    }
+    this.subCommand.addArgument(this.typeArgument);
+
+    // Register the tags associated with the child managed objects.
+    addTags(relation.getChildDefinition().getAllTags());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public SubCommand getSubCommand() {
+    return subCommand;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int run(DSConfig app, PrintStream out, PrintStream err)
+      throws ArgumentException, ClientException {
+    // Determine the type of managed object to be created.
+    String typeName = typeArgument.getValue();
+    ManagedObjectDefinition<? extends C, ?> d = types.get(typeName);
+    if (d == null) {
+      throw ArgumentExceptionFactory.unknownSubType(relation, typeName,
+          typeUsage);
+    }
+
+    // Get the naming argument values.
+    List<String> names = getNamingArgValues(namingArgs);
+
+    // Encode the provided properties.
+    List<String> propertyArgs = propertySetArgument.getValues();
+    MyPropertyProvider provider = new MyPropertyProvider(d, propertyArgs);
+
+    // Add the child managed object.
+    ManagementContext context = app.getManagementContext();
+    ManagedObject<?> parent;
+    try {
+      parent = getManagedObject(context, path, names.subList(0,
+          names.size() - 1));
+    } catch (AuthorizationException e) {
+      int msgID = MSGID_DSCFG_ERROR_CREATE_AUTHZ;
+      String msg = getMessage(msgID, d.getUserFriendlyName());
+      throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+          msgID, msg);
+    } catch (DefinitionDecodingException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_PARENT_DDE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn, ufn, ufn);
+      throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+    } catch (ManagedObjectDecodingException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_PARENT_MODE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+    } catch (CommunicationException e) {
+      int msgID = MSGID_DSCFG_ERROR_CREATE_CE;
+      String msg = getMessage(msgID, d.getUserFriendlyName(), e.getMessage());
+      throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msgID,
+          msg);
+    } catch (ConcurrentModificationException e) {
+      int msgID = MSGID_DSCFG_ERROR_CREATE_CME;
+      String msg = getMessage(msgID, d.getUserFriendlyName());
+      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
+          msgID, msg);
+    } catch (ManagedObjectNotFoundException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_PARENT_MONFE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msgID, msg);
+    }
+
+    try {
+      ManagedObject<? extends C> child;
+      List<DefaultBehaviorException> exceptions =
+        new LinkedList<DefaultBehaviorException>();
+      if (relation instanceof InstantiableRelationDefinition) {
+        InstantiableRelationDefinition<C, ?> irelation =
+          (InstantiableRelationDefinition<C, ?>) relation;
+        String name = names.get(names.size() - 1);
+        child = parent.createChild(irelation, d, name, exceptions);
+      } else {
+        OptionalRelationDefinition<C, ?> orelation =
+          (OptionalRelationDefinition<C, ?>) relation;
+        child = parent.createChild(orelation, d, exceptions);
+      }
+
+      // FIXME: display any default behavior exceptions in verbose
+      // mode.
+
+      // Set any properties specified on the command line.
+      for (PropertyDefinition<?> pd : provider.getProperties()) {
+        setProperty(child, provider, pd);
+      }
+
+      // Confirm commit.
+      String prompt = String.format(Messages.getString("create.confirm"), d
+          .getUserFriendlyName());
+      if (!app.confirmAction(prompt)) {
+        // Output failure message.
+        String msg = String.format(Messages.getString("create.failed"), d
+            .getUserFriendlyName());
+        app.displayVerboseMessage(msg);
+        return 1;
+      }
+
+      // Add the managed object.
+      child.commit();
+
+      // Output success message.
+      String msg = String.format(Messages.getString("create.done"), d
+          .getUserFriendlyName());
+      app.displayVerboseMessage(msg);
+    } catch (MissingMandatoryPropertiesException e) {
+      throw ArgumentExceptionFactory.adaptMissingMandatoryPropertiesException(
+          e, d);
+    } catch (AuthorizationException e) {
+      int msgID = MSGID_DSCFG_ERROR_CREATE_AUTHZ;
+      String msg = getMessage(msgID, d.getUserFriendlyName());
+      throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+          msgID, msg);
+    } catch (ManagedObjectAlreadyExistsException e) {
+      int msgID = MSGID_DSCFG_ERROR_CREATE_MOAEE;
+      String msg = getMessage(msgID, d.getUserFriendlyName());
+      throw new ClientException(LDAPResultCode.ENTRY_ALREADY_EXISTS,
+          msgID, msg);
+    } catch (ConcurrentModificationException e) {
+      int msgID = MSGID_DSCFG_ERROR_CREATE_CME;
+      String msg = getMessage(msgID, d.getUserFriendlyName());
+      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
+          msgID, msg);
+    } catch (OperationRejectedException e) {
+      int msgID = MSGID_DSCFG_ERROR_CREATE_ORE;
+      String msg = getMessage(msgID, d.getUserFriendlyName(), e.getMessage());
+      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
+          msgID, msg);
+    } catch (CommunicationException e) {
+      int msgID = MSGID_DSCFG_ERROR_CREATE_CE;
+      String msg = getMessage(msgID, d.getUserFriendlyName(), e.getMessage());
+      throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msgID,
+          msg);
+    }
+
+    return 0;
+  }
+
+
+
+  // Generate the type name - definition mapping table.
+  @SuppressWarnings("unchecked")
+  private SortedMap<String, ManagedObjectDefinition<? extends C, ?>>
+      getSubTypes(AbstractManagedObjectDefinition<C, ?> d) {
+    SortedMap<String, ManagedObjectDefinition<? extends C, ?>> map;
+    map = new TreeMap<String, ManagedObjectDefinition<? extends C, ?>>();
+
+    // If the top-level definition is instantiable, we use the value
+    // "generic".
+    if (d instanceof ManagedObjectDefinition) {
+      ManagedObjectDefinition<? extends C, ?> mod =
+        (ManagedObjectDefinition<? extends C, ?>) d;
+      map.put(GENERIC_TYPE, mod);
+    }
+
+    // Process its sub-definitions.
+    String suffix = "-" + d.getName();
+    for (AbstractManagedObjectDefinition<? extends C, ?> c :
+        d.getAllChildren()) {
+      if (c instanceof ManagedObjectDefinition) {
+        ManagedObjectDefinition<? extends C, ?> mod =
+          (ManagedObjectDefinition<? extends C, ?>) c;
+
+        // For the type name we shorten it, if possible, by stripping
+        // off the trailing part of the name which matches the
+        // base-type.
+        String name = mod.getName();
+        if (name.endsWith(suffix)) {
+          name = name.substring(0, name.length() - suffix.length());
+        }
+
+        map.put(name, mod);
+      }
+    }
+
+    return map;
+  }
+
+
+
+  // Set a property's initial values.
+  private <T> void setProperty(ManagedObject<?> mo,
+      MyPropertyProvider provider, PropertyDefinition<T> pd) {
+    Collection<T> values = provider.getPropertyValues(pd);
+
+    // This cannot fail because the property values have already been
+    // validated.
+    mo.setPropertyValues(pd, values);
+  }
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java b/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java
new file mode 100644
index 0000000..f9e59e1
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java
@@ -0,0 +1,666 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.ToolMessages.*;
+import static org.opends.server.tools.ToolConstants.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.AttributeTypePropertyDefinition;
+import org.opends.server.admin.ClassLoaderProvider;
+import org.opends.server.admin.ClassPropertyDefinition;
+import org.opends.server.admin.PropertyException;
+import org.opends.server.admin.Tag;
+import org.opends.server.admin.client.ManagedObjectDecodingException;
+import org.opends.server.admin.client.ManagementContext;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.tools.ClientException;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.InitializationException;
+import org.opends.server.types.NullOutputStream;
+import org.opends.server.util.PasswordReader;
+import org.opends.server.util.StaticUtils;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.BooleanArgument;
+import org.opends.server.util.args.SubCommand;
+import org.opends.server.util.args.SubCommandArgumentParser;
+
+
+
+/**
+ * This class provides a command-line tool which enables
+ * administrators to configure the Directory Server.
+ */
+public final class DSConfig {
+
+  /**
+   * The tracer object for the debug logger.
+   */
+  private static final DebugTracer TRACER = getTracer();
+
+
+
+  /**
+   * Provides the command-line arguments to the main application for
+   * processing.
+   *
+   * @param args
+   *          The set of command-line arguments provided to this
+   *          program.
+   */
+  public static void main(String[] args) {
+    DSConfig app = new DSConfig(System.in, System.out, System.err,
+        new LDAPManagementContextFactory());
+    // Only initialize the client environment when run as a standalone
+    // application.
+    try {
+      app.initializeClientEnvironment();
+    } catch (InitializationException e) {
+      // TODO: is this ok as an error message?
+      System.err.println(wrapText(e.getMessage(), MAX_LINE_WIDTH));
+      System.exit(1);
+    }
+
+    // Run the application.
+    int exitCode = app.run(args);
+    if (exitCode != 0) {
+      System.exit(exitCode);
+    }
+  }
+
+  // Flag indicating whether or not the application environment has
+  // already been initialized.
+  private boolean environmentInitialized = false;
+
+  // The error stream which this application should use.
+  private final PrintStream err;
+
+  // The factory which the application should use to retrieve its
+  // management context.
+  private final ManagementContextFactory factory;
+
+  // Flag indicating whether or not the global arguments have
+  // already been initialized.
+  private boolean globalArgumentsInitialized = false;
+
+  // Mapping of sub-commands to their implementations;
+  private final Map<SubCommand, SubCommandHandler> handlers =
+    new HashMap<SubCommand, SubCommandHandler>();
+
+  // The input stream reader which this application should use.
+  private final BufferedReader in;
+
+  // The argument which should be used to request interactive
+  // behavior.
+  private BooleanArgument interactiveArgument;
+
+  // The output stream which this application should use.
+  private final PrintStream out;
+
+  // The command-line argument parser.
+  private final SubCommandArgumentParser parser;
+
+  // The argument which should be used to request quiet output.
+  private BooleanArgument quietArgument;
+
+  // The argument which should be used to request script-friendly
+  // output.
+  private BooleanArgument scriptFriendlyArgument;
+
+  // The argument which should be used to request usage information.
+  private BooleanArgument showUsageArgument;
+
+  // Flag indicating whether or not the sub-commands have
+  // already been initialized.
+  private boolean subCommandsInitialized = false;
+
+  // The argument which should be used to request verbose output.
+  private BooleanArgument verboseArgument;
+
+
+
+  /**
+   * Creates a new dsconfig application instance.
+   *
+   * @param in
+   *          The application input stream.
+   * @param out
+   *          The application output stream.
+   * @param err
+   *          The application error stream.
+   * @param factory
+   *          The factory which this application instance should use
+   *          for obtaining management contexts.
+   */
+  public DSConfig(InputStream in, OutputStream out, OutputStream err,
+      ManagementContextFactory factory) {
+    this.parser = new SubCommandArgumentParser(this.getClass().getName(),
+        getMessage(MSGID_CONFIGDS_TOOL_DESCRIPTION), false);
+
+    if (in != null) {
+      this.in = new BufferedReader(new InputStreamReader(in));
+    } else {
+      this.in = new BufferedReader(new Reader() {
+
+        @Override
+        public void close() throws IOException {
+          // Do nothing.
+        }
+
+
+
+        @Override
+        public int read(char[] cbuf, int off, int len) throws IOException {
+          return -1;
+        }
+
+      });
+    }
+
+    if (out != null) {
+      this.out = new PrintStream(out);
+    } else {
+      this.out = NullOutputStream.printStream();
+    }
+
+    if (err != null) {
+      this.err = new PrintStream(err);
+    } else {
+      this.err = NullOutputStream.printStream();
+    }
+
+    this.factory = factory;
+  }
+
+
+
+  /**
+   * Interactively confirms whether a user wishes to perform an
+   * action. If the application is non-interactive, then the action is
+   * granted by default.
+   *
+   * @param prompt
+   *          The prompt describing the action.
+   * @return Returns <code>true</code> if the user wishes the action
+   *         to be performed, or <code>false</code> if they refused,
+   *         or if an exception occurred.
+   */
+  public boolean confirmAction(String prompt) {
+    if (!isInteractive()) {
+      return true;
+    }
+
+    String yes = Messages.getString("general.yes");
+    String no = Messages.getString("general.no");
+    String errMsg = Messages.getString("general.confirm.error");
+    String error = String.format(errMsg, yes, no);
+    prompt = prompt + String.format(" (%s / %s): ", yes, no);
+
+    while (true) {
+      String response;
+      try {
+        response = readLineOfInput(prompt);
+      } catch (Exception e) {
+        return false;
+      }
+
+      if (response == null) {
+        // End of input.
+        return false;
+      }
+
+      response = response.toLowerCase().trim();
+      if (response.length() == 0) {
+        // Empty input.
+        err.println(wrapText(error, MAX_LINE_WIDTH));
+      } else if (no.startsWith(response)) {
+        return false;
+      } else if (yes.startsWith(response)) {
+        return true;
+      } else {
+        // Try again...
+        err.println(wrapText(error, MAX_LINE_WIDTH));
+      }
+    }
+  }
+
+
+
+  /**
+   * Displays a message to the error stream.
+   *
+   * @param msg
+   *          The message.
+   */
+  public void displayMessage(String msg) {
+    err.println(wrapText(msg, MAX_LINE_WIDTH));
+  }
+
+
+
+  /**
+   * Displays a message to the error stream if verbose mode is
+   * enabled.
+   *
+   * @param msg
+   *          The verbose message.
+   */
+  public void displayVerboseMessage(String msg) {
+    if (isVerbose()) {
+      err.println(wrapText(msg, MAX_LINE_WIDTH));
+    }
+  }
+
+
+
+  /**
+   * Initializes core APIs for use when dsconfig will be run as a
+   * standalone application.
+   *
+   * @throws InitializationException
+   *           If the core APIs could not be initialized.
+   */
+  public void initializeClientEnvironment() throws InitializationException {
+    if (environmentInitialized == false) {
+      // TODO: do we need to do this?
+      DirectoryServer.bootstrapClient();
+
+      // Bootstrap definition classes.
+      ClassLoaderProvider.getInstance().enable();
+
+      // Switch off class name validation in client.
+      ClassPropertyDefinition.setAllowClassValidation(false);
+
+      // Switch off attribute type name validation in client.
+      AttributeTypePropertyDefinition.setCheckSchema(false);
+
+      environmentInitialized = true;
+    }
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested interactive
+   * behavior.
+   *
+   * @return Returns <code>true</code> if the user has requested
+   *         interactive behavior.
+   */
+  public boolean isInteractive() {
+    return interactiveArgument.isPresent();
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested quiet output.
+   *
+   * @return Returns <code>true</code> if the user has requested
+   *         quiet output.
+   */
+  public boolean isQuiet() {
+    return quietArgument.isPresent();
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested script-friendly
+   * output.
+   *
+   * @return Returns <code>true</code> if the user has requested
+   *         script-friendly output.
+   */
+  public boolean isScriptFriendly() {
+    return scriptFriendlyArgument.isPresent();
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested verbose output.
+   *
+   * @return Returns <code>true</code> if the user has requested
+   *         verbose output.
+   */
+  public boolean isVerbose() {
+    return verboseArgument.isPresent();
+  }
+
+
+
+  /**
+   * Interactively retrieves a line of input from the console.
+   *
+   * @param prompt
+   *          The prompt.
+   * @return Returns the line of input, or <code>null</code> if the
+   *         end of input has been reached.
+   * @throws Exception
+   *           If the line of input could not be retrieved for some
+   *           reason.
+   */
+  public String readLineOfInput(String prompt) throws Exception {
+    err.print(wrapText(prompt, MAX_LINE_WIDTH));
+    return in.readLine();
+  }
+
+
+
+  /**
+   * Interactively retrieves a password from the console.
+   *
+   * @param prompt
+   *          The password prompt.
+   * @return Returns the password.
+   * @throws Exception
+   *           If the password could not be retrieved for some reason.
+   */
+  public String readPassword(String prompt) throws Exception {
+    err.print(wrapText(prompt, MAX_LINE_WIDTH));
+    char[] pwChars = PasswordReader.readPassword();
+    return new String(pwChars);
+  }
+
+
+
+  /**
+   * Gets the management context which sub-commands should use in
+   * order to manage the directory server.
+   *
+   * @return Returns the management context which sub-commands should
+   *         use in order to manage the directory server.
+   * @throws ArgumentException
+   *           If a management context related argument could not be
+   *           parsed successfully.
+   * @throws ClientException
+   *           If the management context could not be created.
+   */
+  ManagementContext getManagementContext() throws ArgumentException,
+      ClientException {
+    return factory.getManagementContext(this);
+  }
+
+
+
+  /**
+   * Registers the global arguments with the argument parser.
+   *
+   * @throws ArgumentException
+   *           If a global argument could not be registered.
+   */
+  private void initializeGlobalArguments() throws ArgumentException {
+    if (globalArgumentsInitialized == false) {
+      verboseArgument = new BooleanArgument("verbose", 'v', "verbose",
+          MSGID_DESCRIPTION_VERBOSE);
+
+      quietArgument = new BooleanArgument("quiet", 'q', "quiet",
+          MSGID_DESCRIPTION_QUIET);
+
+      scriptFriendlyArgument = new BooleanArgument("script-friendly", 's',
+          "script-friendly", MSGID_DESCRIPTION_SCRIPT_FRIENDLY);
+
+      interactiveArgument = new BooleanArgument("interactive", 'i',
+          "interactive", MSGID_DESCRIPTION_INTERACTIVE);
+
+      showUsageArgument = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
+          OPTION_LONG_HELP, MSGID_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_SUMMARY);
+
+      // Register the global arguments.
+      parser.addGlobalArgument(showUsageArgument);
+      parser.setUsageArgument(showUsageArgument, out);
+      parser.addGlobalArgument(verboseArgument);
+      parser.addGlobalArgument(quietArgument);
+      parser.addGlobalArgument(scriptFriendlyArgument);
+      parser.addGlobalArgument(interactiveArgument);
+
+      // Register any global arguments required by the management
+      // context factory.
+      factory.registerGlobalArguments(parser);
+
+      globalArgumentsInitialized = true;
+    }
+  }
+
+
+
+  /**
+   * Registers the sub-commands with the argument parser. This method
+   * uses the administration framework introspection APIs to determine
+   * the overall structure of the command-line.
+   *
+   * @throws ArgumentException
+   *           If a sub-command could not be created.
+   */
+  private void initializeSubCommands() throws ArgumentException {
+    if (subCommandsInitialized == false) {
+      Comparator<SubCommand> c = new Comparator<SubCommand>() {
+
+        public int compare(SubCommand o1, SubCommand o2) {
+          return o1.getName().compareTo(o2.getName());
+        }
+      };
+
+      SubCommandBuilder builder = new SubCommandBuilder();
+      Map<Tag, SortedSet<SubCommand>> groups =
+        new TreeMap<Tag, SortedSet<SubCommand>>();
+      SortedSet<SubCommand> allSubCommands = new TreeSet<SubCommand>(c);
+      for (SubCommandHandler handler : builder.getSubCommandHandlers(parser)) {
+        SubCommand sc = handler.getSubCommand();
+
+        handlers.put(sc, handler);
+        allSubCommands.add(sc);
+
+        // Add the sub-command to its groups.
+        for (Tag tag : handler.getTags()) {
+          SortedSet<SubCommand> group = groups.get(tag);
+          if (group == null) {
+            group = new TreeSet<SubCommand>(c);
+            groups.put(tag, group);
+          }
+          group.add(sc);
+        }
+      }
+
+      // Register the usage arguments.
+      for (Map.Entry<Tag, SortedSet<SubCommand>> group : groups.entrySet()) {
+        Tag tag = group.getKey();
+        SortedSet<SubCommand> subCommands = group.getValue();
+
+        String option = OPTION_LONG_HELP + "-" + tag.getName();
+        String synopsis = tag.getSynopsis().toLowerCase();
+        BooleanArgument arg = new BooleanArgument(option, null, option,
+            MSGID_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE, synopsis);
+
+        parser.addGlobalArgument(arg);
+        parser.setUsageGroupArgument(arg, subCommands);
+      }
+
+      // Register the --help-all argument.
+      String option = OPTION_LONG_HELP + "-all";
+      BooleanArgument arg = new BooleanArgument(option, null, option,
+          MSGID_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_ALL);
+
+      parser.addGlobalArgument(arg);
+      parser.setUsageGroupArgument(arg, allSubCommands);
+
+      subCommandsInitialized = true;
+    }
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and makes the
+   * appropriate changes to the Directory Server configuration.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   * @return The exit code from the configuration processing. A
+   *         nonzero value indicates that there was some kind of
+   *         problem during the configuration processing.
+   */
+  private int run(String[] args) {
+    // Register global arguments and sub-commands.
+    try {
+      initializeGlobalArguments();
+      initializeSubCommands();
+    } catch (ArgumentException e) {
+      int msgID = MSGID_CANNOT_INITIALIZE_ARGS;
+      String message = getMessage(msgID, e.getMessage());
+      err.println(wrapText(message, MAX_LINE_WIDTH));
+      return 1;
+    }
+
+    // Parse the command-line arguments provided to this program.
+    try {
+      parser.parseArguments(args);
+    } catch (ArgumentException ae) {
+      int msgID = MSGID_ERROR_PARSING_ARGS;
+      String message = getMessage(msgID, ae.getMessage());
+      err.println(wrapText(message, MAX_LINE_WIDTH));
+      err.println();
+      err.println(parser.getHelpUsageReference());
+      return 1;
+    }
+
+    // If the usage/version argument was provided, then we don't need
+    // to do anything else.
+    if (parser.usageOrVersionDisplayed()) {
+      return 0;
+    }
+
+    // Make sure that we have a sub-command.
+    if (parser.getSubCommand() == null) {
+      int msgID = MSGID_ERROR_PARSING_ARGS;
+      String message = getMessage(msgID,
+          getMessage(MSGID_DSCFG_ERROR_MISSING_SUBCOMMAND));
+      err.println(wrapText(message, MAX_LINE_WIDTH));
+      err.println();
+      err.println(parser.getHelpUsageReference());
+      return 1;
+    }
+
+    if (quietArgument.isPresent() && verboseArgument.isPresent()) {
+      int msgID = MSGID_TOOL_CONFLICTING_ARGS;
+      String message = getMessage(msgID, quietArgument.getLongIdentifier(),
+          verboseArgument.getLongIdentifier());
+      err.println(wrapText(message, MAX_LINE_WIDTH));
+      err.println();
+      err.println(parser.getHelpUsageReference());
+      return 1;
+    }
+
+    if (quietArgument.isPresent() && interactiveArgument.isPresent()) {
+      int msgID = MSGID_TOOL_CONFLICTING_ARGS;
+      String message = getMessage(msgID, quietArgument.getLongIdentifier(),
+          interactiveArgument.getLongIdentifier());
+      err.println(wrapText(message, MAX_LINE_WIDTH));
+      err.println();
+      err.println(parser.getHelpUsageReference());
+      return 1;
+    }
+
+    if (scriptFriendlyArgument.isPresent() && verboseArgument.isPresent()) {
+      int msgID = MSGID_TOOL_CONFLICTING_ARGS;
+      String message = getMessage(msgID, scriptFriendlyArgument
+          .getLongIdentifier(), verboseArgument.getLongIdentifier());
+      err.println(wrapText(message, MAX_LINE_WIDTH));
+      err.println();
+      err.println(parser.getHelpUsageReference());
+      return 1;
+    }
+
+    // Make sure that management context's arguments are valid.
+    try {
+      factory.validateGlobalArguments();
+    } catch (ArgumentException e) {
+      err.println(wrapText(e.getMessage(), MAX_LINE_WIDTH));
+      return 1;
+    }
+
+    // Retrieve the sub-command implementation and run it.
+    SubCommandHandler handler = handlers.get(parser.getSubCommand());
+    try {
+      return handler.run(this, out, err);
+    } catch (ArgumentException e) {
+      err.println(wrapText(e.getMessage(), MAX_LINE_WIDTH));
+      return 1;
+    } catch (ClientException e) {
+      // If the client exception was caused by a decoding exception
+      // then we should display the causes.
+      err.println(wrapText(e.getMessage(), MAX_LINE_WIDTH));
+
+      Throwable cause = e.getCause();
+      if (cause instanceof ManagedObjectDecodingException) {
+        // FIXME: use a table.
+        ManagedObjectDecodingException de =
+          (ManagedObjectDecodingException) cause;
+
+        err.println();
+        for (PropertyException pe : de.getCauses()) {
+          AbstractManagedObjectDefinition<?, ?> d = de
+              .getPartialManagedObject().getManagedObjectDefinition();
+          ArgumentException ae = ArgumentExceptionFactory
+              .adaptPropertyException(pe, d);
+          err.println(wrapText(" * " + ae.getMessage(), MAX_LINE_WIDTH));
+        }
+        err.println();
+      }
+
+      return 1;
+    } catch (Exception e) {
+      if (debugEnabled()) {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+      err.println(wrapText(StaticUtils.stackTraceToString(e), MAX_LINE_WIDTH));
+      return 1;
+    }
+  }
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java
new file mode 100644
index 0000000..fd864be
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java
@@ -0,0 +1,260 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.ToolMessages.*;
+
+import java.io.PrintStream;
+import java.util.List;
+
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.RelationDefinition;
+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.ManagedObject;
+import org.opends.server.admin.client.ManagedObjectDecodingException;
+import org.opends.server.admin.client.ManagementContext;
+import org.opends.server.admin.client.OperationRejectedException;
+import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.opends.server.tools.ClientException;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.StringArgument;
+import org.opends.server.util.args.SubCommand;
+import org.opends.server.util.args.SubCommandArgumentParser;
+
+
+
+/**
+ * A sub-command handler which is used to delete existing managed
+ * objects.
+ * <p>
+ * This sub-command implements the various delete-xxx sub-commands.
+ */
+final class DeleteSubCommandHandler extends SubCommandHandler {
+
+  /**
+   * Creates a new delete-xxx sub-command for an instantiable
+   * relation.
+   *
+   * @param parser
+   *          The sub-command argument parser.
+   * @param p
+   *          The parent managed object path.
+   * @param r
+   *          The instantiable relation.
+   * @return Returns the new delete-xxx sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  public static DeleteSubCommandHandler create(SubCommandArgumentParser parser,
+      ManagedObjectPath<?, ?> p, InstantiableRelationDefinition<?, ?> r)
+      throws ArgumentException {
+    return new DeleteSubCommandHandler(parser, p, r, p.child(r, "DUMMY"));
+  }
+
+
+
+  /**
+   * Creates a new delete-xxx sub-command for an optional relation.
+   *
+   * @param parser
+   *          The sub-command argument parser.
+   * @param p
+   *          The parent managed object path.
+   * @param r
+   *          The optional relation.
+   * @return Returns the new delete-xxx sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  public static DeleteSubCommandHandler create(SubCommandArgumentParser parser,
+      ManagedObjectPath<?, ?> p, OptionalRelationDefinition<?, ?> r)
+      throws ArgumentException {
+    return new DeleteSubCommandHandler(parser, p, r, p.child(r));
+  }
+
+  // The sub-commands naming arguments.
+  private final List<StringArgument> namingArgs;
+
+  // The path of the managed object.
+  private final ManagedObjectPath<?, ?> path;
+
+  // The relation which references the managed
+  // object to be deleted.
+  private final RelationDefinition<?, ?> relation;
+
+  // The sub-command associated with this handler.
+  private final SubCommand subCommand;
+
+
+
+  // Private constructor.
+  private DeleteSubCommandHandler(SubCommandArgumentParser parser,
+      ManagedObjectPath<?, ?> p, RelationDefinition<?, ?> r,
+      ManagedObjectPath<?, ?> c) throws ArgumentException {
+    this.path = p;
+    this.relation = r;
+
+    // Create the sub-command.
+    String name = "delete-" + r.getName();
+    int descriptionID = MSGID_DSCFG_DESCRIPTION_SUBCMD_DELETE;
+    this.subCommand = new SubCommand(parser, name, false, 0, 0, null,
+        descriptionID, r.getChildDefinition().getUserFriendlyPluralName());
+
+    // Create the naming arguments.
+    this.namingArgs = createNamingArgs(subCommand, c);
+
+    // Register the tags associated with the child managed objects.
+    addTags(relation.getChildDefinition().getAllTags());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public SubCommand getSubCommand() {
+    return subCommand;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int run(DSConfig app, PrintStream out, PrintStream err)
+      throws ArgumentException, ClientException {
+    // Get the naming argument values.
+    List<String> names = getNamingArgValues(namingArgs);
+
+    // Delete the child managed object.
+    ManagementContext context = app.getManagementContext();
+    ManagedObject<?> parent;
+    try {
+      parent = getManagedObject(context, path, names.subList(0,
+          names.size() - 1));
+    } catch (AuthorizationException e) {
+      int msgID = MSGID_DSCFG_ERROR_DELETE_AUTHZ;
+      String msg = getMessage(msgID, relation.getUserFriendlyName());
+      throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+          msgID, msg);
+    } catch (DefinitionDecodingException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_PARENT_DDE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn, ufn, ufn);
+      throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+    } catch (ManagedObjectDecodingException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_PARENT_MODE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+    } catch (CommunicationException e) {
+      int msgID = MSGID_DSCFG_ERROR_DELETE_CE;
+      String msg = getMessage(msgID, relation.getUserFriendlyName(), e
+          .getMessage());
+      throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msgID,
+          msg);
+    } catch (ConcurrentModificationException e) {
+      int msgID = MSGID_DSCFG_ERROR_DELETE_CME;
+      String msg = getMessage(msgID, relation.getUserFriendlyName());
+      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID,
+          msg);
+    } catch (ManagedObjectNotFoundException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_PARENT_MONFE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msgID, msg);
+    }
+
+    try {
+      // Confirm deletion.
+      String prompt = String.format(Messages.getString("delete.confirm"),
+          relation.getUserFriendlyName());
+      if (!app.confirmAction(prompt)) {
+        // Output failure message.
+        String msg = String.format(Messages.getString("delete.failed"),
+            relation.getUserFriendlyName());
+        app.displayVerboseMessage(msg);
+        return 1;
+      }
+
+      if (relation instanceof InstantiableRelationDefinition) {
+        InstantiableRelationDefinition<?, ?> irelation =
+          (InstantiableRelationDefinition<?, ?>) relation;
+        parent.removeChild(irelation, names.get(names.size() - 1));
+      } else if (relation instanceof OptionalRelationDefinition) {
+        OptionalRelationDefinition<?, ?> orelation =
+          (OptionalRelationDefinition<?, ?>) relation;
+        parent.removeChild(orelation);
+      }
+
+      // Output success message.
+      String msg = String.format(Messages.getString("delete.done"),
+          relation.getUserFriendlyName());
+      app.displayVerboseMessage(msg);
+    } catch (AuthorizationException e) {
+      int msgID = MSGID_DSCFG_ERROR_DELETE_AUTHZ;
+      String msg = getMessage(msgID, relation.getUserFriendlyName());
+      throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+          msgID, msg);
+    } catch (OperationRejectedException e) {
+      int msgID = MSGID_DSCFG_ERROR_DELETE_ORE;
+      String msg = getMessage(msgID, relation.getUserFriendlyName(), e
+          .getMessage());
+      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID,
+          msg);
+    } catch (ManagedObjectNotFoundException e) {
+      int msgID = MSGID_DSCFG_ERROR_DELETE_MONFE;
+      String msg = getMessage(msgID, relation.getUserFriendlyName());
+      throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msgID, msg);
+    } catch (ConcurrentModificationException e) {
+      int msgID = MSGID_DSCFG_ERROR_DELETE_CME;
+      String msg = getMessage(msgID, relation.getUserFriendlyName());
+      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID,
+          msg);
+    } catch (CommunicationException e) {
+      int msgID = MSGID_DSCFG_ERROR_DELETE_CE;
+      String msg = getMessage(msgID, relation.getUserFriendlyName(), e
+          .getMessage());
+      throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msgID,
+          msg);
+    }
+
+    return 0;
+  }
+
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java
new file mode 100644
index 0000000..b6af6cf
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java
@@ -0,0 +1,387 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.ToolMessages.*;
+
+import java.io.PrintStream;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+
+import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
+import org.opends.server.admin.AliasDefaultBehaviorProvider;
+import org.opends.server.admin.DefaultBehaviorProviderVisitor;
+import org.opends.server.admin.DefinedDefaultBehaviorProvider;
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyOption;
+import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider;
+import org.opends.server.admin.SingletonRelationDefinition;
+import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
+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.ManagedObject;
+import org.opends.server.admin.client.ManagedObjectDecodingException;
+import org.opends.server.admin.client.ManagementContext;
+import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.opends.server.tools.ClientException;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.StringArgument;
+import org.opends.server.util.args.SubCommand;
+import org.opends.server.util.args.SubCommandArgumentParser;
+import org.opends.server.util.table.TableBuilder;
+import org.opends.server.util.table.TablePrinter;
+import org.opends.server.util.table.TextTablePrinter;
+
+
+
+/**
+ * A sub-command handler which is used to retrieve the properties of a
+ * managed object.
+ * <p>
+ * This sub-command implements the various get-xxx-prop sub-commands.
+ */
+final class GetPropSubCommandHandler extends SubCommandHandler {
+
+  /**
+   * Creates a new get-xxx-prop sub-command for an instantiable
+   * relation.
+   *
+   * @param parser
+   *          The sub-command argument parser.
+   * @param path
+   *          The parent managed object path.
+   * @param r
+   *          The instantiable relation.
+   * @return Returns the new get-xxx-prop sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  public static GetPropSubCommandHandler create(
+      SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
+      InstantiableRelationDefinition<?, ?> r) throws ArgumentException {
+    return new GetPropSubCommandHandler(parser, path.child(r, "DUMMY"), r);
+  }
+
+  /**
+   * Creates a new get-xxx-prop sub-command for an optional relation.
+   *
+   * @param parser
+   *          The sub-command argument parser.
+   * @param path
+   *          The parent managed object path.
+   * @param r
+   *          The optional relation.
+   * @return Returns the new get-xxx-prop sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  public static GetPropSubCommandHandler create(
+      SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
+      OptionalRelationDefinition<?, ?> r) throws ArgumentException {
+    return new GetPropSubCommandHandler(parser, path.child(r), r);
+  }
+
+  /**
+   * Creates a new get-xxx-prop sub-command for a singleton relation.
+   *
+   * @param parser
+   *          The sub-command argument parser.
+   * @param path
+   *          The parent managed object path.
+   * @param r
+   *          The singleton relation.
+   * @return Returns the new get-xxx-prop sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  public static GetPropSubCommandHandler create(
+      SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
+      SingletonRelationDefinition<?, ?> r) throws ArgumentException {
+    return new GetPropSubCommandHandler(parser, path.child(r), r);
+  }
+
+  // The sub-commands naming arguments.
+  private final List<StringArgument> namingArgs;
+
+  // The path of the managed object.
+  private final ManagedObjectPath<?, ?> path;
+
+  // The sub-command associated with this handler.
+  private final SubCommand subCommand;
+
+
+
+  // Private constructor.
+  private GetPropSubCommandHandler(SubCommandArgumentParser parser,
+      ManagedObjectPath<?, ?> path, RelationDefinition<?, ?> r)
+      throws ArgumentException {
+    this.path = path;
+
+    // Create the sub-command.
+    String name = "get-" + r.getName() + "-prop";
+    int descriptionID = MSGID_DSCFG_DESCRIPTION_SUBCMD_GETPROP;
+    this.subCommand = new SubCommand(parser, name, false, 0, 0, null,
+        descriptionID, r.getChildDefinition().getUserFriendlyName());
+
+    // Create the naming arguments.
+    this.namingArgs = createNamingArgs(subCommand, path);
+
+    // Register common arguments.
+    registerPropertyNameArgument(this.subCommand);
+    registerRecordModeArgument(this.subCommand);
+    registerUnitSizeArgument(this.subCommand);
+    registerUnitTimeArgument(this.subCommand);
+
+    // Register the tags associated with the child managed objects.
+    addTags(path.getManagedObjectDefinition().getAllTags());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public SubCommand getSubCommand() {
+    return subCommand;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int run(DSConfig app, PrintStream out, PrintStream err)
+      throws ArgumentException, ClientException {
+    // Get the property names.
+    Set<String> propertyNames = getPropertyNames();
+    PropertyValuePrinter valuePrinter = new PropertyValuePrinter(getSizeUnit(),
+        getTimeUnit(), app.isScriptFriendly());
+
+    // Get the naming argument values.
+    List<String> names = getNamingArgValues(namingArgs);
+
+    // Get the targeted managed object.
+    ManagementContext context = app.getManagementContext();
+    ManagedObject<?> child;
+    try {
+      child = getManagedObject(context, path, names);
+    } catch (AuthorizationException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_CHILD_AUTHZ;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+          msgID, msg);
+    } catch (DefinitionDecodingException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_CHILD_DDE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn, ufn, ufn);
+      throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+    } catch (ManagedObjectDecodingException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_CHILD_MODE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+    } catch (CommunicationException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_CHILD_CE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn, e.getMessage());
+      throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msgID,
+          msg);
+    } catch (ConcurrentModificationException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_CHILD_CME;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID,
+          msg);
+    } catch (ManagedObjectNotFoundException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_CHILD_MONFE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msgID, msg);
+    }
+
+    // Validate the property names.
+    ManagedObjectDefinition<?, ?> d = child.getManagedObjectDefinition();
+    Collection<PropertyDefinition<?>> pdList;
+    if (propertyNames.isEmpty()) {
+      pdList = d.getAllPropertyDefinitions();
+    } else {
+      pdList = new LinkedList<PropertyDefinition<?>>();
+      for (String name : propertyNames) {
+        try {
+          pdList.add(d.getPropertyDefinition(name));
+        } catch (IllegalArgumentException e) {
+          throw ArgumentExceptionFactory.unknownProperty(d, name);
+        }
+      }
+    }
+
+    // Now output its properties.
+    TableBuilder builder = new TableBuilder();
+    builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_PROPERTY_NAME));
+    builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_PROPERTY_VALUE));
+    builder.addSortKey(0);
+    for (PropertyDefinition<?> pd : pdList) {
+      if (pd.hasOption(PropertyOption.HIDDEN)) {
+        continue;
+      }
+
+      if (propertyNames.isEmpty() || propertyNames.contains(pd.getName())) {
+        displayProperty(app, builder, child, pd, valuePrinter);
+      }
+    }
+
+    if (app.isScriptFriendly()) {
+      TablePrinter printer = createScriptFriendlyTablePrinter(out);
+      builder.print(printer);
+    } else {
+      TextTablePrinter printer = new TextTablePrinter(out);
+      printer.setColumnSeparator(":");
+      printer.setColumnWidth(1, 0);
+      builder.print(printer);
+    }
+
+    return 0;
+  }
+
+
+
+  // Display the set of values associated with a property.
+  private <T> void displayProperty(final DSConfig app, TableBuilder builder,
+      ManagedObject<?> mo, PropertyDefinition<T> pd,
+      PropertyValuePrinter valuePrinter) {
+    SortedSet<T> values = mo.getPropertyValues(pd);
+    if (values.isEmpty()) {
+      // There are no values or default values. Display the default
+      // behavior for alias values.
+      DefaultBehaviorProviderVisitor<T, String, Void> visitor =
+        new DefaultBehaviorProviderVisitor<T, String, Void>() {
+
+        public String visitAbsoluteInherited(
+            AbsoluteInheritedDefaultBehaviorProvider<T> d, Void p) {
+          // Should not happen - inherited default values are
+          // displayed as normal values.
+          throw new IllegalStateException();
+        }
+
+
+
+        public String visitAlias(AliasDefaultBehaviorProvider<T> d, Void p) {
+          if (app.isVerbose()) {
+            return d.getSynopsis();
+          } else {
+            return null;
+          }
+        }
+
+
+
+        public String visitDefined(DefinedDefaultBehaviorProvider<T> d,
+            Void p) {
+          // Should not happen - real default values are displayed as
+          // normal values.
+          throw new IllegalStateException();
+        }
+
+
+
+        public String visitRelativeInherited(
+            RelativeInheritedDefaultBehaviorProvider<T> d, Void p) {
+          // Should not happen - inherited default values are
+          // displayed as normal values.
+          throw new IllegalStateException();
+        }
+
+
+
+        public String visitUndefined(UndefinedDefaultBehaviorProvider<T> d,
+            Void p) {
+          return null;
+        }
+      };
+
+      builder.startRow();
+      builder.appendCell(pd.getName());
+
+      String content = pd.getDefaultBehaviorProvider().accept(visitor, null);
+      if (content == null) {
+        if (app.isScriptFriendly()) {
+          builder.appendCell();
+        } else {
+          builder.appendCell("-");
+        }
+      } else {
+        builder.appendCell(content);
+      }
+    } else {
+      if (isRecordMode()) {
+        for (T value : values) {
+          builder.startRow();
+          builder.appendCell(pd.getName());
+          builder.appendCell(valuePrinter.print(pd, value));
+        }
+      } else {
+        builder.startRow();
+        builder.appendCell(pd.getName());
+
+        if (app.isScriptFriendly()) {
+          for (T value : values) {
+            builder.appendCell(valuePrinter.print(pd, value));
+          }
+        } else {
+          StringBuilder sb = new StringBuilder();
+          boolean isFirst = true;
+          for (T value : values) {
+            if (!isFirst) {
+              sb.append(", ");
+            }
+            sb.append(valuePrinter.print(pd, value));
+            isFirst = false;
+          }
+
+          builder.appendCell(sb.toString());
+        }
+      }
+    }
+  }
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java
new file mode 100644
index 0000000..8dd749a
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java
@@ -0,0 +1,913 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.ToolMessages.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
+import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.AdministratorAction;
+import org.opends.server.admin.AliasDefaultBehaviorProvider;
+import org.opends.server.admin.DefaultBehaviorProviderVisitor;
+import org.opends.server.admin.DefinedDefaultBehaviorProvider;
+import org.opends.server.admin.EnumPropertyDefinition;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyDefinitionUsageBuilder;
+import org.opends.server.admin.PropertyDefinitionVisitor;
+import org.opends.server.admin.PropertyOption;
+import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider;
+import org.opends.server.admin.StringPropertyDefinition;
+import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
+import org.opends.server.admin.UnknownPropertyDefinitionException;
+import org.opends.server.tools.ClientException;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.StringArgument;
+import org.opends.server.util.args.SubCommand;
+import org.opends.server.util.args.SubCommandArgumentParser;
+import org.opends.server.util.table.TableBuilder;
+import org.opends.server.util.table.TablePrinter;
+import org.opends.server.util.table.TextTablePrinter;
+
+
+
+/**
+ * A sub-command handler which is used to display help about managed
+ * objects and their properties.
+ * <p>
+ * This sub-command implements the help-properties sub-command.
+ */
+final class HelpSubCommandHandler extends SubCommandHandler {
+
+  /**
+   * This class is used to print the default behavior of a property.
+   */
+  private static class DefaultBehaviorPrinter {
+
+    /**
+     * The default behavior printer visitor implementation.
+     *
+     * @param <T>
+     *          The property type.
+     */
+    private static class DefaultVisitor<T> implements
+        DefaultBehaviorProviderVisitor<T, String, PropertyDefinition<T>> {
+
+      /**
+       * {@inheritDoc}
+       */
+      public String visitAbsoluteInherited(
+          AbsoluteInheritedDefaultBehaviorProvider<T> d,
+          PropertyDefinition<T> p) {
+        return String.format(FIELD_INHERITS_ABSOLUTE, d.getPropertyName(), d
+            .getManagedObjectPath().getRelationDefinition()
+            .getUserFriendlyName());
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      public String visitAlias(AliasDefaultBehaviorProvider<T> d,
+          PropertyDefinition<T> p) {
+        return d.getSynopsis();
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      public String visitDefined(DefinedDefaultBehaviorProvider<T> d,
+          PropertyDefinition<T> p) {
+        StringBuilder builder = new StringBuilder();
+        PropertyValuePrinter printer = new PropertyValuePrinter(null, null,
+            false);
+        boolean isFirst = true;
+        for (String s : d.getDefaultValues()) {
+          if (!isFirst) {
+            builder.append(", "); //$NON-NLS-1$
+          }
+
+          T value = p.decodeValue(s);
+          builder.append(printer.print(p, value));
+        }
+
+        return builder.toString();
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      public String visitRelativeInherited(
+          RelativeInheritedDefaultBehaviorProvider<T> d,
+          PropertyDefinition<T> p) {
+        if (d.getRelativeOffset() == 0) {
+          return String.format(FIELD_INHERITS_RELATIVE_THIS, d
+              .getPropertyName(), d.getManagedObjectDefinition()
+              .getUserFriendlyName());
+        } else {
+          return String.format(FIELD_INHERITS_RELATIVE_PARENT, d
+              .getPropertyName(), d.getManagedObjectDefinition()
+              .getUserFriendlyName());
+        }
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      public String visitUndefined(UndefinedDefaultBehaviorProvider<T> d,
+          PropertyDefinition<T> p) {
+        return FIELD_UNDEFINED;
+      }
+
+    }
+
+
+
+    /**
+     * Create a new default behavior printer.
+     */
+    public DefaultBehaviorPrinter() {
+      // No implementation required.
+    }
+
+
+
+    /**
+     * Get a user-friendly description of a property's default
+     * behavior.
+     *
+     * @param <T>
+     *          The type of the property definition.
+     * @param pd
+     *          The property definition.
+     * @return Returns the user-friendly description of a property's
+     *         default behavior.
+     */
+    public <T> String print(PropertyDefinition<T> pd) {
+      DefaultVisitor<T> v = new DefaultVisitor<T>();
+      return pd.getDefaultBehaviorProvider().accept(v, pd);
+    }
+  }
+
+
+
+  /**
+   * This class is used to print detailed syntax information about a
+   * property.
+   */
+  private static class SyntaxPrinter {
+
+    /**
+     * The syntax printer visitor implementation.
+     */
+    private static class Visitor extends
+        PropertyDefinitionVisitor<Void, PrintStream> {
+
+      // Private constructor.
+      private Visitor() {
+        // No implementation required.
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public <E extends Enum<E>> Void visitEnum(EnumPropertyDefinition<E> d,
+          PrintStream p) {
+        displayUsage(p, FIELD_ENUM);
+        p.println();
+
+        TableBuilder builder = new TableBuilder();
+        boolean isFirst = true;
+        for (E value : EnumSet.<E> allOf(d.getEnumClass())) {
+          if (!isFirst) {
+            builder.startRow();
+          }
+
+          builder.startRow();
+          builder.appendCell();
+          builder.appendCell();
+          builder.appendCell(value.toString());
+          builder.appendCell(HEADING_SEPARATOR);
+          builder.appendCell(d.getValueSynopsis(value));
+
+          isFirst = false;
+        }
+
+        TextTablePrinter factory = new TextTablePrinter(p);
+        factory.setDisplayHeadings(false);
+        factory.setColumnWidth(0, HEADING_WIDTH);
+        factory.setColumnWidth(1, HEADING_SEPARATOR.length());
+        factory.setColumnWidth(4, 0);
+        factory.setPadding(0);
+
+        builder.print(factory);
+
+        return null;
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public Void visitString(StringPropertyDefinition d, PrintStream p) {
+        PropertyDefinitionUsageBuilder usageBuilder =
+          new PropertyDefinitionUsageBuilder(true);
+
+        TableBuilder builder = new TableBuilder();
+        builder.startRow();
+        builder.appendCell(HEADING_SYNTAX);
+        builder.appendCell(HEADING_SEPARATOR);
+        builder.appendCell(usageBuilder.getUsage(d));
+
+        if (d.getPattern() != null) {
+          builder.startRow();
+          builder.startRow();
+          builder.appendCell();
+          builder.appendCell();
+          builder.appendCell(d.getPatternSynopsis());
+        }
+
+        TextTablePrinter factory = new TextTablePrinter(p);
+        factory.setDisplayHeadings(false);
+        factory.setColumnWidth(0, HEADING_WIDTH);
+        factory.setColumnWidth(2, 0);
+        factory.setPadding(0);
+
+        builder.print(factory);
+
+        return null;
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public Void visitUnknown(PropertyDefinition d, PrintStream p)
+          throws UnknownPropertyDefinitionException {
+        PropertyDefinitionUsageBuilder usageBuilder =
+          new PropertyDefinitionUsageBuilder(true);
+        displayUsage(p, usageBuilder.getUsage(d));
+
+        return null;
+      }
+
+
+
+      // Common usage.
+      private void displayUsage(PrintStream p, String usage) {
+        TableBuilder builder = new TableBuilder();
+        builder.startRow();
+        builder.appendCell(HEADING_SYNTAX);
+        builder.appendCell(HEADING_SEPARATOR);
+        builder.appendCell(usage);
+
+        TextTablePrinter factory = new TextTablePrinter(p);
+        factory.setDisplayHeadings(false);
+        factory.setColumnWidth(0, HEADING_WIDTH);
+        factory.setColumnWidth(2, 0);
+        factory.setPadding(0);
+
+        builder.print(factory);
+      }
+    }
+
+    // The private implementation.
+    private final Visitor pimpl;
+
+
+
+    /**
+     * Creates a new syntax printer which can be used to print
+     * detailed syntax information about a property.
+     */
+    public SyntaxPrinter() {
+      this.pimpl = new Visitor();
+    }
+
+
+
+    /**
+     * Print detailed syntax information about a property definition.
+     *
+     * @param out
+     *          The output stream.
+     * @param pd
+     *          The property definition.
+     */
+    public void print(PrintStream out, PropertyDefinition<?> pd) {
+      pd.accept(pimpl, out);
+    }
+  }
+
+  // Strings used in property help.
+  private static final String KEY_PREFIX = "help-properties.";
+
+  private static final String FIELD_COMPONENT_RESTART = Messages
+      .getString(KEY_PREFIX + "field.component.restart"); //$NON-NLS-1$
+
+  private static final String FIELD_ENUM = Messages.getString(KEY_PREFIX
+      + "field.enum"); //$NON-NLS-1$
+
+  private static final String FIELD_INHERITS_ABSOLUTE = Messages
+      .getString(KEY_PREFIX + "field.inherits.abs"); //$NON-NLS-1$
+
+  private static final String FIELD_INHERITS_RELATIVE_PARENT = Messages
+      .getString(KEY_PREFIX + "field.inherits.parent"); //$NON-NLS-1$
+
+  private static final String FIELD_INHERITS_RELATIVE_THIS = Messages
+      .getString(KEY_PREFIX + "field.inherits.this"); //$NON-NLS-1$
+
+  private static final String FIELD_MONITORING = Messages.getString(KEY_PREFIX
+      + "field.monitoring"); //$NON-NLS-1$
+
+  private static final String FIELD_NO =
+    Messages.getString("general.no"); //$NON-NLS-1$
+
+  private static final String FIELD_READ_ONLY = Messages.getString(KEY_PREFIX
+      + "field.read-only"); //$NON-NLS-1$
+
+  private static final String FIELD_SERVER_RESTART = Messages
+      .getString(KEY_PREFIX + "field.server.restart"); //$NON-NLS-1$
+
+  private static final String FIELD_UNDEFINED = Messages.getString(KEY_PREFIX
+      + "field.undefined"); //$NON-NLS-1$
+
+  private static final String FIELD_YES =
+    Messages.getString("general.yes"); //$NON-NLS-1$
+
+  private final static String HEADING_DEFAULT = Messages.getString(KEY_PREFIX
+      + "heading.default"); //$NON-NLS-1$
+
+  private static final String HEADING_MANAGED_OBJECT = Messages
+      .getString(KEY_PREFIX + "heading.managed-object"); //$NON-NLS-1$
+
+  private final static String HEADING_MANDATORY = Messages.getString(KEY_PREFIX
+      + "heading.mandatory"); //$NON-NLS-1$
+
+  private final static String HEADING_MULTI_VALUED = Messages
+      .getString(KEY_PREFIX + "heading.multi-valued"); //$NON-NLS-1$
+
+  private static final String HEADING_PROPERTY = Messages.getString(KEY_PREFIX
+      + "heading.property"); //$NON-NLS-1$
+
+  private final static String HEADING_READ_ONLY = Messages.getString(KEY_PREFIX
+      + "heading.read-only"); //$NON-NLS-1$
+
+  private final static String HEADING_SEPARATOR = " : "; //$NON-NLS-1$
+
+  private final static String HEADING_SYNTAX = Messages.getString(KEY_PREFIX
+      + "heading.syntax"); //$NON-NLS-1$
+
+  private final static String DESCRIPTION_OPTIONS_TITLE = Messages
+      .getString(KEY_PREFIX + "description.options"); //$NON-NLS-1$
+
+  private final static String DESCRIPTION_OPTIONS_READ = Messages
+      .getString(KEY_PREFIX + "description.read"); //$NON-NLS-1$
+
+  private final static String DESCRIPTION_OPTIONS_WRITE = Messages
+      .getString(KEY_PREFIX + "description.write"); //$NON-NLS-1$
+
+  private final static String DESCRIPTION_OPTIONS_MANDATORY = Messages
+      .getString(KEY_PREFIX + "description.mandatory"); //$NON-NLS-1$
+
+  private final static String DESCRIPTION_OPTIONS_SINGLE = Messages
+      .getString(KEY_PREFIX + "description.single-valued"); //$NON-NLS-1$
+
+  private final static String DESCRIPTION_OPTIONS_ADMIN = Messages
+      .getString(KEY_PREFIX + "description.admin-action"); //$NON-NLS-1$
+
+  // Width of biggest heading (need to be careful of I18N).
+  private final static int HEADING_WIDTH;
+
+  /**
+   * The value for the long option type.
+   */
+  private static final String OPTION_DSCFG_LONG_TYPE = "type";
+
+
+
+  /**
+   * The value for the short option type.
+   */
+  private static final Character OPTION_DSCFG_SHORT_TYPE = 't';
+
+  static {
+    int tmp = HEADING_SYNTAX.length();
+    tmp = Math.max(tmp, HEADING_DEFAULT.length());
+    tmp = Math.max(tmp, HEADING_MULTI_VALUED.length());
+    tmp = Math.max(tmp, HEADING_MANDATORY.length());
+    tmp = Math.max(tmp, HEADING_READ_ONLY.length());
+    HEADING_WIDTH = tmp;
+  }
+
+  /**
+   * Creates a new help-properties sub-command.
+   *
+   * @param parser
+   *          The sub-command argument parser.
+   * @return Returns the new help-properties sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  public static HelpSubCommandHandler create(SubCommandArgumentParser parser)
+      throws ArgumentException {
+    return new HelpSubCommandHandler(parser);
+  }
+
+
+
+  // The sub-command associated with this handler.
+  private final SubCommand subCommand;
+
+  // The argument which should be used to specify the type of managed
+  // object to be retrieved.
+  private final StringArgument typeArgument;
+
+  // A table listing all the available types of managed object.
+  private final Map<String, AbstractManagedObjectDefinition<?, ?>> types;
+
+  // Private constructor.
+  private HelpSubCommandHandler(SubCommandArgumentParser parser)
+      throws ArgumentException {
+    // Create the sub-command.
+    String name = "list-properties";
+    int descriptionID = MSGID_DSCFG_DESCRIPTION_SUBCMD_HELPPROP;
+    this.subCommand = new SubCommand(parser, name, false, 0, 0, null,
+        descriptionID);
+
+    this.typeArgument = new StringArgument(OPTION_DSCFG_LONG_TYPE,
+        OPTION_DSCFG_SHORT_TYPE, OPTION_DSCFG_LONG_TYPE, false, false, true,
+        "{TYPE}", null, null, MSGID_DSCFG_DESCRIPTION_HELP_TYPE);
+    this.subCommand.addArgument(this.typeArgument);
+
+    // Register common arguments.
+    registerPropertyNameArgument(this.subCommand);
+
+    this.types = new TreeMap<String, AbstractManagedObjectDefinition<?, ?>>();
+  }
+
+
+
+  /**
+   * Displays detailed help about a single property to the specified
+   * output stream.
+   *
+   * @param d
+   *          The managed object definition.
+   * @param name
+   *          The name of the property definition.
+   * @param out
+   *          The output stream.
+   */
+  public void displayVerboseSingleProperty(
+      AbstractManagedObjectDefinition<?, ?> d, String name, PrintStream out) {
+    PropertyDefinition<?> pd = d.getPropertyDefinition(name);
+
+    // Display the title.
+    out.println(String.format(HEADING_PROPERTY, name));
+
+    // Display the property synopsis and description.
+    out.println();
+    out.println(wrapText(pd.getSynopsis(), MAX_LINE_WIDTH));
+    if (pd.getDescription() != null) {
+      out.println();
+      out.println(wrapText(pd.getDescription(), MAX_LINE_WIDTH));
+    }
+
+    // Display the syntax.
+    out.println();
+    SyntaxPrinter syntaxPrinter = new SyntaxPrinter();
+    syntaxPrinter.print(out, pd);
+
+    // Display remaining information in a table.
+    out.println();
+    TableBuilder builder = new TableBuilder();
+
+    // Display the default behavior.
+    DefaultBehaviorPrinter defaultPrinter = new DefaultBehaviorPrinter();
+
+    builder.startRow();
+    builder.appendCell(HEADING_DEFAULT);
+    builder.appendCell(HEADING_SEPARATOR);
+    builder.appendCell(defaultPrinter.print(pd));
+
+    // Display options.
+    builder.startRow();
+    builder.appendCell(HEADING_MULTI_VALUED);
+    builder.appendCell(HEADING_SEPARATOR);
+    if (pd.hasOption(PropertyOption.MULTI_VALUED)) {
+      builder.appendCell(FIELD_YES);
+    } else {
+      builder.appendCell(FIELD_NO);
+    }
+
+    builder.startRow();
+    builder.appendCell(HEADING_MANDATORY);
+    builder.appendCell(HEADING_SEPARATOR);
+    if (pd.hasOption(PropertyOption.MANDATORY)) {
+      builder.appendCell(FIELD_YES);
+    } else {
+      builder.appendCell(FIELD_NO);
+    }
+
+    builder.startRow();
+    builder.appendCell(HEADING_READ_ONLY);
+    builder.appendCell(HEADING_SEPARATOR);
+    if (pd.hasOption(PropertyOption.MONITORING)) {
+      builder.appendCell(FIELD_MONITORING);
+    } else if (pd.hasOption(PropertyOption.READ_ONLY)) {
+      builder.appendCell(String
+          .format(FIELD_READ_ONLY, d.getUserFriendlyName()));
+    } else {
+      builder.appendCell(FIELD_NO);
+    }
+
+    TextTablePrinter factory = new TextTablePrinter(out);
+    factory.setDisplayHeadings(false);
+    factory.setColumnWidth(0, HEADING_WIDTH);
+    factory.setColumnWidth(2, 0);
+    factory.setPadding(0);
+    builder.print(factory);
+
+    // Administrator action.
+    AdministratorAction action = pd.getAdministratorAction();
+    String synopsis = action.getSynopsis();
+    if (synopsis == null) {
+      switch (action.getType()) {
+      case COMPONENT_RESTART:
+        synopsis = String.format(FIELD_COMPONENT_RESTART, d
+            .getUserFriendlyName());
+        break;
+      case SERVER_RESTART:
+        synopsis = FIELD_SERVER_RESTART;
+        break;
+      default:
+        // Do nothing.
+        break;
+      }
+    }
+
+    if (synopsis != null) {
+      out.println();
+      out.println(wrapText(synopsis, MAX_LINE_WIDTH));
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public SubCommand getSubCommand() {
+    return subCommand;
+  }
+
+
+
+  /**
+   * Registers a managed object definition with this help properties
+   * sub-command.
+   *
+   * @param d
+   *          The managed object definition.
+   */
+  public void registerManagedObjectDefinition(
+      AbstractManagedObjectDefinition<?, ?> d) {
+    types.put(d.getName(), d);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int run(DSConfig app, PrintStream out, PrintStream err)
+      throws ArgumentException, ClientException {
+    String typeName = typeArgument.getValue();
+    Set<String> propertyNames = getPropertyNames();
+
+    AbstractManagedObjectDefinition<?, ?> d = null;
+    if (typeName != null) {
+      // Requested help regarding a single managed object type.
+      d = types.get(typeName);
+      if (d == null) {
+        throw ArgumentExceptionFactory.unknownType(typeName);
+      }
+    }
+
+    // Validate property names if the type was specified.
+    if (d != null) {
+      for (String propertyName : propertyNames) {
+        try {
+          d.getPropertyDefinition(propertyName);
+        } catch (IllegalArgumentException e) {
+          throw ArgumentExceptionFactory.unknownProperty(d, propertyName);
+        }
+      }
+    }
+
+    // Determine the set of managed objects to be displayed.
+    Collection<AbstractManagedObjectDefinition<?, ?>> defns;
+    if (d == null) {
+      defns = types.values();
+    } else {
+      defns = Collections.<AbstractManagedObjectDefinition<?, ?>> singleton(d);
+    }
+
+    if (!app.isVerbose()) {
+      displayNonVerbose(app, out, err, defns, propertyNames);
+    } else {
+      displayVerbose(app, out, err, defns, propertyNames);
+    }
+    return 0;
+  }
+
+
+
+  // Output property summary table.
+  private void displayNonVerbose(DSConfig app, PrintStream out,
+      PrintStream err, Collection<AbstractManagedObjectDefinition<?, ?>> defns,
+      Set<String> propertyNames) {
+    if (!app.isScriptFriendly()) {
+      out.println(DESCRIPTION_OPTIONS_TITLE);
+      out.println();
+      out.print(" r -- ");
+      out.println(DESCRIPTION_OPTIONS_READ);
+      out.print(" w -- ");
+      out.println(DESCRIPTION_OPTIONS_WRITE);
+      out.print(" m -- ");
+      out.println(DESCRIPTION_OPTIONS_MANDATORY);
+      out.print(" s -- ");
+      out.println(DESCRIPTION_OPTIONS_SINGLE);
+      out.print(" a -- ");
+      out.println(DESCRIPTION_OPTIONS_ADMIN);
+      out.println();
+      out.println();
+    }
+
+    // Headings.
+    TableBuilder builder = new TableBuilder();
+
+    builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_MANAGED_OBJECT_NAME));
+    builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_PROPERTY_NAME));
+    builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_PROPERTY_OPTIONS));
+    builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_PROPERTY_SYNTAX));
+
+    // Sort keys.
+    builder.addSortKey(0);
+    builder.addSortKey(1);
+
+    // Generate the table content.
+    for (AbstractManagedObjectDefinition<?, ?> mod : defns) {
+      Collection<PropertyDefinition<?>> pds;
+      if (app.isScriptFriendly()) {
+        pds = mod.getAllPropertyDefinitions();
+      } else {
+        pds = mod.getPropertyDefinitions();
+      }
+
+      for (PropertyDefinition<?> pd : pds) {
+        if (pd.hasOption(PropertyOption.HIDDEN)) {
+          continue;
+        }
+
+        if (!propertyNames.isEmpty() && !propertyNames.contains(pd.getName())) {
+          continue;
+        }
+
+        // Display the property.
+        builder.startRow();
+
+        // Display the managed object type if necessary.
+        builder.appendCell(mod.getName());
+
+        // Display the property name.
+        builder.appendCell(pd.getName());
+
+        // Display the options.
+        builder.appendCell(getPropertyOptionSummary(pd));
+
+        // Display the syntax.
+        PropertyDefinitionUsageBuilder v =
+          new PropertyDefinitionUsageBuilder(false);
+        builder.appendCell(v.getUsage(pd));
+      }
+    }
+
+    TablePrinter printer;
+    if (app.isScriptFriendly()) {
+      printer = createScriptFriendlyTablePrinter(out);
+    } else {
+      printer = new TextTablePrinter(out);
+    }
+    builder.print(printer);
+  }
+
+
+
+  // Display detailed help on managed objects and their properties.
+  private void displayVerbose(DSConfig app, PrintStream out, PrintStream err,
+      Collection<AbstractManagedObjectDefinition<?, ?>> defns,
+      Set<String> propertyNames) {
+    // Construct line used to separate consecutive sections.
+    char[] c1 = new char[MAX_LINE_WIDTH];
+    Arrays.fill(c1, '=');
+    char[] c2 = new char[MAX_LINE_WIDTH];
+    Arrays.fill(c2, '-');
+
+    // Display help for each managed object.
+    boolean isFirstManagedObject = true;
+    for (AbstractManagedObjectDefinition<?, ?> mod : defns) {
+      if (!isFirstManagedObject) {
+        out.println();
+        out.println(c1);
+        out.println();
+      }
+
+      // Display the title.
+      out.println(wrapText(String.format(HEADING_MANAGED_OBJECT, mod
+          .getUserFriendlyName()), MAX_LINE_WIDTH));
+
+      out.println();
+      out.println(wrapText(mod.getSynopsis(), MAX_LINE_WIDTH));
+      if (mod.getDescription() != null) {
+        out.println();
+        out.println(wrapText(mod.getDescription(), MAX_LINE_WIDTH));
+      }
+
+      // Display help for each property.
+      Set<PropertyDefinition<?>> pds =
+        new TreeSet<PropertyDefinition<?>>(mod.getAllPropertyDefinitions());
+      for (PropertyDefinition<?> pd : pds) {
+        if (pd.hasOption(PropertyOption.HIDDEN)) {
+          continue;
+        }
+
+        if (!propertyNames.isEmpty() && !propertyNames.contains(pd.getName())) {
+          continue;
+        }
+
+        out.println();
+        out.println(c2);
+        out.println();
+
+        displayVerboseSingleProperty(mod, pd.getName(), out);
+      }
+
+      isFirstManagedObject = false;
+    }
+  }
+
+
+
+  // Display description of the single managed object.
+  /*private void displaySummaryForSingleManagedObject(DSConfig app,
+      PrintStream out, PrintStream err,
+      AbstractManagedObjectDefinition<?, ?> d, Set<String> propertyNames) {
+
+    // Display the title.
+    out.println(wrapText(String.format(HEADING_MANAGED_OBJECT, d
+        .getUserFriendlyName()), MAX_LINE_WIDTH));
+
+    out.println();
+    out.println(wrapText(d.getSynopsis(), MAX_LINE_WIDTH));
+    if (d.getDescription() != null) {
+      out.println();
+      out.println(wrapText(d.getDescription(), MAX_LINE_WIDTH));
+    }
+
+    // Output table of properties.
+    TableBuilder builder = new TableBuilder();
+
+    // Headings.
+    builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_PROPERTY_NAME));
+    builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_PROPERTY_OPTIONS));
+    builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_PROPERTY_SYNTAX));
+
+    // Sort keys.
+    builder.addSortKey(0);
+
+    // Generate the table content.
+    for (String name : propertyNames) {
+      PropertyDefinition<?> pd = d.getPropertyDefinition(name);
+
+      if (pd.hasOption(PropertyOption.HIDDEN)) {
+        continue;
+      }
+
+      // Display a property.
+      builder.startRow();
+      builder.appendCell(pd.getName());
+
+      // Display the options.
+      builder.appendCell(getPropertyOptionSummary(pd));
+
+      // Display the syntax.
+      PropertyDefinitionUsageBuilder v =
+        new PropertyDefinitionUsageBuilder(false);
+      String syntax = v.getUsage(pd);
+      if (syntax.length() < 40) {
+        builder.appendCell(syntax);
+      } else {
+        String msg = getMessage(MSGID_DSCFG_DESCRIPTION_PROPERTY_SYNTAX_HELP);
+        builder.appendCell(msg);
+      }
+    }
+
+    TextTablePrinter factory = new TextTablePrinter(out);
+
+    // Let the syntax column be expandable.
+    factory.setColumnWidth(2, 0);
+
+    out.println();
+    builder.print(factory);
+  }*/
+
+
+
+  // Compute the options field.
+  private String getPropertyOptionSummary(PropertyDefinition<?> pd) {
+    StringBuilder b = new StringBuilder();
+
+    if (pd.hasOption(PropertyOption.MONITORING)
+        || pd.hasOption(PropertyOption.READ_ONLY)) {
+      b.append("r-"); //$NON-NLS-1$
+    } else {
+      b.append("rw"); //$NON-NLS-1$
+    }
+
+    if (pd.hasOption(PropertyOption.MANDATORY)) {
+      b.append('m');
+    } else {
+      b.append('-');
+    }
+
+    if (pd.hasOption(PropertyOption.MULTI_VALUED)) {
+      b.append('-');
+    } else {
+      b.append('s');
+    }
+
+    AdministratorAction action = pd.getAdministratorAction();
+    if (action.getType() != AdministratorAction.Type.NONE) {
+      b.append('a');
+    } else {
+      b.append('-');
+    }
+    return b.toString();
+  }
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/InternalManagementContextFactory.java b/opends/src/server/org/opends/server/tools/dsconfig/InternalManagementContextFactory.java
new file mode 100644
index 0000000..98ee7ca
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/InternalManagementContextFactory.java
@@ -0,0 +1,90 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import org.opends.server.admin.client.ManagementContext;
+import org.opends.server.tools.ClientException;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.SubCommandArgumentParser;
+
+
+
+/**
+ * A management context factory which uses a pre-defined management
+ * context.
+ */
+public final class InternalManagementContextFactory implements
+    ManagementContextFactory {
+
+  // The pre-defined management context.
+  private final ManagementContext context;
+
+
+
+  /**
+   * Creates a new internal management context factory using the
+   * provided management context.
+   *
+   * @param context
+   *          The management context.
+   */
+  public InternalManagementContextFactory(ManagementContext context) {
+    this.context = context;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ManagementContext getManagementContext(DSConfig app)
+      throws ArgumentException, ClientException {
+    return context;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void registerGlobalArguments(SubCommandArgumentParser parser)
+      throws ArgumentException {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void validateGlobalArguments() throws ArgumentException {
+    // No implementation required.
+  }
+
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/LDAPManagementContextFactory.java b/opends/src/server/org/opends/server/tools/dsconfig/LDAPManagementContextFactory.java
new file mode 100644
index 0000000..b6804f8
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/LDAPManagementContextFactory.java
@@ -0,0 +1,212 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.ToolMessages.*;
+import static org.opends.server.tools.ToolConstants.*;
+
+import org.opends.server.admin.client.AuthenticationException;
+import org.opends.server.admin.client.AuthenticationNotSupportedException;
+import org.opends.server.admin.client.CommunicationException;
+import org.opends.server.admin.client.ManagementContext;
+import org.opends.server.admin.client.ldap.JNDIDirContextAdaptor;
+import org.opends.server.admin.client.ldap.LDAPConnection;
+import org.opends.server.admin.client.ldap.LDAPManagementContext;
+import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.opends.server.tools.ClientException;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.FileBasedArgument;
+import org.opends.server.util.args.IntegerArgument;
+import org.opends.server.util.args.StringArgument;
+import org.opends.server.util.args.SubCommandArgumentParser;
+
+
+
+/**
+ * An LDAP management context factory.
+ */
+public final class LDAPManagementContextFactory implements
+    ManagementContextFactory {
+
+  // The default bind DN which will be used to manage the directory
+  // server.
+  private static final String DEFAULT_BIND_DN = "cn=directory manager";
+
+  // The management context.
+  private ManagementContext context = null;
+
+  // The argument which should be used to specify the bind DN.
+  private StringArgument bindDNArgument;
+
+  // The argument which should be used to specify the bind password.
+  private StringArgument bindPasswordArgument;
+
+  // The argument which should be used to specify the location of the
+  // bind password file.
+  private FileBasedArgument bindPasswordFileArgument;
+
+  // The argument which should be used to specify the directory server
+  // LDAP host address.
+  private StringArgument hostArgument;
+
+  // The argument which should be used to specify the directory server
+  // LDAP port.
+  private IntegerArgument portArgument;
+
+
+
+  /**
+   * Creates a new LDAP management context factory.
+   */
+  public LDAPManagementContextFactory() {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ManagementContext getManagementContext(DSConfig app)
+      throws ArgumentException, ClientException {
+    // Lazily create the LDAP management context.
+    if (context == null) {
+      // Get the LDAP host.
+      String hostName = hostArgument.getValue();
+
+      // Get the LDAP port.
+      int portNumber = portArgument.getIntValue();
+
+      // Get the LDAP bind credentials.
+      String bindDN = bindDNArgument.getValue();
+      String bindPassword = bindPasswordArgument.getValue();
+
+      if (bindPasswordFileArgument.isPresent()) {
+        // Read from file if it exists.
+        bindPassword = bindPasswordFileArgument.getValue();
+
+        if (bindPassword == null) {
+          throw ArgumentExceptionFactory.missingBindPassword(bindDN);
+        }
+      } else if (bindPassword == null || bindPassword.equals("-")) {
+        // Read the password from the stdin.
+        if (!app.isInteractive()) {
+          throw ArgumentExceptionFactory
+              .unableToReadBindPasswordInteractively();
+        }
+
+        try {
+          String prompt = getMessage(MSGID_LDAPAUTH_PASSWORD_PROMPT, bindDN);
+          bindPassword = app.readPassword(prompt);
+        } catch (Exception e) {
+          throw ArgumentExceptionFactory.unableToReadBindPassword(e);
+        }
+      }
+
+      // Create the management context.
+      try {
+        LDAPConnection conn = JNDIDirContextAdaptor.simpleBind(hostName,
+            portNumber, bindDN, bindPassword);
+        context = LDAPManagementContext.createFromContext(conn);
+      } catch (AuthenticationNotSupportedException e) {
+        int msgID = MSGID_DSCFG_ERROR_LDAP_SIMPLE_BIND_NOT_SUPPORTED;
+        String message = getMessage(msgID);
+        throw new ClientException(LDAPResultCode.AUTH_METHOD_NOT_SUPPORTED,
+            msgID, message);
+      } catch (AuthenticationException e) {
+        int msgID = MSGID_DSCFG_ERROR_LDAP_SIMPLE_BIND_FAILED;
+        String message = getMessage(msgID, bindDN);
+        throw new ClientException(LDAPResultCode.INVALID_CREDENTIALS, msgID,
+            message);
+      } catch (CommunicationException e) {
+        int msgID = MSGID_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT;
+        String message = getMessage(msgID, hostName, portNumber);
+        throw new ClientException(LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR,
+            msgID, message);
+      }
+    }
+    return context;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void registerGlobalArguments(SubCommandArgumentParser parser)
+      throws ArgumentException {
+    // Create the global arguments.
+    hostArgument = new StringArgument("host", OPTION_SHORT_HOST,
+        OPTION_LONG_HOST, false, false, true, OPTION_VALUE_HOST, "localhost",
+        null, MSGID_DESCRIPTION_HOST);
+
+    portArgument = new IntegerArgument("port", OPTION_SHORT_PORT,
+        OPTION_LONG_PORT, false, false, true, OPTION_VALUE_PORT, 389, null,
+        MSGID_DESCRIPTION_PORT);
+
+    bindDNArgument = new StringArgument("bindDN", OPTION_SHORT_BINDDN,
+        OPTION_LONG_BINDDN, false, false, true, OPTION_VALUE_BINDDN,
+        DEFAULT_BIND_DN, null, MSGID_DESCRIPTION_BINDDN);
+
+    bindPasswordArgument = new StringArgument("bindPassword",
+        OPTION_SHORT_BINDPWD, OPTION_LONG_BINDPWD, false, false, true,
+        OPTION_VALUE_BINDPWD, null, null, MSGID_DESCRIPTION_BINDPASSWORD);
+
+    bindPasswordFileArgument = new FileBasedArgument("bindPasswordFile",
+        OPTION_SHORT_BINDPWD_FILE, OPTION_LONG_BINDPWD_FILE, false, false,
+        OPTION_VALUE_BINDPWD_FILE, null, null,
+        MSGID_DESCRIPTION_BINDPASSWORDFILE);
+
+    // Register the global arguments.
+    parser.addGlobalArgument(hostArgument);
+    parser.addGlobalArgument(portArgument);
+    parser.addGlobalArgument(bindDNArgument);
+    parser.addGlobalArgument(bindPasswordArgument);
+    parser.addGlobalArgument(bindPasswordFileArgument);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void validateGlobalArguments() throws ArgumentException {
+    // Make sure that the user didn't specify any conflicting
+    // arguments.
+    if (bindPasswordArgument.isPresent()
+        && bindPasswordFileArgument.isPresent()) {
+      int msgID = MSGID_TOOL_CONFLICTING_ARGS;
+      String message = getMessage(msgID, bindPasswordArgument
+          .getLongIdentifier(), bindPasswordFileArgument.getLongIdentifier());
+      throw new ArgumentException(msgID, message);
+    }
+  }
+
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java
new file mode 100644
index 0000000..a37ec83
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java
@@ -0,0 +1,415 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.ToolMessages.*;
+
+import java.io.PrintStream;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.RelationDefinition;
+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.ManagedObject;
+import org.opends.server.admin.client.ManagedObjectDecodingException;
+import org.opends.server.admin.client.ManagementContext;
+import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.opends.server.tools.ClientException;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.StringArgument;
+import org.opends.server.util.args.SubCommand;
+import org.opends.server.util.args.SubCommandArgumentParser;
+import org.opends.server.util.table.TableBuilder;
+import org.opends.server.util.table.TablePrinter;
+import org.opends.server.util.table.TextTablePrinter;
+
+
+
+/**
+ * A sub-command handler which is used to list existing managed
+ * objects.
+ * <p>
+ * This sub-command implements the various list-xxx sub-commands.
+ */
+final class ListSubCommandHandler extends SubCommandHandler {
+
+  /**
+   * Creates a new list-xxx sub-command for an instantiable relation.
+   *
+   * @param parser
+   *          The sub-command argument parser.
+   * @param p
+   *          The parent managed object path.
+   * @param r
+   *          The instantiable relation.
+   * @return Returns the new list-xxx sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  public static ListSubCommandHandler create(SubCommandArgumentParser parser,
+      ManagedObjectPath<?, ?> p, InstantiableRelationDefinition<?, ?> r)
+      throws ArgumentException {
+    return new ListSubCommandHandler(parser, p, r, r.getPluralName(), r
+        .getUserFriendlyPluralName());
+  }
+
+
+
+  /**
+   * Creates a new list-xxx sub-command for an optional relation.
+   *
+   * @param parser
+   *          The sub-command argument parser.
+   * @param p
+   *          The parent managed object path.
+   * @param r
+   *          The optional relation.
+   * @return Returns the new list-xxx sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  public static ListSubCommandHandler create(SubCommandArgumentParser parser,
+      ManagedObjectPath<?, ?> p, OptionalRelationDefinition<?, ?> r)
+      throws ArgumentException {
+    return new ListSubCommandHandler(parser, p, r, r.getName(), r
+        .getUserFriendlyName());
+  }
+
+  // The sub-commands naming arguments.
+  private final List<StringArgument> namingArgs;
+
+  // The path of the parent managed object.
+  private final ManagedObjectPath<?, ?> path;
+
+  // The relation which should be listed.
+  private final RelationDefinition<?, ?> relation;
+
+  // The sub-command associated with this handler.
+  private final SubCommand subCommand;
+
+
+
+  // Private constructor.
+  private ListSubCommandHandler(SubCommandArgumentParser parser,
+      ManagedObjectPath<?, ?> p, RelationDefinition<?, ?> r, String rname,
+      String rufn) throws ArgumentException {
+    this.path = p;
+    this.relation = r;
+
+    // Create the sub-command.
+    String name = "list-" + rname;
+    int descriptionID = MSGID_DSCFG_DESCRIPTION_SUBCMD_LIST;
+    this.subCommand = new SubCommand(parser, name, false, 0, 0, null,
+        descriptionID, rufn);
+
+    // Create the naming arguments.
+    this.namingArgs = createNamingArgs(subCommand, path);
+
+    // Register arguments.
+    registerPropertyNameArgument(this.subCommand);
+    registerUnitSizeArgument(this.subCommand);
+    registerUnitTimeArgument(this.subCommand);
+
+    // Register the tags associated with the child managed objects.
+    addTags(relation.getChildDefinition().getAllTags());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public SubCommand getSubCommand() {
+    return subCommand;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int run(DSConfig app, PrintStream out, PrintStream err)
+      throws ArgumentException, ClientException {
+    // Get the property names.
+    Set<String> propertyNames = getPropertyNames();
+
+    if (propertyNames.isEmpty()) {
+      // Use a default set of properties.
+      propertyNames = CLIProfile.getInstance().getDefaultListPropertyNames(
+          relation);
+    }
+
+    PropertyValuePrinter valuePrinter = new PropertyValuePrinter(getSizeUnit(),
+        getTimeUnit(), app.isScriptFriendly());
+
+    // Get the naming argument values.
+    List<String> names = getNamingArgValues(namingArgs);
+
+    String ufn;
+    if (relation instanceof InstantiableRelationDefinition) {
+      InstantiableRelationDefinition<?, ?> irelation =
+        (InstantiableRelationDefinition<?, ?>) relation;
+      ufn = irelation.getUserFriendlyPluralName();
+    } else {
+      ufn = relation.getUserFriendlyName();
+    }
+
+    // List the children.
+    ManagementContext context = app.getManagementContext();
+    ManagedObject<?> parent;
+    try {
+      parent = getManagedObject(context, path, names);
+    } catch (AuthorizationException e) {
+      int msgID = MSGID_DSCFG_ERROR_LIST_AUTHZ;
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+          msgID, msg);
+    } catch (DefinitionDecodingException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_PARENT_DDE;
+      ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn, ufn, ufn);
+      throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+    } catch (ManagedObjectDecodingException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_PARENT_MODE;
+      ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+    } catch (CommunicationException e) {
+      int msgID = MSGID_DSCFG_ERROR_LIST_CE;
+      String msg = getMessage(msgID, ufn, e.getMessage());
+      throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msgID,
+          msg);
+    } catch (ConcurrentModificationException e) {
+      int msgID = MSGID_DSCFG_ERROR_LIST_CME;
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID,
+          msg);
+    } catch (ManagedObjectNotFoundException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_PARENT_MONFE;
+      ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msgID, msg);
+    }
+
+    SortedMap<String, ManagedObject<?>> children =
+      new TreeMap<String, ManagedObject<?>>();
+    if (relation instanceof InstantiableRelationDefinition) {
+      InstantiableRelationDefinition<?, ?> irelation =
+        (InstantiableRelationDefinition<?, ?>) relation;
+      try {
+        for (String s : parent.listChildren(irelation)) {
+          try {
+            children.put(s, parent.getChild(irelation, s));
+          } catch (ManagedObjectNotFoundException e) {
+            // Ignore - as it's been removed since we did the list.
+          }
+        }
+      } catch (DefinitionDecodingException e) {
+        // FIXME: just output this as a warnings (incl. the name) but
+        // continue.
+        int msgID = MSGID_DSCFG_ERROR_LIST_DDE;
+        String msg = getMessage(msgID, ufn, ufn, ufn);
+        throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+      } catch (ManagedObjectDecodingException e) {
+        // FIXME: just output this as a warnings (incl. the name) but
+        // continue.
+        int msgID = MSGID_DSCFG_ERROR_LIST_MODE;
+        String msg = getMessage(msgID, ufn);
+        throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+      } catch (AuthorizationException e) {
+        int msgID = MSGID_DSCFG_ERROR_LIST_AUTHZ;
+        String msg = getMessage(msgID, ufn);
+        throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+            msgID, msg);
+      } catch (ConcurrentModificationException e) {
+        int msgID = MSGID_DSCFG_ERROR_LIST_CME;
+        String msg = getMessage(msgID, ufn);
+        throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID,
+            msg);
+      } catch (CommunicationException e) {
+        int msgID = MSGID_DSCFG_ERROR_LIST_CE;
+        String msg = getMessage(msgID, ufn, e.getMessage());
+        throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN,
+            msgID, msg);
+      }
+    } else if (relation instanceof OptionalRelationDefinition) {
+      OptionalRelationDefinition<?, ?> orelation =
+        (OptionalRelationDefinition<?, ?>) relation;
+      try {
+        if (parent.hasChild(orelation)) {
+          ManagedObject<?> child = parent.getChild(orelation);
+          children.put(child.getManagedObjectDefinition().getName(), child);
+        } else {
+          // Indicate that the managed object does not exist.
+          throw new ManagedObjectNotFoundException();
+        }
+      } catch (AuthorizationException e) {
+        int msgID = MSGID_DSCFG_ERROR_LIST_AUTHZ;
+        String msg = getMessage(msgID, ufn);
+        throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+            msgID, msg);
+      } catch (DefinitionDecodingException e) {
+        int msgID = MSGID_DSCFG_ERROR_LIST_DDE;
+        String msg = getMessage(msgID, ufn, ufn, ufn);
+        throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+      } catch (ManagedObjectDecodingException e) {
+        int msgID = MSGID_DSCFG_ERROR_LIST_MODE;
+        String msg = getMessage(msgID, ufn);
+        throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+      } catch (ConcurrentModificationException e) {
+        int msgID = MSGID_DSCFG_ERROR_LIST_CME;
+        String msg = getMessage(msgID, ufn);
+        throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID,
+            msg);
+      } catch (CommunicationException e) {
+        int msgID = MSGID_DSCFG_ERROR_LIST_CE;
+        String msg = getMessage(msgID, ufn, e.getMessage());
+        throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN,
+            msgID, msg);
+      } catch (ManagedObjectNotFoundException e) {
+        int msgID = MSGID_DSCFG_ERROR_LIST_MONFE;
+        String msg = getMessage(msgID, ufn);
+        throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msgID, msg);
+      }
+    }
+
+    // Output the results.
+    if (app.isScriptFriendly()) {
+      // Output just the names of the children.
+      for (String name : children.keySet()) {
+        out.println(name);
+      }
+    } else {
+      // Create a table of their properties.
+      TableBuilder builder = new TableBuilder();
+      builder.appendHeading(relation.getUserFriendlyName());
+      builder
+          .appendHeading(getMessage(MSGID_DSCFG_HEADING_MANAGED_OBJECT_TYPE));
+      if (!propertyNames.isEmpty()) {
+      }
+      for (String propertyName : propertyNames) {
+        builder.appendHeading(propertyName);
+      }
+      builder.addSortKey(0);
+
+      String baseType = relation.getName();
+      String typeSuffix = "-" + baseType;
+      for (String name : children.keySet()) {
+        ManagedObject<?> child = children.get(name);
+        ManagedObjectDefinition<?, ?> d = child.getManagedObjectDefinition();
+
+        // First output the name.
+        builder.startRow();
+        builder.appendCell(name);
+
+        // Output the managed object type in the form used in
+        // create-xxx commands.
+        String childType = d.getName();
+        if (baseType.equals(childType)) {
+          builder.appendCell("generic");
+        } else if (childType.endsWith(typeSuffix)) {
+          builder.appendCell(childType.substring(0, childType.length()
+              - typeSuffix.length()));
+        } else {
+          builder.appendCell(childType);
+        }
+
+        // Now any requested properties.
+        for (String propertyName : propertyNames) {
+          try {
+            PropertyDefinition<?> pd = d.getPropertyDefinition(propertyName);
+            displayProperty(app, builder, child, pd, valuePrinter);
+          } catch (IllegalArgumentException e) {
+            // Assume this child managed object does not support this
+            // property.
+            if (app.isScriptFriendly()) {
+              builder.appendCell();
+            } else {
+              builder.appendCell("-");
+            }
+          }
+        }
+      }
+
+      if (app.isScriptFriendly()) {
+        TablePrinter printer = createScriptFriendlyTablePrinter(out);
+        builder.print(printer);
+      } else {
+        TextTablePrinter printer = new TextTablePrinter(out);
+        printer.setColumnSeparator(":");
+        builder.print(printer);
+      }
+    }
+
+    return 0;
+  }
+
+
+
+  // Display the set of values associated with a property.
+  private <T> void displayProperty(DSConfig app, TableBuilder builder,
+      ManagedObject<?> mo, PropertyDefinition<T> pd,
+      PropertyValuePrinter valuePrinter) {
+    SortedSet<T> values = mo.getPropertyValues(pd);
+    if (values.isEmpty()) {
+      if (app.isScriptFriendly()) {
+        builder.appendCell();
+      } else {
+        builder.appendCell("-");
+      }
+    } else {
+      StringBuilder sb = new StringBuilder();
+      boolean isFirst = true;
+      for (T value : values) {
+        if (!isFirst) {
+          sb.append(", ");
+        }
+        sb.append(valuePrinter.print(pd, value));
+        isFirst = false;
+      }
+
+      builder.appendCell(sb.toString());
+    }
+  }
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/ManagementContextFactory.java b/opends/src/server/org/opends/server/tools/dsconfig/ManagementContextFactory.java
new file mode 100644
index 0000000..c4372f7
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/ManagementContextFactory.java
@@ -0,0 +1,93 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import org.opends.server.admin.client.ManagementContext;
+import org.opends.server.tools.ClientException;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.SubCommandArgumentParser;
+
+
+
+/**
+ * A factory for retrieving the management context which should be
+ * used by the dsconfig application.
+ * <p>
+ * Factory implementations are responsible for registering their
+ * required global options during initialization.
+ */
+public interface ManagementContextFactory {
+
+  /**
+   * Gets the management context which sub-commands should use in
+   * order to manage the directory server. Implementations can use the
+   * application instance for retrieving passwords interactively.
+   *
+   * @param app
+   *          The application instance.
+   * @return Returns the management context which sub-commands should
+   *         use in order to manage the directory server.
+   * @throws ArgumentException
+   *           If a management context related argument could not be
+   *           parsed successfully.
+   * @throws ClientException
+   *           If the management context could not be created.
+   */
+  ManagementContext getManagementContext(DSConfig app) throws ArgumentException,
+      ClientException;
+
+
+
+  /**
+   * Initializes this management context factory using the provided
+   * parser. The management context factory can register global
+   * options with the parser if required.
+   *
+   * @param parser
+   *          The application sub-command argument parser.
+   * @throws ArgumentException
+   *           If the factory failed to register its required global
+   *           options.
+   */
+  void registerGlobalArguments(SubCommandArgumentParser parser)
+      throws ArgumentException;
+
+
+
+  /**
+   * Validates any global arguments passed to the application.
+   * Implementations of this method should check that the values
+   * passed to their global arguments are valid and are not
+   * incompatible with each other.
+   *
+   * @throws ArgumentException
+   *           If the global arguments are invalid for some reason.
+   */
+  void validateGlobalArguments() throws ArgumentException;
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/Messages.java b/opends/src/server/org/opends/server/tools/dsconfig/Messages.java
new file mode 100644
index 0000000..71ae99f
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/Messages.java
@@ -0,0 +1,72 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+
+
+/**
+ * Message resource bundle for dsconfig.
+ */
+public class Messages {
+
+  // The name of the bundle.
+  private static final String BUNDLE_NAME =
+    "org.opends.server.tools.dsconfig.messages"; //$NON-NLS-1$
+
+  // The single resource bundle.
+  private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+      .getBundle(BUNDLE_NAME);
+
+
+
+  // Prevent instantiation.
+  private Messages() {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * Get the named property.
+   *
+   * @param key
+   *          The name of the property.
+   * @return Returns the named property.
+   */
+  public static String getString(String key) {
+    try {
+      return RESOURCE_BUNDLE.getString(key);
+    } catch (MissingResourceException e) {
+      return '!' + key + '!';
+    }
+  }
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/PropertyValuePrinter.java b/opends/src/server/org/opends/server/tools/dsconfig/PropertyValuePrinter.java
new file mode 100644
index 0000000..71aa027
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/PropertyValuePrinter.java
@@ -0,0 +1,207 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import java.text.NumberFormat;
+
+import org.opends.server.admin.DurationPropertyDefinition;
+import org.opends.server.admin.DurationUnit;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyValueVisitor;
+import org.opends.server.admin.SizePropertyDefinition;
+import org.opends.server.admin.SizeUnit;
+
+
+
+/**
+ * A class responsible for displaying property values. This class
+ * takes care of using locale specific formatting rules.
+ */
+final class PropertyValuePrinter {
+
+  /**
+   * Perform property type specific print formatting.
+   */
+  private static class MyPropertyValueVisitor extends
+      PropertyValueVisitor<String, Void> {
+
+    // The requested size unit (null if the property's unit should be
+    // used).
+    private final SizeUnit sizeUnit;
+
+    // The requested time unit (null if the property's unit should be
+    // used).
+    private final DurationUnit timeUnit;
+
+    // Whether or not values should be displayed in a script-friendly
+    // manner.
+    private final boolean isScriptFriendly;
+
+    // The formatter to use for numeric values.
+    private final NumberFormat numberFormat;
+
+
+
+    // Private constructor.
+    private MyPropertyValueVisitor(SizeUnit sizeUnit, DurationUnit timeUnit,
+        boolean isScriptFriendly) {
+      this.sizeUnit = sizeUnit;
+      this.timeUnit = timeUnit;
+      this.isScriptFriendly = isScriptFriendly;
+
+      this.numberFormat = NumberFormat.getNumberInstance();
+      if (this.isScriptFriendly) {
+        numberFormat.setGroupingUsed(false);
+        numberFormat.setMaximumFractionDigits(2);
+      } else {
+        numberFormat.setGroupingUsed(true);
+        numberFormat.setMaximumFractionDigits(2);
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String visitDuration(DurationPropertyDefinition d, Long v, Void p) {
+      if (d.getUpperLimit() == null && (v < 0 || v == Long.MAX_VALUE)) {
+        return "unlimited";
+      }
+
+      long ms = d.getBaseUnit().toMilliSeconds(v);
+
+      // Use human-readable string representation by default.
+      if (timeUnit == null && !isScriptFriendly && ms != 0) {
+        return DurationUnit.toString(ms);
+      }
+
+      // Use either the specified unit or the property definition's
+      // base unit.
+      DurationUnit unit = timeUnit;
+      if (unit == null) {
+        unit = d.getBaseUnit();
+      }
+
+      StringBuilder builder = new StringBuilder();
+      builder.append(numberFormat.format(unit.fromMilliSeconds(ms)));
+      builder.append(' ');
+      builder.append(unit.getShortName());
+
+      return builder.toString();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String visitSize(SizePropertyDefinition d, Long v, Void p) {
+      if (d.isAllowUnlimited() && v < 0) {
+        return "unlimited";
+      }
+
+      SizeUnit unit = sizeUnit;
+      if (unit == null) {
+        if (isScriptFriendly) {
+          // Assume users want a more accurate value.
+          unit = SizeUnit.getBestFitUnitExact(v);
+        } else {
+          unit = SizeUnit.getBestFitUnit(v);
+        }
+      }
+
+      StringBuilder builder = new StringBuilder();
+      builder.append(numberFormat.format(unit.fromBytes(v)));
+      builder.append(' ');
+      builder.append(unit.getShortName());
+
+      return builder.toString();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <T> String visitUnknown(PropertyDefinition<T> d, T v, Void p) {
+      // For all other property definition types the default encoding
+      // will do.
+      return d.encodeValue(v);
+    }
+
+  }
+
+  // The property value printer implementation.
+  private final MyPropertyValueVisitor pimpl;
+
+
+
+  /**
+   * Creates a new property value printer.
+   *
+   * @param sizeUnit
+   *          The user requested size unit or <code>null</code> if
+   *          best-fit.
+   * @param timeUnit
+   *          The user requested time unit or <code>null</code> if
+   *          best-fit.
+   * @param isScriptFriendly
+   *          If values should be displayed in a script friendly
+   *          manner.
+   */
+  public PropertyValuePrinter(SizeUnit sizeUnit, DurationUnit timeUnit,
+      boolean isScriptFriendly) {
+    this.pimpl = new MyPropertyValueVisitor(sizeUnit, timeUnit,
+        isScriptFriendly);
+  }
+
+
+
+  /**
+   * Print a property value according to the rules of this property
+   * value printer.
+   *
+   * @param <T>
+   *          The type of property value.
+   * @param pd
+   *          The property definition.
+   * @param value
+   *          The property value.
+   * @return Returns the string representation of the property value
+   *         encoded according to the rules of this property value
+   *         printer.
+   */
+  public <T> String print(PropertyDefinition<T> pd, T value) {
+    return pd.accept(pimpl, value, null);
+  }
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java
new file mode 100644
index 0000000..cf8ccc7
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java
@@ -0,0 +1,568 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.ToolMessages.*;
+
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.IllegalPropertyValueStringException;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectAlreadyExistsException;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyException;
+import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.SingletonRelationDefinition;
+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.ManagedObject;
+import org.opends.server.admin.client.ManagedObjectDecodingException;
+import org.opends.server.admin.client.ManagementContext;
+import org.opends.server.admin.client.MissingMandatoryPropertiesException;
+import org.opends.server.admin.client.OperationRejectedException;
+import org.opends.server.protocols.ldap.LDAPResultCode;
+import org.opends.server.tools.ClientException;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.StringArgument;
+import org.opends.server.util.args.SubCommand;
+import org.opends.server.util.args.SubCommandArgumentParser;
+
+
+
+/**
+ * A sub-command handler which is used to modify the properties of a
+ * managed object.
+ * <p>
+ * This sub-command implements the various set-xxx-prop sub-commands.
+ */
+final class SetPropSubCommandHandler extends SubCommandHandler {
+
+  /**
+   * Type of modication being performed.
+   */
+  private static enum ModificationType {
+    /**
+     * Append a single value to the property.
+     */
+    ADD,
+
+    /**
+     * Remove a single value from the property.
+     */
+    REMOVE,
+
+    /**
+     * Append a single value to the property (first invocation removes
+     * existing values).
+     */
+    SET;
+  }
+
+  /**
+   * The value for the long option add.
+   */
+  private static final String OPTION_DSCFG_LONG_ADD = "add";
+
+  /**
+   * The value for the long option remove.
+   */
+  private static final String OPTION_DSCFG_LONG_REMOVE = "remove";
+
+  /**
+   * The value for the long option reset.
+   */
+  private static final String OPTION_DSCFG_LONG_RESET = "reset";
+
+  /**
+   * The value for the long option set.
+   */
+  private static final String OPTION_DSCFG_LONG_SET = "set";
+
+  /**
+   * The value for the short option add.
+   */
+  private static final Character OPTION_DSCFG_SHORT_ADD = null;
+
+  /**
+   * The value for the short option remove.
+   */
+  private static final Character OPTION_DSCFG_SHORT_REMOVE = null;
+
+  /**
+   * The value for the short option reset.
+   */
+  private static final Character OPTION_DSCFG_SHORT_RESET = null;
+
+  /**
+   * The value for the short option set.
+   */
+  private static final Character OPTION_DSCFG_SHORT_SET = null;
+
+
+
+  /**
+   * Creates a new set-xxx-prop sub-command for an instantiable
+   * relation.
+   *
+   * @param parser
+   *          The sub-command argument parser.
+   * @param path
+   *          The parent managed object path.
+   * @param r
+   *          The instantiable relation.
+   * @return Returns the new set-xxx-prop sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  public static SetPropSubCommandHandler create(
+      SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
+      InstantiableRelationDefinition<?, ?> r) throws ArgumentException {
+    return new SetPropSubCommandHandler(parser, path.child(r, "DUMMY"), r);
+  }
+
+
+
+  /**
+   * Creates a new set-xxx-prop sub-command for an optional relation.
+   *
+   * @param parser
+   *          The sub-command argument parser.
+   * @param path
+   *          The parent managed object path.
+   * @param r
+   *          The optional relation.
+   * @return Returns the new set-xxx-prop sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  public static SetPropSubCommandHandler create(
+      SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
+      OptionalRelationDefinition<?, ?> r) throws ArgumentException {
+    return new SetPropSubCommandHandler(parser, path.child(r), r);
+  }
+
+
+
+  /**
+   * Creates a new set-xxx-prop sub-command for a singleton relation.
+   *
+   * @param parser
+   *          The sub-command argument parser.
+   * @param path
+   *          The parent managed object path.
+   * @param r
+   *          The singleton relation.
+   * @return Returns the new set-xxx-prop sub-command.
+   * @throws ArgumentException
+   *           If the sub-command could not be created successfully.
+   */
+  public static SetPropSubCommandHandler create(
+      SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
+      SingletonRelationDefinition<?, ?> r) throws ArgumentException {
+    return new SetPropSubCommandHandler(parser, path.child(r), r);
+  }
+
+  // The sub-commands naming arguments.
+  private final List<StringArgument> namingArgs;
+
+  // The path of the managed object.
+  private final ManagedObjectPath<?, ?> path;
+
+  // The argument which should be used to specify zero or more
+  // property value adds.
+  private final StringArgument propertyAddArgument;
+
+  // The argument which should be used to specify zero or more
+  // property value removes.
+  private final StringArgument propertyRemoveArgument;
+
+  // The argument which should be used to specify zero or more
+  // property value resets.
+  private final StringArgument propertyResetArgument;
+
+  // The argument which should be used to specify zero or more
+  // property value assignments.
+  private final StringArgument propertySetArgument;
+
+  // The sub-command associated with this handler.
+  private final SubCommand subCommand;
+
+
+
+  // Private constructor.
+  private SetPropSubCommandHandler(SubCommandArgumentParser parser,
+      ManagedObjectPath<?, ?> path, RelationDefinition<?, ?> r)
+      throws ArgumentException {
+    this.path = path;
+
+    // Create the sub-command.
+    String name = "set-" + r.getName() + "-prop";
+    int descriptionID = MSGID_DSCFG_DESCRIPTION_SUBCMD_SETPROP;
+    this.subCommand = new SubCommand(parser, name, false, 0, 0, null,
+        descriptionID, r.getChildDefinition().getUserFriendlyName());
+
+    // Create the naming arguments.
+    this.namingArgs = createNamingArgs(subCommand, path);
+
+    // Create the --set argument.
+    this.propertySetArgument = new StringArgument(OPTION_DSCFG_LONG_SET,
+        OPTION_DSCFG_SHORT_SET, OPTION_DSCFG_LONG_SET, false, true, true,
+        "{PROP:VAL}", null, null, MSGID_DSCFG_DESCRIPTION_PROP_VAL);
+    this.subCommand.addArgument(this.propertySetArgument);
+
+    // Create the --reset argument.
+    this.propertyResetArgument = new StringArgument(OPTION_DSCFG_LONG_RESET,
+        OPTION_DSCFG_SHORT_RESET, OPTION_DSCFG_LONG_RESET, false, true, true,
+        "{PROP}", null, null, MSGID_DSCFG_DESCRIPTION_RESET_PROP);
+    this.subCommand.addArgument(this.propertyResetArgument);
+
+    // Create the --add argument.
+    this.propertyAddArgument = new StringArgument(OPTION_DSCFG_LONG_ADD,
+        OPTION_DSCFG_SHORT_ADD, OPTION_DSCFG_LONG_ADD, false, true, true,
+        "{PROP:VAL}", null, null, MSGID_DSCFG_DESCRIPTION_ADD_PROP_VAL);
+    this.subCommand.addArgument(this.propertyAddArgument);
+
+    // Create the --remove argument.
+    this.propertyRemoveArgument = new StringArgument(OPTION_DSCFG_LONG_REMOVE,
+        OPTION_DSCFG_SHORT_REMOVE, OPTION_DSCFG_LONG_REMOVE, false, true, true,
+        "{PROP:VAL}", null, null, MSGID_DSCFG_DESCRIPTION_REMOVE_PROP_VAL);
+    this.subCommand.addArgument(this.propertyRemoveArgument);
+
+    // Register the tags associated with the child managed objects.
+    addTags(path.getManagedObjectDefinition().getAllTags());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public SubCommand getSubCommand() {
+    return subCommand;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @SuppressWarnings("unchecked")
+  @Override
+  public int run(DSConfig app, PrintStream out, PrintStream err)
+      throws ArgumentException, ClientException {
+    // Get the naming argument values.
+    List<String> names = getNamingArgValues(namingArgs);
+
+    ManagementContext context = app.getManagementContext();
+    ManagedObject<?> child;
+    try {
+      child = getManagedObject(context, path, names);
+    } catch (AuthorizationException e) {
+      int msgID = MSGID_DSCFG_ERROR_MODIFY_AUTHZ;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+          msgID, msg);
+    } catch (DefinitionDecodingException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_CHILD_DDE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn, ufn, ufn);
+      throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+    } catch (ManagedObjectDecodingException e) {
+      // FIXME: should not abort here. Instead, display the errors (if
+      // verbose) and apply the changes to the partial managed object.
+      int msgID = MSGID_DSCFG_ERROR_GET_CHILD_MODE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+    } catch (CommunicationException e) {
+      int msgID = MSGID_DSCFG_ERROR_MODIFY_CE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn, e.getMessage());
+      throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+    } catch (ConcurrentModificationException e) {
+      int msgID = MSGID_DSCFG_ERROR_MODIFY_CME;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
+          msgID, msg);
+    } catch (ManagedObjectNotFoundException e) {
+      int msgID = MSGID_DSCFG_ERROR_GET_CHILD_MONFE;
+      String ufn = path.getManagedObjectDefinition().getUserFriendlyName();
+      String msg = getMessage(msgID, ufn);
+      throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msgID, msg);
+    }
+
+    ManagedObjectDefinition<?, ?> d = child.getManagedObjectDefinition();
+    Map<String, ModificationType> lastModTypes =
+      new HashMap<String, ModificationType>();
+    Map<PropertyDefinition, Set> changes =
+      new HashMap<PropertyDefinition, Set>();
+
+    // Reset properties.
+    for (String m : propertyResetArgument.getValues()) {
+      // Check the property definition.
+      PropertyDefinition<?> pd;
+      try {
+        pd = d.getPropertyDefinition(m);
+      } catch (IllegalArgumentException e) {
+        throw ArgumentExceptionFactory.unknownProperty(d, m);
+      }
+
+      // Save the modification type.
+      lastModTypes.put(m, ModificationType.SET);
+
+      // Apply the modification.
+      modifyPropertyValues(child, pd, changes, ModificationType.SET, null);
+    }
+
+    // Set properties.
+    for (String m : propertySetArgument.getValues()) {
+      // Parse the property "property:value".
+      int sep = m.indexOf(':');
+
+      if (sep < 0) {
+        throw ArgumentExceptionFactory.missingSeparatorInPropertyArgument(m);
+      }
+
+      if (sep == 0) {
+        throw ArgumentExceptionFactory.missingNameInPropertyArgument(m);
+      }
+
+      String propertyName = m.substring(0, sep);
+      String value = m.substring(sep + 1, m.length());
+      if (value.length() == 0) {
+        throw ArgumentExceptionFactory.missingValueInPropertyArgument(m);
+      }
+
+      // Check the property definition.
+      PropertyDefinition<?> pd;
+      try {
+        pd = d.getPropertyDefinition(propertyName);
+      } catch (IllegalArgumentException e) {
+        throw ArgumentExceptionFactory.unknownProperty(d, propertyName);
+      }
+
+      // Apply the modification.
+      if (lastModTypes.containsKey(propertyName)) {
+        modifyPropertyValues(child, pd, changes, ModificationType.ADD, value);
+      } else {
+        lastModTypes.put(propertyName, ModificationType.SET);
+        modifyPropertyValues(child, pd, changes, ModificationType.SET, value);
+      }
+    }
+
+    // Remove properties.
+    for (String m : propertyRemoveArgument.getValues()) {
+      // Parse the property "property:value".
+      int sep = m.indexOf(':');
+
+      if (sep < 0) {
+        throw ArgumentExceptionFactory.missingSeparatorInPropertyArgument(m);
+      }
+
+      if (sep == 0) {
+        throw ArgumentExceptionFactory.missingNameInPropertyArgument(m);
+      }
+
+      String propertyName = m.substring(0, sep);
+      String value = m.substring(sep + 1, m.length());
+      if (value.length() == 0) {
+        throw ArgumentExceptionFactory.missingValueInPropertyArgument(m);
+      }
+
+      // Check the property definition.
+      PropertyDefinition<?> pd;
+      try {
+        pd = d.getPropertyDefinition(propertyName);
+      } catch (IllegalArgumentException e) {
+        throw ArgumentExceptionFactory.unknownProperty(d, propertyName);
+      }
+
+      // Apply the modification.
+      if (lastModTypes.containsKey(propertyName)) {
+        if (lastModTypes.get(propertyName) == ModificationType.SET) {
+          throw ArgumentExceptionFactory.incompatiblePropertyModification(m);
+        }
+      } else {
+        lastModTypes.put(propertyName, ModificationType.REMOVE);
+        modifyPropertyValues(child, pd, changes,
+            ModificationType.REMOVE, value);
+      }
+    }
+
+    // Add properties.
+    for (String m : propertyAddArgument.getValues()) {
+      // Parse the property "property:value".
+      int sep = m.indexOf(':');
+
+      if (sep < 0) {
+        throw ArgumentExceptionFactory.missingSeparatorInPropertyArgument(m);
+      }
+
+      if (sep == 0) {
+        throw ArgumentExceptionFactory.missingNameInPropertyArgument(m);
+      }
+
+      String propertyName = m.substring(0, sep);
+      String value = m.substring(sep + 1, m.length());
+      if (value.length() == 0) {
+        throw ArgumentExceptionFactory.missingValueInPropertyArgument(m);
+      }
+
+      // Check the property definition.
+      PropertyDefinition<?> pd;
+      try {
+        pd = d.getPropertyDefinition(propertyName);
+      } catch (IllegalArgumentException e) {
+        throw ArgumentExceptionFactory.unknownProperty(d, propertyName);
+      }
+
+      // Apply the modification.
+      if (lastModTypes.containsKey(propertyName)) {
+        if (lastModTypes.get(propertyName) == ModificationType.SET) {
+          throw ArgumentExceptionFactory.incompatiblePropertyModification(m);
+        }
+      } else {
+        lastModTypes.put(propertyName, ModificationType.ADD);
+        modifyPropertyValues(child, pd, changes, ModificationType.ADD, value);
+      }
+    }
+
+    // Commit the changes.
+    for (PropertyDefinition<?> pd : changes.keySet()) {
+      try {
+        child.setPropertyValues(pd, changes.get(pd));
+      } catch (PropertyException e) {
+        throw ArgumentExceptionFactory.adaptPropertyException(e, d);
+      }
+    }
+
+    try {
+      // Confirm commit.
+      String prompt = String.format(Messages.getString("modify.confirm"), d
+          .getUserFriendlyName());
+      if (!app.confirmAction(prompt)) {
+        // Output failure message.
+        String msg = String.format(Messages.getString("modify.failed"), d
+            .getUserFriendlyName());
+        app.displayVerboseMessage(msg);
+        return 1;
+      }
+
+      child.commit();
+
+      // Output success message.
+      String msg = String.format(Messages.getString("modify.done"), d
+          .getUserFriendlyName());
+      app.displayVerboseMessage(msg);
+    } catch (MissingMandatoryPropertiesException e) {
+      throw ArgumentExceptionFactory.adaptMissingMandatoryPropertiesException(
+          e, d);
+    } catch (AuthorizationException e) {
+      int msgID = MSGID_DSCFG_ERROR_MODIFY_AUTHZ;
+      String msg = getMessage(msgID, d.getUserFriendlyName());
+      throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+          msgID, msg);
+    } catch (ConcurrentModificationException e) {
+      int msgID = MSGID_DSCFG_ERROR_MODIFY_CME;
+      String msg = getMessage(msgID, d.getUserFriendlyName());
+      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
+          msgID, msg);
+    } catch (OperationRejectedException e) {
+      int msgID = MSGID_DSCFG_ERROR_MODIFY_ORE;
+      String msg = getMessage(msgID, d.getUserFriendlyName(), e.getMessage());
+      throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
+          msgID, msg);
+    } catch (CommunicationException e) {
+      int msgID = MSGID_DSCFG_ERROR_MODIFY_CE;
+      String msg = getMessage(msgID, d.getUserFriendlyName(), e.getMessage());
+      throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msgID, msg);
+    } catch (ManagedObjectAlreadyExistsException e) {
+      // Should never happen.
+      throw new IllegalStateException(e);
+    }
+
+    return 0;
+  }
+
+
+
+  // Apply a single modification to the current change-set.
+  @SuppressWarnings("unchecked")
+  private <T> void modifyPropertyValues(ManagedObject<?> mo,
+      PropertyDefinition<T> pd, Map<PropertyDefinition, Set> changes,
+      ModificationType modType, String s) throws ArgumentException {
+    Set<T> values = changes.get(pd);
+    if (values == null) {
+      values = mo.getPropertyValues(pd);
+    }
+
+    if (s == null || s.length() == 0) {
+      // Reset back to defaults.
+      values.clear();
+    } else {
+      T value;
+      try {
+        value = pd.decodeValue(s);
+      } catch (IllegalPropertyValueStringException e) {
+        throw ArgumentExceptionFactory.adaptPropertyException(e, mo
+            .getManagedObjectDefinition());
+      }
+
+      switch (modType) {
+      case ADD:
+        values.add(value);
+        break;
+      case REMOVE:
+        values.remove(value);
+        break;
+      case SET:
+        values = new TreeSet<T>(pd);
+        values.add(value);
+        break;
+      }
+    }
+
+    changes.put(pd, values);
+  }
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/SubCommandBuilder.java b/opends/src/server/org/opends/server/tools/dsconfig/SubCommandBuilder.java
new file mode 100644
index 0000000..6a5defb
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/SubCommandBuilder.java
@@ -0,0 +1,294 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.AggregationRelationDefinition;
+import org.opends.server.admin.Configuration;
+import org.opends.server.admin.ConfigurationClient;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.RelationDefinitionVisitor;
+import org.opends.server.admin.SingletonRelationDefinition;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.SubCommandArgumentParser;
+
+
+
+/**
+ * A relation definition visitor which is used to determine the
+ * run-time sub-commands which are available.
+ */
+final class SubCommandBuilder {
+
+  /**
+   * A relation definition visitor used to recursively determine the
+   * set of available sub-commands.
+   */
+  private static final class Visitor implements
+      RelationDefinitionVisitor<Void, ManagedObjectPath<?, ?>> {
+
+    // Any exception that occurred whilst creating the sub-commands.
+    private ArgumentException exception = null;
+
+    // The set of available sub-commands.
+    private List<SubCommandHandler> handlers = null;
+
+    // The help sub-command handler.
+    private HelpSubCommandHandler helpHandler = null;
+
+    // The sub-command argument parser.
+    private final SubCommandArgumentParser parser;
+
+    // Private constructor.
+    private Visitor(SubCommandArgumentParser parser) {
+      this.parser = parser;
+    }
+
+
+
+    /**
+     * Get the constructed list of sub-commands handlers.
+     *
+     * @return Returns the constructed list of sub-commands handlers.
+     * @throws ArgumentException
+     *           If a sub-command could not be created successfully.
+     */
+    public List<SubCommandHandler> getSubCommandHandlers()
+        throws ArgumentException {
+      if (handlers == null) {
+        handlers = new LinkedList<SubCommandHandler>();
+
+        // We always need a help properties sub-command handler.
+        helpHandler = HelpSubCommandHandler.create(parser);
+        handlers.add(helpHandler);
+
+        processPath(ManagedObjectPath.emptyPath());
+      }
+
+      if (exception != null) {
+        throw exception;
+      }
+
+      return handlers;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Void visitAggregation(AggregationRelationDefinition<?, ?> r,
+        ManagedObjectPath<?, ?> p) {
+      // Do not create sub-commands for aggregations.
+      return null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Void visitInstantiable(InstantiableRelationDefinition<?, ?> r,
+        ManagedObjectPath<?, ?> p) {
+      try {
+        // Create the sub-commands.
+        handlers.add(CreateSubCommandHandler.create(parser, p, r));
+        handlers.add(DeleteSubCommandHandler.create(parser, p, r));
+        handlers.add(ListSubCommandHandler.create(parser, p, r));
+        handlers.add(GetPropSubCommandHandler.create(parser, p, r));
+        handlers.add(SetPropSubCommandHandler.create(parser, p, r));
+
+        // Process the referenced managed object definition and its
+        // sub-types.
+        processRelation(p, r);
+      } catch (ArgumentException e) {
+        exception = e;
+      }
+
+      return null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Void visitOptional(OptionalRelationDefinition<?, ?> r,
+        ManagedObjectPath<?, ?> p) {
+      try {
+        // Create the sub-commands.
+        handlers.add(CreateSubCommandHandler.create(parser, p, r));
+        handlers.add(DeleteSubCommandHandler.create(parser, p, r));
+        handlers.add(ListSubCommandHandler.create(parser, p, r));
+        handlers.add(GetPropSubCommandHandler.create(parser, p, r));
+        handlers.add(SetPropSubCommandHandler.create(parser, p, r));
+
+        // Process the referenced managed object definition and its
+        // sub-types.
+        processRelation(p, r);
+      } catch (ArgumentException e) {
+        exception = e;
+      }
+
+      return null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Void visitSingleton(SingletonRelationDefinition<?, ?> r,
+        ManagedObjectPath<?, ?> p) {
+      try {
+        // Create the sub-commands.
+        handlers.add(GetPropSubCommandHandler.create(parser, p, r));
+        handlers.add(SetPropSubCommandHandler.create(parser, p, r));
+
+        // Process the referenced managed object definition and its
+        // sub-types.
+        processRelation(p, r);
+      } catch (ArgumentException e) {
+        exception = e;
+      }
+
+      return null;
+    }
+
+
+
+    // Process the relations associated with the managed object
+    // definition identified by the provided path.
+    private void processPath(ManagedObjectPath<?, ?> path) {
+      AbstractManagedObjectDefinition<?, ?> d = path
+          .getManagedObjectDefinition();
+
+      // Do not process inherited relation definitions.
+      for (RelationDefinition<?, ?> r : d.getRelationDefinitions()) {
+        r.accept(this, path);
+      }
+    }
+
+
+
+    // Process an instantiable relation.
+    private <C extends ConfigurationClient, S extends Configuration>
+        void processRelation(
+        ManagedObjectPath<?, ?> path, InstantiableRelationDefinition<C, S> r) {
+      AbstractManagedObjectDefinition<C, S> d = r.getChildDefinition();
+
+      // Process all relations associated directly with this definition.
+      helpHandler.registerManagedObjectDefinition(d);
+      processPath(path.child(r, d, "DUMMY"));
+
+      // Now process relations associated with derived definitions.
+      for (AbstractManagedObjectDefinition<? extends C, ? extends S> c : d
+          .getAllChildren()) {
+        helpHandler.registerManagedObjectDefinition(c);
+        processPath(path.child(r, c, "DUMMY"));
+      }
+    }
+
+
+
+    // Process an optional relation.
+    private <C extends ConfigurationClient, S extends Configuration>
+        void processRelation(
+        ManagedObjectPath<?, ?> path, OptionalRelationDefinition<C, S> r) {
+      AbstractManagedObjectDefinition<C, S> d = r.getChildDefinition();
+
+      // Process all relations associated directly with this definition.
+      helpHandler.registerManagedObjectDefinition(d);
+      processPath(path.child(r, d));
+
+      // Now process relations associated with derived definitions.
+      for (AbstractManagedObjectDefinition<? extends C, ? extends S> c : d
+          .getAllChildren()) {
+        helpHandler.registerManagedObjectDefinition(c);
+        processPath(path.child(r, c));
+      }
+    }
+
+
+
+    // Process a singleton relation.
+    private <C extends ConfigurationClient, S extends Configuration>
+        void processRelation(
+        ManagedObjectPath<?, ?> path, SingletonRelationDefinition<C, S> r) {
+      AbstractManagedObjectDefinition<C, S> d = r.getChildDefinition();
+
+      // Process all relations associated directly with this definition.
+      helpHandler.registerManagedObjectDefinition(d);
+      processPath(path.child(r, d));
+
+      // Now process relations associated with derived definitions.
+      for (AbstractManagedObjectDefinition<? extends C, ? extends S> c : d
+          .getAllChildren()) {
+        helpHandler.registerManagedObjectDefinition(c);
+        processPath(path.child(r, c));
+      }
+    }
+
+  }
+
+
+
+  /**
+   * Create a new sub-command builder.
+   */
+  public SubCommandBuilder() {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * Get the set of sub-command handlers constructed by this builder.
+   *
+   * @param parser
+   *          The sub-command argument parser.
+   * @return Returns the set of sub-command handlers constructed by
+   *         this builder.
+   * @throws ArgumentException
+   *           If a sub-command could not be created successfully.
+   */
+  public Collection<SubCommandHandler> getSubCommandHandlers(
+      SubCommandArgumentParser parser) throws ArgumentException {
+    Visitor v = new Visitor(parser);
+    return v.getSubCommandHandlers();
+  }
+
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java
new file mode 100644
index 0000000..a393f3d
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java
@@ -0,0 +1,858 @@
+/*
+ * 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.tools.dsconfig;
+
+
+
+import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.ToolMessages.*;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.Configuration;
+import org.opends.server.admin.ConfigurationClient;
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.DurationUnit;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.ManagedObjectPathSerializer;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.SingletonRelationDefinition;
+import org.opends.server.admin.SizeUnit;
+import org.opends.server.admin.Tag;
+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.ManagedObject;
+import org.opends.server.admin.client.ManagedObjectDecodingException;
+import org.opends.server.admin.client.ManagementContext;
+import org.opends.server.tools.ClientException;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.BooleanArgument;
+import org.opends.server.util.args.StringArgument;
+import org.opends.server.util.args.SubCommand;
+import org.opends.server.util.table.TabSeparatedTablePrinter;
+import org.opends.server.util.table.TablePrinter;
+
+
+
+/**
+ * An interface for sub-command implementations.
+ */
+abstract class SubCommandHandler {
+
+  /**
+   * A path serializer which is used to retrieve a managed object
+   * based on a path and a list of path arguments.
+   */
+  private static class ManagedObjectFinder implements
+      ManagedObjectPathSerializer {
+
+    // Any argument exception that was caught when attempting to find
+    // the
+    // managed object.
+    private ArgumentException ae;
+
+    // The index of the next path argument to be retrieved.
+    private int argIndex;
+
+    // The list of managed object path arguments.
+    private List<String> args;
+
+    private AuthorizationException authze;
+
+    private CommunicationException ce;
+
+    private ConcurrentModificationException cme;
+
+    // Any operation exception that was caught when attempting to find
+    // the
+    // managed object.
+    private DefinitionDecodingException dde;
+
+    // Flag indicating whether or not an exception occurred during
+    // retrieval.
+    private boolean gotException;
+
+    // The last managed object retrieved.
+    private ManagedObject<?> managedObject;
+
+    private ManagedObjectDecodingException mode;
+
+    private ManagedObjectNotFoundException monfe;
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <C extends ConfigurationClient, S extends Configuration>
+        void appendManagedObjectPathElement(
+        InstantiableRelationDefinition<? super C, ? super S> r,
+        AbstractManagedObjectDefinition<C, S> d, String name) {
+      if (!gotException) {
+        // We should ignore the "template" name here and use a path
+        // argument.
+        String childName = args.get(argIndex++);
+
+        try {
+          ManagedObject<?> child = managedObject.getChild(r, childName);
+
+          // Check that child is a sub-type of the specified
+          // definition.
+          if (!child.getManagedObjectDefinition().isChildOf(d)) {
+            ae = ArgumentExceptionFactory.wrongManagedObjectType(r, child
+                .getManagedObjectDefinition());
+            gotException = true;
+          } else {
+            managedObject = child;
+          }
+        } catch (DefinitionDecodingException e) {
+          dde = e;
+          gotException = true;
+        } catch (ManagedObjectDecodingException e) {
+          mode = e;
+          gotException = true;
+        } catch (AuthorizationException e) {
+          authze = e;
+          gotException = true;
+        } catch (ManagedObjectNotFoundException e) {
+          monfe = e;
+          gotException = true;
+        } catch (ConcurrentModificationException e) {
+          cme = e;
+          gotException = true;
+        } catch (CommunicationException e) {
+          ce = e;
+          gotException = true;
+        }
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <C extends ConfigurationClient, S extends Configuration>
+        void appendManagedObjectPathElement(
+        OptionalRelationDefinition<? super C, ? super S> r,
+        AbstractManagedObjectDefinition<C, S> d) {
+      if (!gotException) {
+        try {
+          ManagedObject<?> child = managedObject.getChild(r);
+
+          // Check that child is a sub-type of the specified
+          // definition.
+          if (!child.getManagedObjectDefinition().isChildOf(d)) {
+            ae = ArgumentExceptionFactory.wrongManagedObjectType(r, child
+                .getManagedObjectDefinition());
+            gotException = true;
+          } else {
+            managedObject = child;
+          }
+        } catch (DefinitionDecodingException e) {
+          dde = e;
+          gotException = true;
+        } catch (ManagedObjectDecodingException e) {
+          mode = e;
+          gotException = true;
+        } catch (AuthorizationException e) {
+          authze = e;
+          gotException = true;
+        } catch (ManagedObjectNotFoundException e) {
+          monfe = e;
+          gotException = true;
+        } catch (ConcurrentModificationException e) {
+          cme = e;
+          gotException = true;
+        } catch (CommunicationException e) {
+          ce = e;
+          gotException = true;
+        }
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <C extends ConfigurationClient, S extends Configuration>
+        void appendManagedObjectPathElement(
+        SingletonRelationDefinition<? super C, ? super S> r,
+        AbstractManagedObjectDefinition<C, S> d) {
+      if (!gotException) {
+        try {
+          ManagedObject<?> child = managedObject.getChild(r);
+
+          // Check that child is a sub-type of the specified
+          // definition.
+          if (!child.getManagedObjectDefinition().isChildOf(d)) {
+            ae = ArgumentExceptionFactory.wrongManagedObjectType(r, child
+                .getManagedObjectDefinition());
+            gotException = true;
+          } else {
+            managedObject = child;
+          }
+        } catch (DefinitionDecodingException e) {
+          dde = e;
+          gotException = true;
+        } catch (ManagedObjectDecodingException e) {
+          mode = e;
+          gotException = true;
+        } catch (AuthorizationException e) {
+          authze = e;
+          gotException = true;
+        } catch (ManagedObjectNotFoundException e) {
+          monfe = e;
+          gotException = true;
+        } catch (ConcurrentModificationException e) {
+          cme = e;
+          gotException = true;
+        } catch (CommunicationException e) {
+          ce = e;
+          gotException = true;
+        }
+      }
+    }
+
+
+
+    /**
+     * Finds the named managed object.
+     *
+     * @param context
+     *          The management context.
+     * @param path
+     *          The managed object path.
+     * @param args
+     *          The managed object path arguments.
+     * @return Returns the named managed object.
+     * @throws ArgumentException
+     *           If one of the naming arguments referenced a managed
+     *           object of the wrong type.
+     * @throws DefinitionDecodingException
+     *           If the managed object was found but its type could
+     *           not be determined.
+     * @throws ManagedObjectDecodingException
+     *           If the managed object was found but one or more of
+     *           its properties could not be decoded.
+     * @throws ManagedObjectNotFoundException
+     *           If the requested managed object could not be found on
+     *           the server.
+     * @throws ConcurrentModificationException
+     *           If this managed object has been removed from the
+     *           server by another client.
+     * @throws AuthorizationException
+     *           If the server refuses to retrieve the managed object
+     *           because the client does not have the correct
+     *           privileges.
+     * @throws CommunicationException
+     *           If the client cannot contact the server due to an
+     *           underlying communication problem.
+     */
+    public ManagedObject<?> find(ManagementContext context,
+        ManagedObjectPath<?, ?> path, List<String> args)
+        throws ArgumentException, CommunicationException,
+        AuthorizationException, ConcurrentModificationException,
+        DefinitionDecodingException, ManagedObjectDecodingException,
+        ManagedObjectNotFoundException {
+      this.managedObject = context.getRootConfigurationManagedObject();
+      this.args = args;
+      this.argIndex = 0;
+
+      this.gotException = false;
+      this.ae = null;
+      this.authze = null;
+      this.ce = null;
+      this.cme = null;
+      this.dde = null;
+      this.mode = null;
+      this.monfe = null;
+
+      path.serialize(this);
+
+      if (ae != null) {
+        throw ae;
+      } else if (authze != null) {
+        throw authze;
+      } else if (ce != null) {
+        throw ce;
+      } else if (cme != null) {
+        throw cme;
+      } else if (dde != null) {
+        throw dde;
+      } else if (mode != null) {
+        throw mode;
+      } else if (monfe != null) {
+        throw monfe;
+      } else {
+        return managedObject;
+      }
+    }
+  }
+
+
+
+  /**
+   * A path serializer which is used to register a sub-command's
+   * naming arguments.
+   */
+  private static class NamingArgumentBuilder implements
+      ManagedObjectPathSerializer {
+
+    /**
+     * Creates the naming arguments for a given path.
+     *
+     * @param subCommand
+     *          The sub-command.
+     * @param path
+     *          The managed object path.
+     * @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);
+      path.serialize(builder);
+
+      if (builder.e != null) {
+        throw builder.e;
+      }
+
+      return builder.arguments;
+    }
+
+    // The list of naming arguments.
+    private final List<StringArgument> arguments =
+      new LinkedList<StringArgument>();
+
+    // Any argument exception thrown when creating the naming
+    // arguments.
+    private ArgumentException e = null;
+
+    // The sub-command.
+    private final SubCommand subCommand;
+
+
+
+    /**
+     * Creates a new naming argument builder.
+     *
+     * @param subCommand
+     *          Add the naming arguments to this sub-command.
+     */
+    public NamingArgumentBuilder(SubCommand subCommand) {
+      this.subCommand = subCommand;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <C extends ConfigurationClient, S extends Configuration>
+        void appendManagedObjectPathElement(
+        InstantiableRelationDefinition<? super C, ? super S> r,
+        AbstractManagedObjectDefinition<C, S> d, String name) {
+      // Use the last word in the managed object name as the argument
+      // prefix.
+      StringBuilder builder = new StringBuilder();
+
+      String s = d.getName();
+      int i = s.lastIndexOf('-');
+      if (i < 0 || i == (s.length() - 1)) {
+        builder.append(s);
+      } else {
+        builder.append(s.substring(i + 1));
+      }
+      builder.append("-name");
+      String argName = builder.toString();
+
+      try {
+        StringArgument arg = new StringArgument(argName, null, argName, true,
+            true, "{NAME}", MSGID_DSCFG_DESCRIPTION_NAME, d
+                .getUserFriendlyName());
+
+        subCommand.addArgument(arg);
+        arguments.add(arg);
+      } catch (ArgumentException e) {
+        this.e = e;
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <C extends ConfigurationClient, S extends Configuration>
+        void appendManagedObjectPathElement(
+        OptionalRelationDefinition<? super C, ? super S> r,
+        AbstractManagedObjectDefinition<C, S> d) {
+      // No implementation required.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <C extends ConfigurationClient, S extends Configuration>
+        void appendManagedObjectPathElement(
+        SingletonRelationDefinition<? super C, ? super S> r,
+        AbstractManagedObjectDefinition<C, S> d) {
+      // No implementation required.
+    }
+
+  }
+
+  /**
+   * The value for the long option property.
+   */
+  private static final String OPTION_DSCFG_LONG_PROPERTY = "property";
+
+  /**
+   * The value for the long option record.
+   */
+  private static final String OPTION_DSCFG_LONG_RECORD = "record";
+
+  /**
+   * The value for the long option unit-size.
+   */
+  private static final String OPTION_DSCFG_LONG_UNIT_SIZE = "unit-size";
+
+  /**
+   * The value for the long option unit-time.
+   */
+  private static final String OPTION_DSCFG_LONG_UNIT_TIME = "unit-time";
+
+  /**
+   * The value for the short option property.
+   */
+  private static final Character OPTION_DSCFG_SHORT_PROPERTY = null;
+
+  /**
+   * The value for the short option record.
+   */
+  private static final char OPTION_DSCFG_SHORT_RECORD = 'E';
+
+  /**
+   * The value for the short option unit-size.
+   */
+  private static final char OPTION_DSCFG_SHORT_UNIT_SIZE = 'Z';
+
+  /**
+   * The value for the short option unit-time.
+   */
+  private static final char OPTION_DSCFG_SHORT_UNIT_TIME = 'M';
+
+  // The argument which should be used to specify zero or more
+  // property names.
+  private StringArgument propertyArgument;
+
+  // The argument which should be used to request record mode.
+  private BooleanArgument recordModeArgument;
+
+  // The tags associated with this sub-command handler.
+  private final Set<Tag> tags = new HashSet<Tag>();
+
+  // The argument which should be used to request specific size units.
+  private StringArgument unitSizeArgument;
+
+  // The argument which should be used to request specific time units.
+  private StringArgument unitTimeArgument;
+
+
+
+  /**
+   * Create a new sub-command handler.
+   */
+  protected SubCommandHandler() {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * Gets the sub-command associated with this handler.
+   *
+   * @return Returns the sub-command associated with this handler.
+   */
+  public abstract SubCommand getSubCommand();
+
+
+
+  /**
+   * Gets the tags associated with this sub-command handler.
+   *
+   * @return Returns the tags associated with this sub-command
+   *         handler.
+   */
+  public final Set<Tag> getTags() {
+    return tags;
+  }
+
+
+
+  /**
+   * Run this sub-command handler.
+   *
+   * @param app
+   *          The application.
+   * @param out
+   *          The application output stream.
+   * @param err
+   *          The application error stream.
+   * @return Returns zero if the sub-command completed successfully or
+   *         non-zero if it did not.
+   * @throws ArgumentException
+   *           If an argument required by the sub-command could not be
+   *           parsed successfully.
+   * @throws ClientException
+   *           If the management context could not be created.
+   */
+  public abstract int run(DSConfig app, PrintStream out, PrintStream err)
+      throws ArgumentException, ClientException;
+
+
+
+  /**
+   * Get the string representation of this sub-command handler.
+   * <p>
+   * The string representation is simply the sub-command's name.
+   *
+   * @return Returns the string representation of this sub-command
+   *         handler.
+   */
+  @Override
+  public final String toString() {
+    return getSubCommand().getName();
+  }
+
+
+
+  /**
+   * Adds one or more tags to this sub-command handler.
+   *
+   * @param tags
+   *          The tags to be added to this sub-command handler.
+   */
+  protected final void addTags(Collection<Tag> tags) {
+    this.tags.addAll(tags);
+  }
+
+
+
+  /**
+   * Adds one or more tags to this sub-command handler.
+   *
+   * @param tags
+   *          The tags to be added to this sub-command handler.
+   */
+  protected final void addTags(Tag... tags) {
+    addTags(Arrays.asList(tags));
+  }
+
+
+
+  /**
+   * Creates the naming arguments for a given path and registers them.
+   *
+   * @param subCommand
+   *          The sub-command.
+   * @param p
+   *          The managed object path.
+   * @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);
+  }
+
+
+
+  /**
+   * Creates a script-friendly table printer. This factory method
+   * should be used by sub-command handler implementations rather than
+   * constructing a table printer directly so that we can easily
+   * switch table implementations (perhaps dynamically depending on
+   * argument).
+   *
+   * @param stream
+   *          The output stream for the table.
+   * @return Returns a script-friendly table printer.
+   */
+  protected final TablePrinter createScriptFriendlyTablePrinter(
+      PrintStream stream) {
+    return new TabSeparatedTablePrinter(stream);
+  }
+
+
+
+  /**
+   * Get the managed object referenced by the provided managed object
+   * path.
+   *
+   * @param context
+   *          The management context.
+   * @param path
+   *          The managed object path.
+   * @param args
+   *          The list of managed object names required by the path.
+   * @return Returns the managed object referenced by the provided
+   *         managed object path.
+   * @throws DefinitionDecodingException
+   *           If the managed object was found but its type could not
+   *           be determined.
+   * @throws ManagedObjectDecodingException
+   *           If the managed object was found but one or more of its
+   *           properties could not be decoded.
+   * @throws ManagedObjectNotFoundException
+   *           If the requested managed object could not be found on
+   *           the server.
+   * @throws ConcurrentModificationException
+   *           If this managed object has been removed from the server
+   *           by another client.
+   * @throws AuthorizationException
+   *           If the server refuses to retrieve the managed object
+   *           because the client does not have the correct
+   *           privileges.
+   * @throws CommunicationException
+   *           If the client cannot contact the server due to an
+   *           underlying communication problem.
+   * @throws ArgumentException
+   *           If one of the naming arguments referenced a managed
+   *           object of the wrong type.
+   */
+  protected final ManagedObject<?> getManagedObject(ManagementContext context,
+      ManagedObjectPath<?, ?> path, List<String> args)
+      throws ArgumentException, AuthorizationException,
+      DefinitionDecodingException, ManagedObjectDecodingException,
+      CommunicationException, ConcurrentModificationException,
+      ManagedObjectNotFoundException {
+    ManagedObjectFinder finder = new ManagedObjectFinder();
+    return finder.find(context, path, args);
+  }
+
+
+
+  /**
+   * Gets the values of the naming arguments.
+   *
+   * @param namingArgs
+   *          The naming arguments.
+   * @return Returns the values of the naming arguments.
+   */
+  protected final List<String> getNamingArgValues(
+      List<StringArgument> namingArgs) {
+    ArrayList<String> values = new ArrayList<String>(namingArgs.size());
+    for (StringArgument arg : namingArgs) {
+      values.add(arg.getValue());
+    }
+    return values;
+  }
+
+
+
+  /**
+   * Gets the optional list of property names that the user requested.
+   *
+   * @return Returns the optional list of property names that the user
+   *         requested.
+   */
+  protected final Set<String> getPropertyNames() {
+    if (propertyArgument != null) {
+      return new LinkedHashSet<String>(propertyArgument.getValues());
+    } else {
+      return Collections.emptySet();
+    }
+  }
+
+
+
+  /**
+   * Gets the optional size unit that the user requested.
+   *
+   * @return Returns the size unit that the user requested, or
+   *         <code>null</code> if no size unit was specified.
+   * @throws ArgumentException
+   *           If the user specified an invalid size unit.
+   */
+  protected final SizeUnit getSizeUnit() throws ArgumentException {
+    if (unitSizeArgument != null) {
+      String value = unitSizeArgument.getValue();
+
+      if (value != null) {
+        try {
+          return SizeUnit.getUnit(value);
+        } catch (IllegalArgumentException e) {
+          int msgID = MSGID_DSCFG_ERROR_SIZE_UNIT_UNRECOGNIZED;
+          String msg = getMessage(msgID, value);
+          throw new ArgumentException(msgID, msg);
+        }
+      }
+    }
+
+    return null;
+  }
+
+
+
+  /**
+   * Gets the optional time unit that the user requested.
+   *
+   * @return Returns the time unit that the user requested, or
+   *         <code>null</code> if no time unit was specified.
+   * @throws ArgumentException
+   *           If the user specified an invalid time unit.
+   */
+  protected final DurationUnit getTimeUnit() throws ArgumentException {
+    if (unitTimeArgument != null) {
+      String value = unitTimeArgument.getValue();
+
+      if (value != null) {
+        try {
+          return DurationUnit.getUnit(value);
+        } catch (IllegalArgumentException e) {
+          int msgID = MSGID_DSCFG_ERROR_TIME_UNIT_UNRECOGNIZED;
+          String msg = getMessage(msgID, value);
+          throw new ArgumentException(msgID, msg);
+        }
+      }
+    }
+
+    return null;
+  }
+
+
+
+  /**
+   * Determines whether the user requested record-mode.
+   *
+   * @return Returns <code>true</code> if the user requested
+   *         record-mode.
+   */
+  protected final boolean isRecordMode() {
+    if (recordModeArgument != null) {
+      return recordModeArgument.isPresent();
+    } else {
+      return false;
+    }
+  }
+
+
+
+  /**
+   * Registers the property name argument with the sub-command.
+   *
+   * @param subCommand
+   *          The sub-command.
+   * @throws ArgumentException
+   *           If the property name argument could not be registered.
+   */
+  protected final void registerPropertyNameArgument(SubCommand subCommand)
+      throws ArgumentException {
+    this.propertyArgument = new StringArgument(OPTION_DSCFG_LONG_PROPERTY,
+        OPTION_DSCFG_SHORT_PROPERTY, OPTION_DSCFG_LONG_PROPERTY, false, true,
+        true, "{PROP}", null, null, MSGID_DSCFG_DESCRIPTION_PROP);
+    subCommand.addArgument(propertyArgument);
+  }
+
+
+
+  /**
+   * Registers the record mode argument with the sub-command.
+   *
+   * @param subCommand
+   *          The sub-command.
+   * @throws ArgumentException
+   *           If the record mode argument could not be registered.
+   */
+  protected final void registerRecordModeArgument(SubCommand subCommand)
+      throws ArgumentException {
+    this.recordModeArgument = new BooleanArgument(OPTION_DSCFG_LONG_RECORD,
+        OPTION_DSCFG_SHORT_RECORD, OPTION_DSCFG_LONG_RECORD,
+        MSGID_DSCFG_DESCRIPTION_RECORD);
+    subCommand.addArgument(recordModeArgument);
+  }
+
+
+
+  /**
+   * Registers the unit-size argument with the sub-command.
+   *
+   * @param subCommand
+   *          The sub-command.
+   * @throws ArgumentException
+   *           If the unit-size argument could not be registered.
+   */
+  protected final void registerUnitSizeArgument(SubCommand subCommand)
+      throws ArgumentException {
+    this.unitSizeArgument = new StringArgument(OPTION_DSCFG_LONG_UNIT_SIZE,
+        OPTION_DSCFG_SHORT_UNIT_SIZE, OPTION_DSCFG_LONG_UNIT_SIZE, false, true,
+        "{UNIT}", MSGID_DSCFG_DESCRIPTION_UNIT_SIZE);
+
+    subCommand.addArgument(unitSizeArgument);
+  }
+
+
+
+  /**
+   * Registers the unit-time argument with the sub-command.
+   *
+   * @param subCommand
+   *          The sub-command.
+   * @throws ArgumentException
+   *           If the unit-time argument could not be registered.
+   */
+  protected final void registerUnitTimeArgument(SubCommand subCommand)
+      throws ArgumentException {
+    this.unitTimeArgument = new StringArgument(OPTION_DSCFG_LONG_UNIT_TIME,
+        OPTION_DSCFG_SHORT_UNIT_TIME, OPTION_DSCFG_LONG_UNIT_TIME, false, true,
+        "{UNIT}", MSGID_DSCFG_DESCRIPTION_UNIT_TIME);
+
+    subCommand.addArgument(unitTimeArgument);
+  }
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/messages.properties b/opends/src/server/org/opends/server/tools/dsconfig/messages.properties
new file mode 100644
index 0000000..90875b7
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/messages.properties
@@ -0,0 +1,38 @@
+general.no=no
+general.yes=yes
+general.confirm.error=Invalid response. Please enter "%s" or "%s".
+help-properties.field.enum=one of the following values:
+help-properties.field.undefined=undefined
+help-properties.field.inherits.abs=inherits from the property "%s" in the %s.
+help-properties.field.inherits.parent=inherits from the property "%s" in the parent %s
+help-properties.field.inherits.this=inherits from the property "%s" in this %s
+help-properties.field.server.restart=The server must be restarted in order for changes to this property to take effect.
+help-properties.field.component.restart=The %s must be restarted in order for changes to this property to take effect.
+help-properties.field.read-only=read-only - this property can only be specified when the %s is created
+help-properties.field.monitoring=monitoring - this property is automatically generated by the server
+help-properties.heading.property=Property: %s
+help-properties.heading.managed-object=Managed Object: %s
+help-properties.heading.default=Default behavior
+help-properties.heading.mandatory=Mandatory
+help-properties.heading.multi-valued=Multi-valued
+help-properties.heading.read-only=Read-only
+help-properties.heading.syntax=Syntax
+help-properties.description.options=Option Types:
+help-properties.description.read=Property value(s) are readable
+help-properties.description.write=Property value(s) are writable
+help-properties.description.mandatory=The property is mandatory
+help-properties.description.single-valued=The property is single-valued
+help-properties.description.admin-action=Administrative action is required for changes to take effect
+create.confirm=Are you sure that you want to create the %s?
+delete.confirm=Are you sure that you want to delete the %s?
+modify.confirm=Are you sure that you want to modify the %s?
+create.done=The %s was created successfully.
+delete.done=The %s was deleted successfully.
+modify.done=The %s was modified successfully.
+create.failed=The %s was not created.
+delete.failed=The %s was not deleted.
+modify.failed=The %s was not modified.
+property-reader.prompt1.singular=Specify a value for "%s" whose current value is %s
+property-reader.prompt1.plural=Specify values for "%s" whose current values are %s
+property-reader.prompt2=New value (press RETURN to accept, or ? for help):
+property-reader.mandatory=The property "%s" is mandatory and must be specified.
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/package-info.java b/opends/src/server/org/opends/server/tools/dsconfig/package-info.java
new file mode 100644
index 0000000..9540704
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/package-info.java
@@ -0,0 +1,35 @@
+/*
+ * 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 2006-2007 Sun Microsystems, Inc.
+ */
+
+
+
+/**
+ * This package contains the implementation of the directory server
+ * configuration tool.
+ */
+package org.opends.server.tools.dsconfig;
+

--
Gitblit v1.10.0