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