From eaa23f4b7af97c108ecffa40c86c32e723a90594 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Wed, 29 Aug 2007 14:40:34 +0000
Subject: [PATCH] Fix issue 1831: dsconfig interactive mode.
---
opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java | 2
opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java | 69
opends/src/server/org/opends/server/util/cli/MenuBuilder.java | 818 ++++++
opends/src/server/org/opends/server/util/cli/MenuCallback.java | 21
opends/src/server/org/opends/server/util/cli/HelpCallback.java | 4
opends/src/server/org/opends/server/util/cli/OutputStreamConsoleApplication.java | 105
opends/src/messages/messages/utility.properties | 28
opends/src/messages/src/org/opends/messages/Category.java | 6
opends/src/server/org/opends/server/util/cli/ValidationCallback.java | 10
opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java | 4
opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java | 437 ++-
opends/src/server/org/opends/server/util/cli/ErrorStreamConsoleApplication.java | 105
opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java | 91
opends/src/server/org/opends/server/tools/dsconfig/PropertyValueEditor.java | 1888 ++++++++++++++
opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliParser.java | 2
opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliGlobalAdmin.java | 1
opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java | 11
opends/src/server/org/opends/server/util/cli/MenuResult.java | 324 ++
opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java | 323 +
opends/src/server/org/opends/server/util/cli/Menu.java | 52
opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java | 426 ++
opends/src/server/org/opends/server/tools/dsconfig/PropertyValuePrinter.java | 88
opends/src/server/org/opends/server/tools/dsconfig/LDAPManagementContextFactory.java | 147 +
opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java | 98
opends/src/server/org/opends/server/util/cli/CLIException.java | 92
opends/src/messages/messages/dsconfig.properties | 409 +++
opends/src/messages/messages/tools.properties | 301 --
opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandlerFactory.java | 357 ++
opends/src/server/org/opends/server/admin/client/ManagedObject.java | 19
opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliMain.java | 1
opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java | 218 +
/dev/null | 304 --
opends/src/server/org/opends/server/tools/dsconfig/ManagementContextFactory.java | 1
opends/src/server/org/opends/server/util/cli/package-info.java | 29
opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliServer.java | 1
opends/build.xml | 3
opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java | 150
opends/src/server/org/opends/server/tools/DBTest.java | 2
opends/src/server/org/opends/server/tools/dsconfig/InternalManagementContextFactory.java | 1
opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java | 312 +
opends/src/server/org/opends/server/util/cli/ConsoleApplication.java | 453 +++
41 files changed, 6,296 insertions(+), 1,417 deletions(-)
diff --git a/opends/build.xml b/opends/build.xml
index 9a4e320..7b71e47 100644
--- a/opends/build.xml
+++ b/opends/build.xml
@@ -214,6 +214,9 @@
<genmsg sourceProps="${msg.prop.dir}/core.properties"
destJava="${msg.javagen.dir}/org/opends/messages/CoreMessages.java">
</genmsg>
+ <genmsg sourceProps="${msg.prop.dir}/dsconfig.properties"
+ destJava="${msg.javagen.dir}/org/opends/messages/DSConfigMessages.java">
+ </genmsg>
<genmsg sourceProps="${msg.prop.dir}/extension.properties"
destJava="${msg.javagen.dir}/org/opends/messages/ExtensionMessages.java">
</genmsg>
diff --git a/opends/src/messages/messages/dsconfig.properties b/opends/src/messages/messages/dsconfig.properties
new file mode 100644
index 0000000..0cf9cc7
--- /dev/null
+++ b/opends/src/messages/messages/dsconfig.properties
@@ -0,0 +1,409 @@
+# 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.
+
+
+
+#
+# Global directives
+#
+global.category=DSCONFIG
+
+#
+# Format string definitions
+#
+# Keys must be formatted as follows:
+#
+# [SEVERITY]_[DESCRIPTION]_[ORDINAL]
+#
+# where:
+#
+# SEVERITY is one of:
+# [INFO, MILD_WARN, SEVERE_WARN, MILD_ERR, SEVERE_ERR, FATAL_ERR, DEBUG, NOTICE]
+#
+# DESCRIPTION is an upper case string providing a hint as to the context of
+# the message in upper case with the underscore ('_') character serving as
+# word separator
+#
+# ORDINAL is an integer unique among other ordinals in this file
+#
+SEVERE_ERR_DSCFG_ERROR_CANNOT_READ_CONNECTION_PARAMETERS_1000=The connection \
+ parameters could not be read due to the following error: %s
+SEVERE_ERR_DSCFG_ERROR_LDAP_SIMPLE_BIND_FAILED_1001=Unable to authenticate to \
+ the server as %s
+SEVERE_ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT_1002=Unable to connect to the \
+ server at %s on port %s
+SEVERE_ERR_DSCFG_ERROR_LDAP_SIMPLE_BIND_NOT_SUPPORTED_1003=Unable to \
+ authenticate using simple authentication
+INFO_DSCFG_DESCRIPTION_SUBCMD_CREATE_1004=Creates %s
+INFO_DSCFG_DESCRIPTION_SUBCMD_DELETE_1005=Deletes %s
+INFO_DSCFG_DESCRIPTION_SUBCMD_LIST_1006=Lists existing %s
+INFO_DSCFG_DESCRIPTION_SUBCMD_GETPROP_1007=Shows %s properties
+INFO_DSCFG_DESCRIPTION_SUBCMD_SETPROP_1008=Modifies %s properties
+SEVERE_ERR_DSCFG_ERROR_MISSING_SUBCOMMAND_1009=A sub-command must be \
+ specified
+INFO_DSCFG_DESCRIPTION_TYPE_1010=The type of %s which should be created. The \
+ value for TYPE can be one of: %s
+SEVERE_ERR_DSCFG_ERROR_NO_PASSWORD_1011=No password was specified for \
+ administrator "%s"
+SEVERE_ERR_DSCFG_ERROR_PROPERTY_UNRECOGNIZED_1012=The property "%s" is not a \
+ recognized property of %s
+SEVERE_ERR_DSCFG_ERROR_PROPERTY_INVALID_VALUE_1013=The value "%s" is not a \
+ valid value for the %s property "%s" which has the following syntax: %s
+SEVERE_ERR_DSCFG_ERROR_PROPERTY_READ_ONLY_1014=The %s property "%s" is \
+ read-only and cannot be modified
+SEVERE_ERR_DSCFG_ERROR_PROPERTY_MANDATORY_1015=The %s property "%s" is \
+ mandatory and must be specified
+SEVERE_ERR_DSCFG_ERROR_PROPERTY_SINGLE_VALUED_1016=It is not possible to \
+ specify multiple values for the %s property "%s" as it is single-valued
+INFO_DSCFG_DESCRIPTION_SUBCMD_HELPPROP_1017=Describes managed objects and \
+ their properties
+INFO_DSCFG_HEADING_COMPONENT_NAME_1018=Component
+INFO_DSCFG_HEADING_PROPERTY_NAME_1019=Property
+INFO_DSCFG_HEADING_PROPERTY_VALUE_1020=Value(s)
+INFO_DSCFG_HEADING_PROPERTY_SYNTAX_1021=Syntax
+INFO_DSCFG_HEADING_PROPERTY_OPTIONS_1022=Options
+INFO_DSCFG_HEADING_PROPERTY_DEFAULT_1023=Default
+INFO_DSCFG_HEADING_PROPERTY_DESCRIPTION_1024=Description
+INFO_DSCFG_DESCRIPTION_PROPERTY_SYNTAX_HELP_1025=See detailed help
+SEVERE_ERR_DSCFG_ERROR_GET_PARENT_DDE_1026=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
+SEVERE_ERR_DSCFG_ERROR_GET_PARENT_MODE_1027=The parent %s could not be \
+ retrieved because of the reasons listed below:
+SEVERE_ERR_DSCFG_ERROR_GET_PARENT_MONFE_1028=The parent %s does not exist
+SEVERE_ERR_DSCFG_ERROR_GET_PARENT_AUTHZ_1029=The parent %s could not be \
+ retrieved because you do not have the correct authorization
+SEVERE_ERR_DSCFG_ERROR_GET_PARENT_CE_1030=The parent %s could not be \
+ retrieved due to a communications problem: %s
+SEVERE_ERR_DSCFG_ERROR_GET_PARENT_CME_1031=The parent %s could not be \
+ retrieved because another client is currently making conflicting \
+ configuration changes
+SEVERE_ERR_DSCFG_ERROR_CREATE_MMPE_1032=The %s could not be created because \
+ the following mandatory properties must be defined: %s
+SEVERE_ERR_DSCFG_ERROR_CREATE_MOAEE_1033=The %s could not be created because \
+ there is already an existing one with the same name
+SEVERE_ERR_DSCFG_ERROR_CREATE_AUTHZ_1034=The %s could not be created because \
+ you do not have the correct authorization
+SEVERE_ERR_DSCFG_ERROR_CREATE_CE_1035=The %s could not be created due to a \
+ communications problem: %s
+SEVERE_ERR_DSCFG_ERROR_CREATE_CME_1036=The %s could not be created because \
+ another client is currently making conflicting configuration changes
+SEVERE_ERR_DSCFG_ERROR_CREATE_ORE_1037=The server prevented the %s from being \
+ created because of the following reason: %s
+SEVERE_ERR_DSCFG_ERROR_DELETE_MONFE_1038=The %s could not be deleted because \
+ it does not exist
+SEVERE_ERR_DSCFG_ERROR_DELETE_AUTHZ_1039=The %s could not be deleted because \
+ you do not have the correct authorization
+SEVERE_ERR_DSCFG_ERROR_DELETE_ORE_1040=The server prevented the %s from being \
+ deleted because of the following reason: %s
+SEVERE_ERR_DSCFG_ERROR_DELETE_CE_1041=The %s could not be deleted due to a \
+ communications problem: %s
+SEVERE_ERR_DSCFG_ERROR_DELETE_CME_1042=The %s could not be deleted because \
+ another client is currently making conflicting configuration changes
+SEVERE_ERR_DSCFG_ERROR_GET_CHILD_DDE_1043=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
+SEVERE_ERR_DSCFG_ERROR_GET_CHILD_MODE_1044=The %s could not be retrieved \
+ because of the reasons listed below:
+SEVERE_ERR_DSCFG_ERROR_GET_CHILD_MONFE_1045=The %s does not exist
+SEVERE_ERR_DSCFG_ERROR_GET_CHILD_AUTHZ_1046=The %s could not be accessed \
+ because you do not have the correct authorization
+SEVERE_ERR_DSCFG_ERROR_GET_CHILD_CE_1047=The %s could not be accessed due to \
+ a communications problem: %s
+SEVERE_ERR_DSCFG_ERROR_GET_CHILD_CME_1048=The %s could not be accessed \
+ because another client is currently making conflicting configuration changes
+SEVERE_ERR_DSCFG_ERROR_MODIFY_MONFE_1049=The %s could not be modified because \
+ it does not exist
+SEVERE_ERR_DSCFG_ERROR_MODIFY_AUTHZ_1050=The %s could not be modified because \
+ you do not have the correct authorization
+SEVERE_ERR_DSCFG_ERROR_MODIFY_CE_1051=The %s could not be modified due to a \
+ communications problem: %s
+SEVERE_ERR_DSCFG_ERROR_MODIFY_CME_1052=The %s could not be modified because \
+ another client is currently making conflicting configuration changes
+SEVERE_ERR_DSCFG_ERROR_MODIFY_ORE_1053=The server prevented the %s from being \
+ modified because of the following reason: %s
+SEVERE_ERR_DSCFG_ERROR_LIST_DDE_1054=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
+SEVERE_ERR_DSCFG_ERROR_LIST_MODE_1055=The %s could not be retrieved because \
+ of the reasons listed below:
+SEVERE_ERR_DSCFG_ERROR_LIST_MONFE_1056=The %s does not exist
+SEVERE_ERR_DSCFG_ERROR_LIST_AUTHZ_1057=The %s could not be listed because you \
+ do not have the correct authorization
+SEVERE_ERR_DSCFG_ERROR_LIST_CE_1058=The %s could not be listed due to a \
+ communications problem: %s
+SEVERE_ERR_DSCFG_ERROR_LIST_CME_1059=The %s could not be listed because \
+ another client is currently making conflicting configuration changes
+SEVERE_ERR_DSCFG_ERROR_PROPERTY_UNKNOWN_ERROR_1060=The value(s) of the %s \
+ property "%s" could not be determined due to an unknown error: %s
+SEVERE_ERR_DSCFG_ERROR_PROPERTY_DEFAULT_BEHAVIOR_1061=The default value(s) of \
+ the %s property "%s" could not be determined due to the following reason: %s
+SEVERE_ERR_DSCFG_ERROR_PROPERTY_INHERITED_DEFAULT_BEHAVIOR_1062=The inherited \
+ default value(s) of the %s property "%s" could not be determined
+SEVERE_ERR_DSCFG_ERROR_NO_SEPARATOR_IN_PROPERTY_VALUE_1063=The property \
+ argument "%s" does not contain a name/value separator. The argument should \
+ have the following syntax: property:value
+SEVERE_ERR_DSCFG_ERROR_NO_NAME_IN_PROPERTY_VALUE_1064=The property argument \
+ "%s" does not contain a property name. The argument should have the following \
+ syntax: property:value
+SEVERE_ERR_DSCFG_ERROR_NO_VALUE_IN_PROPERTY_VALUE_1065=The property argument \
+ "%s" does not contain a property value. The argument should have the \
+ following syntax: property:value
+SEVERE_ERR_DSCFG_ERROR_SUB_TYPE_UNRECOGNIZED_1066=The sub-type "%s" is not a \
+ recognized type of %s. It should be one of: %s
+SEVERE_ERR_DSCFG_ERROR_TYPE_UNRECOGNIZED_1067="%s" is not a recognized \
+ component type
+SEVERE_ERR_DSCFG_ERROR_NO_SEPARATOR_IN_PROPERTY_MOD_1068=The property \
+ modification "%s" does not contain a name/value separator. The argument \
+ should have the following syntax: property[+|-]:value
+SEVERE_ERR_DSCFG_ERROR_NO_NAME_IN_PROPERTY_MOD_1069=The property modification \
+ "%s" does not contain a property name. The argument should have the following \
+ syntax: property[+|-]:value
+SEVERE_ERR_DSCFG_ERROR_NO_VALUE_IN_PROPERTY_MOD_1070=The property \
+ modification "%s" does not contain a property value. The argument should have \
+ the following syntax: property[+|-]:value
+SEVERE_ERR_DSCFG_ERROR_INCOMPATIBLE_PROPERTY_MOD_1071=The property \
+ modification "%s" is incompatible with a previous modification to the same \
+ property
+SEVERE_ERR_DSCFG_ERROR_WRONG_MANAGED_OBJECT_TYPE_1072=The %s could not be \
+ retrieved because it was the wrong type of managed object: %s
+INFO_DSCFG_DESCRIPTION_TYPE_DEFAULT_1073=The type of %s which should be \
+ created (Default: %s). The value for TYPE can be one of: %s
+INFO_DSCFG_DESCRIPTION_RECORD_1074=Modifies the display output to show one \
+ property value per line
+INFO_DSCFG_DESCRIPTION_UNIT_TIME_1078=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)
+INFO_DSCFG_DESCRIPTION_UNIT_SIZE_1079=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)
+INFO_DSCFG_ERROR_TIME_UNIT_UNRECOGNIZED_1080=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)
+INFO_DSCFG_ERROR_SIZE_UNIT_UNRECOGNIZED_1081=The size unit "%s" is invalid. \
+ The valid size units are b, kb, mb, gb, or tb (bytes, kilobytes, megabytes, \
+ gigabytes, or terabytes)
+INFO_DSCFG_HEADING_COMPONENT_TYPE_1082=Type
+INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_1083=Display subcommands relating to \
+ %s
+INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_ALL_1084=Display all subcommands
+INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_SUMMARY_1085=Display summary usage \
+ information
+INFO_DSCFG_DESCRIPTION_NAME_1086=The name of the %s
+INFO_DSCFG_DESCRIPTION_PROP_1087=The name of a property to be displayed
+INFO_DSCFG_DESCRIPTION_PROP_VAL_1088=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
+INFO_DSCFG_DESCRIPTION_ADD_PROP_VAL_1089=Adds a single value to a property \
+ where PROP is the name of the property and VAL is the single value to be \
+ added
+INFO_DSCFG_DESCRIPTION_REMOVE_PROP_VAL_1090=Removes a single value from a \
+ property where PROP is the name of the property and VAL is the single value \
+ to be removed
+INFO_DSCFG_DESCRIPTION_RESET_PROP_1091=Resets a property back to its default \
+ values where PROP is the name of the property to be reset
+INFO_DSCFG_DESCRIPTION_HELP_TYPE_1092=The type of components whose properties \
+ should be described. The value for TYPE must be one of the component types \
+ associated with the CATEGORY specified using the "--category" option
+SEVERE_ERR_DSCFG_ERROR_BIND_PASSWORD_NONINTERACTIVE_1093=The LDAP bind \
+ password was not specified and cannot be read interactively
+INFO_DSCFG_DESCRIPTION_FORCE_1196=Ignore non-existent %s
+SEVERE_ERR_DSCFG_ERROR_UNABLE_TO_RESET_MANDATORY_PROPERTY_1200=The %s \
+ property "%s" is mandatory cannot be reset. Use the "%s" option to specify a \
+ new value
+SEVERE_ERR_DSCFG_ERROR_ILLEGAL_NAME_SYNTAX_1204=The name "%s" is not a valid \
+ name for the %s which has the following syntax: %s
+SEVERE_ERR_DSCFG_ERROR_ILLEGAL_NAME_EMPTY_1205=Empty names are not permitted \
+ for %s
+SEVERE_ERR_DSCFG_ERROR_ILLEGAL_NAME_BLANK_1206=Blank names are not permitted \
+ for %s
+SEVERE_ERR_DSCFG_ERROR_ILLEGAL_NAME_UNKNOWN_1207=The name "%s" is not a valid \
+ name for the %s
+INFO_DSCFG_DESCRIPTION_NAME_CREATE_1208=The name of the new %s
+INFO_DSCFG_DESCRIPTION_NAME_CREATE_EXT_1209=The name of the new %s which will \
+ also be used as the value of the "%s" property: %s
+SEVERE_ERR_DSCFG_ERROR_UNABLE_TO_SET_NAMING_PROPERTY_1210=The property "%s" \
+ cannot be set as it is defined implicitly by the name of the %s
+INFO_DSCFG_DESCRIPTION_ADVANCED_GET_1216=Modifies the display output to show \
+ the advanced properties of the %s
+INFO_DSCFG_DESCRIPTION_ADVANCED_SET_1217=Allows the configuration of advanced \
+ properties during interactive mode
+INFO_DSCFG_DESCRIPTION_ADVANCED_HELP_1218=Modifies the display output to show \
+ the advanced properties of components
+SEVERE_ERR_DSCFG_ERROR_MISSING_NON_INTERACTIVE_ARG_1223=The argument "--%s" \
+ must be specified when this application is used non-interactively
+SEVERE_ERR_DSCFG_ERROR_CANNOT_READ_CONSOLE_INPUT_1224=The response could not \
+ be read from the console due to the following error: %s
+INFO_DSCFG_CREATE_TYPE_PROMPT_1225=>>>> Select the type of %s that you want to \
+ create:
+INFO_DSCFG_CREATE_NAME_PROMPT_1226=>>>> Enter a name for the %s that you want to \
+ create:
+SEVERE_ERR_DSCFG_ERROR_CREATE_NAME_ALREADY_EXISTS_1227=There is already \
+ another %s with the name "%s"
+INFO_DSCFG_DESCRIPTION_CREATE_HELP_HEADING_TYPE_1228=Type
+INFO_DSCFG_DESCRIPTION_CREATE_HELP_HEADING_DESCR_1229=Description
+SEVERE_ERR_DSCFG_ERROR_FINDER_NO_CHILDREN_1230=Unable to continue since there \
+ are no %s currently configured on the server
+SEVERE_ERR_DSCFG_ERROR_FINDER_SINGLE_CHILD_REJECTED_1231=Unable to continue \
+ because the only available %s was not selected
+INFO_DSCFG_FINDER_PROMPT_SINGLE_1232=>>>> There is only one %s: "%s". Are you sure \
+ that this is the correct one?
+INFO_DSCFG_FINDER_PROMPT_MANY_1233=>>>> Select the %s from the following list:
+INFO_DSCFG_GENERAL_CHOICE_PROMPT_NOHELP_1237=Enter choice [1 - %d]:
+INFO_DSCFG_GENERAL_CHOICE_PROMPT_HELP_1238=Enter choice [1 - %d, ? - help]:
+SEVERE_ERR_DSCFG_ERROR_GENERAL_CHOICE_1239=Invalid response. Please enter a \
+ value between 1 and %d
+INFO_DSCFG_HELP_FIELD_ENUM_1254=one of the following values:
+INFO_DSCFG_HELP_FIELD_UNDEFINED_1255=undefined
+INFO_DSCFG_HELP_FIELD_INHERITED_ABS_1256=inherits from the property "%s" in \
+ the %s
+INFO_DSCFG_HELP_FIELD_INHERITED_PARENT_1257=inherits from the property "%s" \
+ in the parent %s
+INFO_DSCFG_HELP_FIELD_INHERITED_THIS_1258=inherits from the property "%s" in \
+ this %s
+INFO_DSCFG_HELP_FIELD_SERVER_RESTART_1259=The server must be restarted in \
+ order for changes to this property to take effect
+INFO_DSCFG_HELP_FIELD_COMPONENT_RESTART_1260=The %s must be restarted in \
+ order for changes to this property to take effect
+INFO_DSCFG_HELP_FIELD_READ_ONLY_1261=read-only - this property can only be \
+ specified when the %s is created
+INFO_DSCFG_HELP_FIELD_MONITORING_1262=monitoring - this property is \
+ automatically generated by the server
+INFO_DSCFG_HELP_HEADING_PROPERTY_1263=Property: %s
+INFO_DSCFG_HELP_HEADING_COMPONENT_1264=Component name: %s
+INFO_DSCFG_HELP_HEADING_DEFAULT_1265=Default behavior
+INFO_DSCFG_HELP_HEADING_MANDATORY_1266=Mandatory
+INFO_DSCFG_HELP_HEADING_ADVANCED_1267=Advanced
+INFO_DSCFG_HELP_HEADING_MULTI_VALUED_1268=Multi-valued
+INFO_DSCFG_HELP_HEADING_READ_ONLY_1269=Read-only
+INFO_DSCFG_HELP_HEADING_SYNTAX_1270=Syntax
+INFO_DSCFG_HELP_DESCRIPTION_OPTION_1271=Option Types:
+INFO_DSCFG_HELP_DESCRIPTION_READ_1272=Property value(s) are readable
+INFO_DSCFG_HELP_DESCRIPTION_WRITE_1273=Property value(s) are writable
+INFO_DSCFG_HELP_DESCRIPTION_MANDATORY_1274=The property is mandatory
+INFO_DSCFG_HELP_DESCRIPTION_SINGLE_VALUED_1275=The property is single-valued
+INFO_DSCFG_HELP_DESCRIPTION_ADMIN_ACTION_1276=Administrative action is \
+ required for changes to take effect
+INFO_DSCFG_CONFIRM_CREATE_1277=Are you sure that you want to create the %s?
+INFO_DSCFG_CONFIRM_DELETE_1278=Are you sure that you want to delete the %s?
+INFO_DSCFG_CONFIRM_MODIFY_1279=Are you sure that you want to modify the %s?
+INFO_DSCFG_CONFIRM_CREATE_SUCCESS_1280=The %s was created successfully
+INFO_DSCFG_CONFIRM_DELETE_SUCCESS_1281=The %s was deleted successfully
+INFO_DSCFG_CONFIRM_MODIFY_SUCCESS_1282=The %s was modified successfully
+INFO_DSCFG_CONFIRM_CREATE_FAIL_1283=The %s was not created
+INFO_DSCFG_CONFIRM_DELETE_FAIL_1284=The %s was not deleted
+INFO_DSCFG_CONFIRM_MODIFY_FAIL_1285=The %s was not modified
+INFO_DSCFG_DESCRIPTION_HELP_CATEGORY_1286=The category of components whose \
+ properties should be described
+SEVERE_ERR_DSCFG_ERROR_CATEGORY_UNRECOGNIZED_1287="%s" is not a recognized \
+ component category
+SEVERE_ERR_DSCFG_ERROR_CATEGORY_TYPE_UNRECOGNIZED_1288="%s" is not a \
+ recognized component type in category "%s"
+SEVERE_ERR_DSCFG_ERROR_PROPERTY_UNRECOGNIZED_NO_DEFN_1289=The property "%s" \
+ is not a recognized property
+INFO_DSCFG_DESCRIPTION_HELP_INHERITED_1290=Modifies the display output to \
+ show the inherited properties of components
+INFO_VALUE_TRUE_1291=true
+INFO_VALUE_FALSE_1292=false
+INFO_VALUE_UNLIMITED_1293=unlimited
+INFO_EDITOR_PROMPT_SELECT_VALUE_SINGLE_1294=Select a value for the "%s" property:
+INFO_EDITOR_PROMPT_SELECT_VALUE_MULTI_1295=Select one or more values for the "%s" property:
+INFO_EDITOR_HEADING_SYNTAX_1296=Syntax: %s
+INFO_EDITOR_HEADING_VALUES_SUMMARY_1297=The "%s" property has the following values:
+INFO_EDITOR_PROMPT_SELECT_VALUES_ADD_1299=Select the values you wish to add:
+INFO_EDITOR_PROMPT_SELECT_VALUES_REMOVE_1302=Select the values you wish to remove:
+INFO_EDITOR_PROMPT_MODIFY_MENU_1303=Do you want to modify the "%s" property?
+INFO_EDITOR_OPTION_VALUES_1298=%d)
+INFO_EDITOR_OPTION_ADD_ALL_VALUES_1300=Add all values
+INFO_EDITOR_OPTION_ADD_ONE_OR_MORE_VALUES_1304=Add one or more values
+INFO_EDITOR_OPTION_REMOVE_ONE_OR_MORE_VALUES_1305=Remove one or more values
+INFO_EDITOR_OPTION_REMOVE_ALL_VALUES_1306=Remove all values
+INFO_EDITOR_OPTION_REVERT_CHANGES_1307=Revert changes
+INFO_EDITOR_OPTION_LEAVE_UNDEFINED_1311=Leave undefined
+INFO_EDITOR_OPTION_USE_DEFAULT_ALIAS_1308=Use the default behavior: %s
+INFO_EDITOR_OPTION_USE_DEFAULT_INHERITED_ALIAS_1309=Use the inherited default behavior: %s
+INFO_EDITOR_OPTION_USE_DEFAULT_INHERITED_ALIAS_UNDEFINED_1310=Use the inherited default behavior: undefined
+INFO_EDITOR_OPTION_USE_VALUE_1312=Use the value: %s
+INFO_EDITOR_OPTION_USE_DEFAULT_VALUE_1313=Use the default value: %s
+INFO_EDITOR_OPTION_USE_INHERITED_DEFAULT_VALUE_1314=Use the inherited default value: %s
+INFO_EDITOR_OPTION_USE_VALUES_1315=Use these values
+INFO_EDITOR_OPTION_USE_DEFAULT_VALUES_1316=Use these default values
+INFO_EDITOR_OPTION_USE_INHERITED_DEFAULT_VALUES_1317=Use these inherited default values
+INFO_EDITOR_OPTION_KEEP_DEFAULT_ALIAS_1318=Keep the default behavior: %s
+INFO_EDITOR_OPTION_KEEP_DEFAULT_INHERITED_ALIAS_1319=Keep the inherited default behavior: %s
+INFO_EDITOR_OPTION_KEEP_DEFAULT_INHERITED_ALIAS_UNDEFINED_1320=Keep the inherited default behavior: undefined
+INFO_EDITOR_OPTION_KEEP_VALUE_1321=Keep the value: %s
+INFO_EDITOR_OPTION_KEEP_DEFAULT_VALUE_1322=Keep the default value: %s
+INFO_EDITOR_OPTION_KEEP_INHERITED_DEFAULT_VALUE_1323=Keep the inherited default value: %s
+INFO_EDITOR_OPTION_KEEP_VALUES_1324=Keep these values
+INFO_EDITOR_OPTION_KEEP_DEFAULT_VALUES_1325=Keep these default values
+INFO_EDITOR_OPTION_KEEP_INHERITED_DEFAULT_VALUES_1326=Keep these inherited default values
+INFO_EDITOR_OPTION_RESET_DEFAULT_ALIAS_1327=Reset to the default behavior: %s
+INFO_EDITOR_OPTION_RESET_DEFAULT_INHERITED_ALIAS_1328=Reset to the inherited default behavior: %s
+INFO_EDITOR_OPTION_RESET_DEFAULT_INHERITED_ALIAS_UNDEFINED_1329=Reset to the inherited default behavior: undefined
+INFO_EDITOR_OPTION_RESET_DEFAULT_VALUE_1331=Reset to the default value: %s
+INFO_EDITOR_OPTION_RESET_INHERITED_DEFAULT_VALUE_1332=Reset to the inherited default value: %s
+INFO_EDITOR_OPTION_RESET_DEFAULT_VALUES_1334=Reset to the default values: %s
+INFO_EDITOR_OPTION_RESET_INHERITED_DEFAULT_VALUES_1335=Reset to the inherited default values: %s
+INFO_EDITOR_HEADING_READ_ONLY_ALIAS_UNDEFINED_1336=The "%s" property is undefined
+INFO_EDITOR_HEADING_READ_ONLY_ALIAS_1337=The "%s" property is undefined: %s
+INFO_EDITOR_HEADING_READ_ONLY_VALUE_1338=The "%s" property has the following value: %s
+INFO_EDITOR_HEADING_READ_ONLY_VALUES_1339=The "%s" property has the following values:
+INFO_EDITOR_PROMPT_READ_ONLY_1340=This property is read-only and cannot be modified. Would you like to view its help documentation?
+INFO_EDITOR_OPTION_CHANGE_TO_DEFAULT_VALUE_1341=Change it to the default value: %s
+INFO_EDITOR_OPTION_CHANGE_TO_VALUE_1342=Change it to the value: %s
+INFO_EDITOR_OPTION_CHANGE_VALUE_1343=Change the value
+INFO_EDITOR_HEADING_CONFIGURE_PROPERTY_1344=>>>> Configuring the "%s" property
+INFO_EDITOR_PROMPT_READ_FIRST_VALUE_1345=Enter a value for the "%s" property:
+INFO_EDITOR_PROMPT_READ_FIRST_VALUE_OPTIONAL_1346=Enter a value for the "%s" property [continue]:
+INFO_EDITOR_PROMPT_READ_NEXT_VALUE_1347=Enter another value for the "%s" property [continue]:
+SEVERE_ERR_EDITOR_READ_FIRST_DUPLICATE_1348=This property already contains the value "%s". Please enter a different value
+SEVERE_ERR_EDITOR_READ_NEXT_DUPLICATE_1349=This property already contains the value "%s". Please enter a different value, or press RETURN to continue
+INFO_EDITOR_HEADING_CONFIGURE_COMPONENT_1350=>>>> Configure the properties of the %s
+INFO_EDITOR_OPTION_FINISH_CREATE_COMPONENT_1351=finish - create the new %s
+INFO_EDITOR_OPTION_FINISH_MODIFY_COMPONENT_1352=finish - apply any changes to the %s
+INFO_EDITOR_OPTION_FINISH_KEY_1353=f
+INFO_EDITOR_HEADING_CONFIGURE_PROPERTY_CONT_1354=>>>> Configuring the "%s" property (Continued)
+INFO_DSCFG_CREATE_NAME_PROMPT_NAMING_1355=>>>> Specify a name for the %s. This name will be used as the value for the "%s" property which has the following description:
+INFO_DSCFG_CREATE_NAME_PROMPT_NAMING_CONT_1356=Enter a name for the %s that you want to create:
+INFO_DSCFG_HEADING_MAIN_MENU_TITLE_1357=>>>> OpenDS configuration console main menu
+INFO_DSCFG_HEADING_MAIN_MENU_PROMPT_1358=What do you want to configure?
+INFO_DSCFG_HEADING_COMPONENT_MENU_TITLE_1359=>>>> %s management menu
+INFO_DSCFG_HEADING_COMPONENT_MENU_PROMPT_1360=What would you like to do?
+INFO_DSCFG_OPTION_COMPONENT_MENU_CREATE_1361=Create a new %s
+INFO_DSCFG_OPTION_COMPONENT_MENU_MODIFY_SINGULAR_1362=View and edit the %s
+INFO_DSCFG_OPTION_COMPONENT_MENU_MODIFY_PLURAL_1363=View and edit an existing %s
+INFO_DSCFG_OPTION_COMPONENT_MENU_DELETE_1364=Delete an existing %s
+INFO_DSCFG_OPTION_COMPONENT_MENU_LIST_PLURAL_1365=List existing %s
+INFO_DSCFG_OPTION_COMPONENT_MENU_LIST_SINGULAR_1366=Show the %s
+INFO_DSCFG_PROMPT_HOST_NAME_1367=Directory server hostname or IP address [%s]:
+INFO_DSCFG_PROMPT_PORT_NUMBER_1368=Directory server port number [%d]:
+INFO_DSCFG_PROMPT_BIND_DN_1369=Administrator user bind DN [%s]:
+SEVERE_ERR_DSCFG_BAD_HOST_NAME_1370=The hostname "%s" could not be resolved. Please check you have have the correct address
+SEVERE_ERR_DSCFG_BAD_PORT_NUMBER_1371=Invalid port number "%s". Please enter a valid port number between 1 and 65535
+INFO_DSCFG_GENERIC_TYPE_OPTION_1372=Generic %s
+INFO_DSCFG_HEADING_CONNECTION_PARAMETERS_1373=>>>> Specify OpenDS LDAP connection parameters
+
diff --git a/opends/src/messages/messages/tools.properties b/opends/src/messages/messages/tools.properties
index fafad32..958efa6 100644
--- a/opends/src/messages/messages/tools.properties
+++ b/opends/src/messages/messages/tools.properties
@@ -1601,193 +1601,10 @@
start with "dn:" to indicate a user DN
INFO_DESCRIPTION_PRODUCT_VERSION_891=Display Directory Server version \
information
-SEVERE_ERR_DSCFG_ERROR_CANNOT_READ_LDAP_BIND_PASSWORD_1000=The LDAP bind \
- password could not be read due to the following error: %s
-SEVERE_ERR_DSCFG_ERROR_LDAP_SIMPLE_BIND_FAILED_1001=Unable to authenticate to \
- the server as %s
-SEVERE_ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT_1002=Unable to connect to the \
- server at %s on port %s
-SEVERE_ERR_DSCFG_ERROR_LDAP_SIMPLE_BIND_NOT_SUPPORTED_1003=Unable to \
- authenticate using simple authentication
-INFO_DSCFG_DESCRIPTION_SUBCMD_CREATE_1004=Creates %s
-INFO_DSCFG_DESCRIPTION_SUBCMD_DELETE_1005=Deletes %s
-INFO_DSCFG_DESCRIPTION_SUBCMD_LIST_1006=Lists existing %s
-INFO_DSCFG_DESCRIPTION_SUBCMD_GETPROP_1007=Shows %s properties
-INFO_DSCFG_DESCRIPTION_SUBCMD_SETPROP_1008=Modifies %s properties
-SEVERE_ERR_DSCFG_ERROR_MISSING_SUBCOMMAND_1009=A sub-command must be \
- specified
-INFO_DSCFG_DESCRIPTION_TYPE_1010=The type of %s which should be created. The \
- value for TYPE can be one of: %s
-SEVERE_ERR_DSCFG_ERROR_NO_PASSWORD_1011=No password was specified for \
- administrator "%s"
-SEVERE_ERR_DSCFG_ERROR_PROPERTY_UNRECOGNIZED_1012=The property "%s" is not a \
- recognized property of %s
-SEVERE_ERR_DSCFG_ERROR_PROPERTY_INVALID_VALUE_1013=The value "%s" is not a \
- valid value for the %s property "%s" which has the following syntax: %s
-SEVERE_ERR_DSCFG_ERROR_PROPERTY_READ_ONLY_1014=The %s property "%s" is \
- read-only and cannot be modified
-SEVERE_ERR_DSCFG_ERROR_PROPERTY_MANDATORY_1015=The %s property "%s" is \
- mandatory and must be specified
-SEVERE_ERR_DSCFG_ERROR_PROPERTY_SINGLE_VALUED_1016=It is not possible to \
- specify multiple values for the %s property "%s" as it is single-valued
-INFO_DSCFG_DESCRIPTION_SUBCMD_HELPPROP_1017=Describes managed objects and \
- their properties
-INFO_DSCFG_HEADING_COMPONENT_NAME_1018=Component
-INFO_DSCFG_HEADING_PROPERTY_NAME_1019=Property
-INFO_DSCFG_HEADING_PROPERTY_VALUE_1020=Value(s)
-INFO_DSCFG_HEADING_PROPERTY_SYNTAX_1021=Syntax
-INFO_DSCFG_HEADING_PROPERTY_OPTIONS_1022=Options
-INFO_DSCFG_HEADING_PROPERTY_DEFAULT_1023=Default
-INFO_DSCFG_HEADING_PROPERTY_DESCRIPTION_1024=Description
-INFO_DSCFG_DESCRIPTION_PROPERTY_SYNTAX_HELP_1025=See detailed help
-SEVERE_ERR_DSCFG_ERROR_GET_PARENT_DDE_1026=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
-SEVERE_ERR_DSCFG_ERROR_GET_PARENT_MODE_1027=The parent %s could not be \
- retrieved because of the reasons listed below:
-SEVERE_ERR_DSCFG_ERROR_GET_PARENT_MONFE_1028=The parent %s does not exist
-SEVERE_ERR_DSCFG_ERROR_GET_PARENT_AUTHZ_1029=The parent %s could not be \
- retrieved because you do not have the correct authorization
-SEVERE_ERR_DSCFG_ERROR_GET_PARENT_CE_1030=The parent %s could not be \
- retrieved due to a communications problem: %s
-SEVERE_ERR_DSCFG_ERROR_GET_PARENT_CME_1031=The parent %s could not be \
- retrieved because another client is currently making conflicting \
- configuration changes
-SEVERE_ERR_DSCFG_ERROR_CREATE_MMPE_1032=The %s could not be created because \
- the following mandatory properties must be defined: %s
-SEVERE_ERR_DSCFG_ERROR_CREATE_MOAEE_1033=The %s could not be created because \
- there is already an existing one with the same name
-SEVERE_ERR_DSCFG_ERROR_CREATE_AUTHZ_1034=The %s could not be created because \
- you do not have the correct authorization
-SEVERE_ERR_DSCFG_ERROR_CREATE_CE_1035=The %s could not be created due to a \
- communications problem: %s
-SEVERE_ERR_DSCFG_ERROR_CREATE_CME_1036=The %s could not be created because \
- another client is currently making conflicting configuration changes
-SEVERE_ERR_DSCFG_ERROR_CREATE_ORE_1037=The server prevented the %s from being \
- created because of the following reason: %s
-SEVERE_ERR_DSCFG_ERROR_DELETE_MONFE_1038=The %s could not be deleted because \
- it does not exist
-SEVERE_ERR_DSCFG_ERROR_DELETE_AUTHZ_1039=The %s could not be deleted because \
- you do not have the correct authorization
-SEVERE_ERR_DSCFG_ERROR_DELETE_ORE_1040=The server prevented the %s from being \
- deleted because of the following reason: %s
-SEVERE_ERR_DSCFG_ERROR_DELETE_CE_1041=The %s could not be deleted due to a \
- communications problem: %s
-SEVERE_ERR_DSCFG_ERROR_DELETE_CME_1042=The %s could not be deleted because \
- another client is currently making conflicting configuration changes
-SEVERE_ERR_DSCFG_ERROR_GET_CHILD_DDE_1043=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
-SEVERE_ERR_DSCFG_ERROR_GET_CHILD_MODE_1044=The %s could not be retrieved \
- because of the reasons listed below:
-SEVERE_ERR_DSCFG_ERROR_GET_CHILD_MONFE_1045=The %s does not exist
-SEVERE_ERR_DSCFG_ERROR_GET_CHILD_AUTHZ_1046=The %s could not be accessed \
- because you do not have the correct authorization
-SEVERE_ERR_DSCFG_ERROR_GET_CHILD_CE_1047=The %s could not be accessed due to \
- a communications problem: %s
-SEVERE_ERR_DSCFG_ERROR_GET_CHILD_CME_1048=The %s could not be accessed \
- because another client is currently making conflicting configuration changes
-SEVERE_ERR_DSCFG_ERROR_MODIFY_MONFE_1049=The %s could not be modified because \
- it does not exist
-SEVERE_ERR_DSCFG_ERROR_MODIFY_AUTHZ_1050=The %s could not be modified because \
- you do not have the correct authorization
-SEVERE_ERR_DSCFG_ERROR_MODIFY_CE_1051=The %s could not be modified due to a \
- communications problem: %s
-SEVERE_ERR_DSCFG_ERROR_MODIFY_CME_1052=The %s could not be modified because \
- another client is currently making conflicting configuration changes
-SEVERE_ERR_DSCFG_ERROR_MODIFY_ORE_1053=The server prevented the %s from being \
- modified because of the following reason: %s
-SEVERE_ERR_DSCFG_ERROR_LIST_DDE_1054=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
-SEVERE_ERR_DSCFG_ERROR_LIST_MODE_1055=The %s could not be retrieved because \
- of the reasons listed below:
-SEVERE_ERR_DSCFG_ERROR_LIST_MONFE_1056=The %s does not exist
-SEVERE_ERR_DSCFG_ERROR_LIST_AUTHZ_1057=The %s could not be listed because you \
- do not have the correct authorization
-SEVERE_ERR_DSCFG_ERROR_LIST_CE_1058=The %s could not be listed due to a \
- communications problem: %s
-SEVERE_ERR_DSCFG_ERROR_LIST_CME_1059=The %s could not be listed because \
- another client is currently making conflicting configuration changes
-SEVERE_ERR_DSCFG_ERROR_PROPERTY_UNKNOWN_ERROR_1060=The value(s) of the %s \
- property "%s" could not be determined due to an unknown error: %s
-SEVERE_ERR_DSCFG_ERROR_PROPERTY_DEFAULT_BEHAVIOR_1061=The default value(s) of \
- the %s property "%s" could not be determined due to the following reason: %s
-SEVERE_ERR_DSCFG_ERROR_PROPERTY_INHERITED_DEFAULT_BEHAVIOR_1062=The inherited \
- default value(s) of the %s property "%s" could not be determined
-SEVERE_ERR_DSCFG_ERROR_NO_SEPARATOR_IN_PROPERTY_VALUE_1063=The property \
- argument "%s" does not contain a name/value separator. The argument should \
- have the following syntax: property:value
-SEVERE_ERR_DSCFG_ERROR_NO_NAME_IN_PROPERTY_VALUE_1064=The property argument \
- "%s" does not contain a property name. The argument should have the following \
- syntax: property:value
-SEVERE_ERR_DSCFG_ERROR_NO_VALUE_IN_PROPERTY_VALUE_1065=The property argument \
- "%s" does not contain a property value. The argument should have the \
- following syntax: property:value
-SEVERE_ERR_DSCFG_ERROR_SUB_TYPE_UNRECOGNIZED_1066=The sub-type "%s" is not a \
- recognized type of %s. It should be one of: %s
-SEVERE_ERR_DSCFG_ERROR_TYPE_UNRECOGNIZED_1067="%s" is not a recognized \
- component type
-SEVERE_ERR_DSCFG_ERROR_NO_SEPARATOR_IN_PROPERTY_MOD_1068=The property \
- modification "%s" does not contain a name/value separator. The argument \
- should have the following syntax: property[+|-]:value
-SEVERE_ERR_DSCFG_ERROR_NO_NAME_IN_PROPERTY_MOD_1069=The property modification \
- "%s" does not contain a property name. The argument should have the following \
- syntax: property[+|-]:value
-SEVERE_ERR_DSCFG_ERROR_NO_VALUE_IN_PROPERTY_MOD_1070=The property \
- modification "%s" does not contain a property value. The argument should have \
- the following syntax: property[+|-]:value
-SEVERE_ERR_DSCFG_ERROR_INCOMPATIBLE_PROPERTY_MOD_1071=The property \
- modification "%s" is incompatible with a previous modification to the same \
- property
-SEVERE_ERR_DSCFG_ERROR_WRONG_MANAGED_OBJECT_TYPE_1072=The %s could not be \
- retrieved because it was the wrong type of managed object: %s
-INFO_DSCFG_DESCRIPTION_TYPE_DEFAULT_1073=The type of %s which should be \
- created (Default: %s). The value for TYPE can be one of: %s
-INFO_DSCFG_DESCRIPTION_RECORD_1074=Modifies the display output to show one \
- property value per line
INFO_DESCRIPTION_QUIET_1075=Use quiet mode
INFO_DESCRIPTION_SCRIPT_FRIENDLY_1076=Use script-friendly mode
INFO_DESCRIPTION_NO_PROMPT_1077=Use non-interactive mode. If some data in \
the command is missing the user will not be prompted and the tool will fail
-INFO_DSCFG_DESCRIPTION_UNIT_TIME_1078=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)
-INFO_DSCFG_DESCRIPTION_UNIT_SIZE_1079=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)
-INFO_DSCFG_ERROR_TIME_UNIT_UNRECOGNIZED_1080=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)
-INFO_DSCFG_ERROR_SIZE_UNIT_UNRECOGNIZED_1081=The size unit "%s" is invalid. \
- The valid size units are b, kb, mb, gb, or tb (bytes, kilobytes, megabytes, \
- gigabytes, or terabytes)
-INFO_DSCFG_HEADING_COMPONENT_TYPE_1082=Type
-INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_1083=Display subcommands relating to \
- %s
-INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_ALL_1084=Display all subcommands
-INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_SUMMARY_1085=Display summary usage \
- information
-INFO_DSCFG_DESCRIPTION_NAME_1086=The name of the %s
-INFO_DSCFG_DESCRIPTION_PROP_1087=The name of a property to be displayed
-INFO_DSCFG_DESCRIPTION_PROP_VAL_1088=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
-INFO_DSCFG_DESCRIPTION_ADD_PROP_VAL_1089=Adds a single value to a property \
- where PROP is the name of the property and VAL is the single value to be \
- added
-INFO_DSCFG_DESCRIPTION_REMOVE_PROP_VAL_1090=Removes a single value from a \
- property where PROP is the name of the property and VAL is the single value \
- to be removed
-INFO_DSCFG_DESCRIPTION_RESET_PROP_1091=Resets a property back to its default \
- values where PROP is the name of the property to be reset
-INFO_DSCFG_DESCRIPTION_HELP_TYPE_1092=The type of components whose properties \
- should be described. The value for TYPE must be one of the component types \
- associated with the CATEGORY specified using the "--category" option
-SEVERE_ERR_DSCFG_ERROR_BIND_PASSWORD_NONINTERACTIVE_1093=The LDAP bind \
- password was not specified and cannot be read interactively
INFO_PWPSTATE_TOOL_DESCRIPTION_1094=This utility may be used to retrieve and \
manipulate the values of password policy state variables
INFO_PWPSTATE_DESCRIPTION_HOST_1095=Directory server hostname or IP address
@@ -1995,7 +1812,6 @@
INFO_LDIFIMPORT_DESCRIPTION_COUNT_REJECTS_1195=Count the number of entries \
rejected by the server and return that value as the exit code (values > 255 \
will be reduced to 255 due to exit code restrictions)
-INFO_DSCFG_DESCRIPTION_FORCE_1196=Ignore non-existent %s
INFO_LDIFIMPORT_DESCRIPTION_SKIP_FILE_1197=Write skipped entries to the \
specified file
SEVERE_ERR_LDIFIMPORT_CANNOT_OPEN_SKIP_FILE_1198=An error occurred while \
@@ -2003,27 +1819,11 @@
INFO_VERIFYINDEX_DESCRIPTION_COUNT_ERRORS_1199=Count the number of errors \
found during the verification and return that value as the exit code (values \
> 255 will be reduced to 255 due to exit code restrictions)
-SEVERE_ERR_DSCFG_ERROR_UNABLE_TO_RESET_MANDATORY_PROPERTY_1200=The %s \
- property "%s" is mandatory cannot be reset. Use the "%s" option to specify a \
- new value
INFO_PWPSTATE_LABEL_PASSWORD_HISTORY_1201=Password History
INFO_DESCRIPTION_PWPSTATE_GET_PASSWORD_HISTORY_1202=Display password history \
state values for the user
INFO_DESCRIPTION_PWPSTATE_CLEAR_PASSWORD_HISTORY_1203=Clear password history \
state values for the user. This should be used only for testing purposes
-SEVERE_ERR_DSCFG_ERROR_ILLEGAL_NAME_SYNTAX_1204=The name "%s" is not a valid \
- name for the %s which has the following syntax: %s
-SEVERE_ERR_DSCFG_ERROR_ILLEGAL_NAME_EMPTY_1205=Empty names are not permitted \
- for %s
-SEVERE_ERR_DSCFG_ERROR_ILLEGAL_NAME_BLANK_1206=Blank names are not permitted \
- for %s
-SEVERE_ERR_DSCFG_ERROR_ILLEGAL_NAME_UNKNOWN_1207=The name "%s" is not a valid \
- name for the %s
-INFO_DSCFG_DESCRIPTION_NAME_CREATE_1208=The name of the new %s
-INFO_DSCFG_DESCRIPTION_NAME_CREATE_EXT_1209=The name of the new %s which will \
- also be used as the value of the "%s" property: %s
-SEVERE_ERR_DSCFG_ERROR_UNABLE_TO_SET_NAMING_PROPERTY_1210=The property "%s" \
- cannot be set as it is defined implicitly by the name of the %s
SEVERE_ERR_CONFIGDS_PORT_ALREADY_SPECIFIED_1211=ERROR: You have specified \
the value %s for different ports
SEVERE_ERR_CLI_ERROR_PROPERTY_UNRECOGNIZED_1212=The property "%s" is not a \
@@ -2033,12 +1833,6 @@
SEVERE_ERR_CLI_ERROR_INVALID_PROPERTY_VALUE_1214=The value "%s" specified for \
the property "%s" is invalid
INFO_CLI_HEADING_PROPERTY_DEFAULT_VALUE_1215=Default value
-INFO_DSCFG_DESCRIPTION_ADVANCED_GET_1216=Modifies the display output to show \
- the advanced properties of the %s
-INFO_DSCFG_DESCRIPTION_ADVANCED_SET_1217=Allows the configuration of advanced \
- properties during interactive mode
-INFO_DSCFG_DESCRIPTION_ADVANCED_HELP_1218=Modifies the display output to show \
- the advanced properties of components
INFO_REVERT_DESCRIPTION_DIRECTORY_1219=Directory where reversion files are \
stored. This should be one of the child directories of the 'history' \
directory that is created when the upgrade tool is run
@@ -2047,50 +1841,6 @@
INFO_REVERT_DESCRIPTION_INTERACTIVE_1221=Prompt for any required information \
rather than fail
INFO_REVERT_DESCRIPTION_SILENT_1222=Perform a quiet reversion
-SEVERE_ERR_DSCFG_ERROR_MISSING_NON_INTERACTIVE_ARG_1223=The argument "--%s" \
- must be specified when this application is used non-interactively
-SEVERE_ERR_DSCFG_ERROR_CANNOT_READ_CONSOLE_INPUT_1224=The response could not \
- be read from the console due to the following error: %s
-INFO_DSCFG_CREATE_TYPE_PROMPT_1225=Select the type of %s that you want to \
- create:
-INFO_DSCFG_CREATE_NAME_PROMPT_1226=Enter a name for the %s that you want to \
- create:
-SEVERE_ERR_DSCFG_ERROR_CREATE_NAME_ALREADY_EXISTS_1227=There is already \
- another %s with the name "%s"
-INFO_DSCFG_DESCRIPTION_CREATE_HELP_HEADING_TYPE_1228=Type
-INFO_DSCFG_DESCRIPTION_CREATE_HELP_HEADING_DESCR_1229=Description
-SEVERE_ERR_DSCFG_ERROR_FINDER_NO_CHILDREN_1230=Unable to continue since there \
- are no %s currently configured on the server
-SEVERE_ERR_DSCFG_ERROR_FINDER_SINGLE_CHILD_REJECTED_1231=Unable to continue \
- because the only available %s was not selected
-INFO_DSCFG_FINDER_PROMPT_SINGLE_1232=There is only one %s: "%s". Are you sure \
- that this is the correct one?
-INFO_DSCFG_FINDER_PROMPT_MANY_1233=Select the %s from the following list:
-INFO_DSCFG_GENERAL_CONFIRM_NO_1234=no
-INFO_DSCFG_GENERAL_CONFIRM_YES_1235=yes
-SEVERE_ERR_DSCFG_ERROR_GENERAL_CONFIRM_1236=Invalid response. Please enter \
- "%s" or "%s"
-INFO_DSCFG_GENERAL_CHOICE_PROMPT_NOHELP_1237=Enter choice [1 - %d]:
-INFO_DSCFG_GENERAL_CHOICE_PROMPT_HELP_1238=Enter choice [1 - %d, ? - help]:
-SEVERE_ERR_DSCFG_ERROR_GENERAL_CHOICE_1239=Invalid response. Please enter a \
- value between 1 and %d
-INFO_DSCFG_VALUE_READER_MENU_RESET_1240=reset the value back to its default
-INFO_DSCFG_VALUE_READER_MENU_SET_1241=modify the value
-INFO_DSCFG_VALUE_READER_MENU_ADD_1242=add a value
-INFO_DSCFG_VALUE_READER_MENU_REMOVE_1243=remove a value
-INFO_DSCFG_VALUE_READER_MENU_CONTINUE_1244=continue
-INFO_DSCFG_VALUE_READER_PROMPT_REMOVE_1245=Select the value to be removed \
- from the "%s" property:
-INFO_DSCFG_VALUE_READER_PROMPT_SELECT_VALUE_1246=Select a value for the "%s" \
- property:
-INFO_DSCFG_VALUE_READER_PROMPT_ENTER_VALUE_1247=Enter a value for the "%s" \
- property:
-INFO_DSCFG_VALUE_READER_MENU_TITLE_1248=Select a property to be edited, or \
- enter "%d" to continue:
-INFO_DSCFG_VALUE_READER_PROMPT_MANDATORY_1249=The property "%s" is mandatory \
- and must have a value specified
-INFO_DSCFG_VALUE_READER_PROMPT_MODIFY_MENU_1250=Do you want to modify the \
- "%s" property?
INFO_LDIFIMPORT_DESCRIPTION_CLEAR_BACKEND_1251=Remove all entries for all \
base DNs in the backend before importing
SEVERE_ERR_LDIFIMPORT_MISSING_BACKEND_ARGUMENT_1252=Neither the %s or the %s \
@@ -2099,56 +1849,6 @@
SEVERE_ERR_LDIFIMPORT_MISSING_CLEAR_BACKEND_1253=Importing to a backend \
without the append argument will remove all entries for all base DNs (%s) in \
the backend. The %s argument must be given to continue with import
-INFO_DSCFG_HELP_FIELD_ENUM_1254=one of the following values:
-INFO_DSCFG_HELP_FIELD_UNDEFINED_1255=undefined
-INFO_DSCFG_HELP_FIELD_INHERITED_ABS_1256=inherits from the property "%s" in \
- the %s
-INFO_DSCFG_HELP_FIELD_INHERITED_PARENT_1257=inherits from the property "%s" \
- in the parent %s
-INFO_DSCFG_HELP_FIELD_INHERITED_THIS_1258=inherits from the property "%s" in \
- this %s
-INFO_DSCFG_HELP_FIELD_SERVER_RESTART_1259=The server must be restarted in \
- order for changes to this property to take effect
-INFO_DSCFG_HELP_FIELD_COMPONENT_RESTART_1260=The %s must be restarted in \
- order for changes to this property to take effect
-INFO_DSCFG_HELP_FIELD_READ_ONLY_1261=read-only - this property can only be \
- specified when the %s is created
-INFO_DSCFG_HELP_FIELD_MONITORING_1262=monitoring - this property is \
- automatically generated by the server
-INFO_DSCFG_HELP_HEADING_PROPERTY_1263=Property: %s
-INFO_DSCFG_HELP_HEADING_COMPONENT_1264=Component name: %s
-INFO_DSCFG_HELP_HEADING_DEFAULT_1265=Default behavior
-INFO_DSCFG_HELP_HEADING_MANDATORY_1266=Mandatory
-INFO_DSCFG_HELP_HEADING_ADVANCED_1267=Advanced
-INFO_DSCFG_HELP_HEADING_MULTI_VALUED_1268=Multi-valued
-INFO_DSCFG_HELP_HEADING_READ_ONLY_1269=Read-only
-INFO_DSCFG_HELP_HEADING_SYNTAX_1270=Syntax
-INFO_DSCFG_HELP_DESCRIPTION_OPTION_1271=Option Types:
-INFO_DSCFG_HELP_DESCRIPTION_READ_1272=Property value(s) are readable
-INFO_DSCFG_HELP_DESCRIPTION_WRITE_1273=Property value(s) are writable
-INFO_DSCFG_HELP_DESCRIPTION_MANDATORY_1274=The property is mandatory
-INFO_DSCFG_HELP_DESCRIPTION_SINGLE_VALUED_1275=The property is single-valued
-INFO_DSCFG_HELP_DESCRIPTION_ADMIN_ACTION_1276=Administrative action is \
- required for changes to take effect
-INFO_DSCFG_CONFIRM_CREATE_1277=Are you sure that you want to create the %s?
-INFO_DSCFG_CONFIRM_DELETE_1278=Are you sure that you want to delete the %s?
-INFO_DSCFG_CONFIRM_MODIFY_1279=Are you sure that you want to modify the %s?
-INFO_DSCFG_CONFIRM_CREATE_SUCCESS_1280=The %s was created successfully
-INFO_DSCFG_CONFIRM_DELETE_SUCCESS_1281=The %s was deleted successfully
-INFO_DSCFG_CONFIRM_MODIFY_SUCCESS_1282=The %s was modified successfully
-INFO_DSCFG_CONFIRM_CREATE_FAIL_1283=The %s was not created
-INFO_DSCFG_CONFIRM_DELETE_FAIL_1284=The %s was not deleted
-INFO_DSCFG_CONFIRM_MODIFY_FAIL_1285=The %s was not modified
-INFO_DSCFG_DESCRIPTION_HELP_CATEGORY_1286=The category of components whose \
- properties should be described
-SEVERE_ERR_DSCFG_ERROR_CATEGORY_UNRECOGNIZED_1287="%s" is not a recognized \
- component category
-SEVERE_ERR_DSCFG_ERROR_CATEGORY_TYPE_UNRECOGNIZED_1288="%s" is not a \
- recognized component type in category "%s"
-SEVERE_ERR_DSCFG_ERROR_PROPERTY_UNRECOGNIZED_NO_DEFN_1289=The property "%s" \
- is not a recognized property
-INFO_DSCFG_DESCRIPTION_HELP_INHERITED_1290=Modifies the display output to \
- show the inherited properties of components
MILD_ERR_MAKELDIF_TAG_LIST_NO_ARGUMENTS_1291=The list tag on line %d of the \
template file does not contain any arguments to specify the list values. At \
least one list value must be provided
@@ -2298,3 +1998,4 @@
min/max data size %s as a integer: %s
SEVERE_ERR_CONFIGDS_CANNOT_ENABLE_ADS_TRUST_STORE_1373=An error occurred while \
attempting to enable the ADS trust store: %s
+SEVERE_ERR_DBTEST_MISSING_SUBCOMMAND_1374=A sub-command must be specified
diff --git a/opends/src/messages/messages/utility.properties b/opends/src/messages/messages/utility.properties
index 780cd34..10f1636 100644
--- a/opends/src/messages/messages/utility.properties
+++ b/opends/src/messages/messages/utility.properties
@@ -472,4 +472,30 @@
SEVERE_ERR_BASE64_CANNOT_WRITE_RAW_DATA_199=An error occurred while \
attempting to write the decoded data: %s
SEVERE_ERR_BASE64_UNKNOWN_SUBCOMMAND_200=Unknown subcommand %s
-
+INFO_GENERAL_NO_201=no
+INFO_GENERAL_YES_202=yes
+SEVERE_ERR_CONSOLE_APP_CONFIRM_203=Invalid response. Please enter \
+ "%s" or "%s"
+INFO_MENU_OPTION_HELP_204=help
+INFO_MENU_OPTION_HELP_KEY_205=?
+INFO_MENU_OPTION_CANCEL_206=cancel
+INFO_MENU_OPTION_CANCEL_KEY_207=c
+INFO_MENU_OPTION_QUIT_208=quit
+INFO_MENU_OPTION_QUIT_KEY_209=q
+INFO_MENU_NUMERIC_OPTION_210=%d)
+INFO_MENU_CHAR_OPTION_211=%c)
+SEVERE_ERR_MENU_BAD_CHOICE_MULTI_212=Invalid response. Please enter one or \
+more valid menu options
+SEVERE_ERR_MENU_BAD_CHOICE_SINGLE_213=Invalid response. Please enter a valid \
+menu option
+SEVERE_ERR_MENU_BAD_CHOICE_MULTI_DUPE_214=The option "%s" was specified \
+more than once. Please enter one or more valid menu options
+INFO_MENU_PROMPT_SINGLE_215=Enter choice:
+INFO_MENU_PROMPT_SINGLE_DEFAULT_216=Enter choice [%s]:
+INFO_MENU_PROMPT_MULTI_217=Enter one or more choices separated by commas:
+INFO_MENU_PROMPT_MULTI_DEFAULT_218=Enter one or more choices separated by commas [%s]:
+INFO_MENU_PROMPT_RETURN_TO_CONTINUE_219=Press RETURN to continue
+INFO_MENU_PROMPT_CONFIRM_220=%s (%s / %s) [%s]:
+SEVERE_ERR_CONSOLE_INPUT_ERROR_221=The response could not be read from the console due to the following error: %s
+INFO_MENU_OPTION_BACK_222=back
+INFO_MENU_OPTION_BACK_KEY_223=b
diff --git a/opends/src/messages/src/org/opends/messages/Category.java b/opends/src/messages/src/org/opends/messages/Category.java
index 99685b9..c5046e4 100644
--- a/opends/src/messages/src/org/opends/messages/Category.java
+++ b/opends/src/messages/src/org/opends/messages/Category.java
@@ -140,6 +140,12 @@
ADMIN_TOOL(0x01100000),
/**
+ * The category used for messages associated with the dsconfig
+ * administration tool.
+ */
+ DSCONFIG(0x01200000),
+
+ /**
* The category that will be used for messages associated with
* third-party (including user-defined) modules.
*/
diff --git a/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java b/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java
index f953d1e..466f5a3 100644
--- a/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java
+++ b/opends/src/server/org/opends/server/admin/PropertyDefinitionUsageBuilder.java
@@ -312,7 +312,7 @@
* {@inheritDoc}
*/
@Override
- public Message visitUnknown(PropertyDefinition<?> d, Void p)
+ public <T> Message visitUnknown(PropertyDefinition<T> d, Void p)
throws UnknownPropertyDefinitionException {
return Message.raw("?");
}
diff --git a/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java b/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java
index b445037..63e7c0b 100644
--- a/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java
+++ b/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java
@@ -241,6 +241,8 @@
* {@link UnknownPropertyDefinitionException}. Sub-classes can
* override this method with their own default behavior.
*
+ * @param <T>
+ * The type of the underlying property.
* @param d
* The property definition to visit.
* @param p
@@ -250,7 +252,7 @@
* Visitor implementations may optionally throw this
* exception.
*/
- public R visitUnknown(PropertyDefinition<?> d, P p)
+ public <T> R visitUnknown(PropertyDefinition<T> d, P p)
throws UnknownPropertyDefinitionException {
throw new UnknownPropertyDefinitionException(d, p);
}
diff --git a/opends/src/server/org/opends/server/admin/client/ManagedObject.java b/opends/src/server/org/opends/server/admin/client/ManagedObject.java
index bd8ed4a..d34b3e0 100644
--- a/opends/src/server/org/opends/server/admin/client/ManagedObject.java
+++ b/opends/src/server/org/opends/server/admin/client/ManagedObject.java
@@ -443,6 +443,25 @@
/**
+ * Determines whether or not the specified property is set. If the
+ * property is unset, then any default behavior associated with the
+ * property applies.
+ *
+ * @param pd
+ * The property definition.
+ * @return Returns <code>true</code> if the property has been set,
+ * or <code>false</code> if it is unset and any default
+ * behavior associated with the property applies.
+ * @throws IllegalArgumentException
+ * If the property definition is not associated with this
+ * managed object's definition.
+ */
+ boolean isPropertyPresent(PropertyDefinition<?> pd)
+ throws IllegalArgumentException;
+
+
+
+ /**
* Determines whether or not the optional managed object associated
* with the specified optional relations exists.
*
diff --git a/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliGlobalAdmin.java b/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliGlobalAdmin.java
index 9f62f5f..adcef30 100644
--- a/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliGlobalAdmin.java
+++ b/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliGlobalAdmin.java
@@ -29,6 +29,7 @@
import org.opends.messages.MessageBuilder;
import static org.opends.messages.AdminMessages.*;
+import static org.opends.messages.DSConfigMessages.*;
import static org.opends.messages.ToolMessages.*;
import static org.opends.server.tools.ToolConstants.*;
diff --git a/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliMain.java b/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliMain.java
index b314e6e..68bb2bb 100644
--- a/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliMain.java
+++ b/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliMain.java
@@ -39,6 +39,7 @@
import static org.opends.server.admin.client.cli.DsFrameworkCliReturnCode.*;
import static org.opends.messages.AdminMessages.*;
+import static org.opends.messages.DSConfigMessages.*;
import static org.opends.messages.ToolMessages.*;
import org.opends.messages.MessageBuilder;
import static org.opends.server.util.ServerConstants.*;
diff --git a/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliParser.java b/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliParser.java
index ed34041..80d1192 100644
--- a/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliParser.java
+++ b/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliParser.java
@@ -28,7 +28,7 @@
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.messages.AdminMessages.*;
-import static org.opends.messages.ToolMessages.*;
+import static org.opends.messages.DSConfigMessages.*;
import org.opends.messages.Message;
import static org.opends.server.tools.ToolConstants.*;
import static org.opends.server.util.ServerConstants.MAX_LINE_WIDTH;
diff --git a/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliServer.java b/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliServer.java
index eba4c43..3f9ee00 100644
--- a/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliServer.java
+++ b/opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliServer.java
@@ -29,6 +29,7 @@
import org.opends.messages.MessageBuilder;
import static org.opends.messages.AdminMessages.*;
+import static org.opends.messages.DSConfigMessages.*;
import static org.opends.messages.ToolMessages.*;
import static org.opends.server.tools.ToolConstants.*;
diff --git a/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java b/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
index 39c7419..16120aa 100644
--- a/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
+++ b/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
@@ -675,6 +675,17 @@
/**
* {@inheritDoc}
*/
+ public boolean isPropertyPresent(PropertyDefinition<?> pd)
+ throws IllegalArgumentException {
+ Property<?> p = properties.getProperty(pd);
+ return !p.isEmpty();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
public <C extends ConfigurationClient, S extends Configuration>
boolean hasChild(OptionalRelationDefinition<C, S> r)
throws IllegalArgumentException, ConcurrentModificationException,
diff --git a/opends/src/server/org/opends/server/tools/DBTest.java b/opends/src/server/org/opends/server/tools/DBTest.java
index d269c81..a7a0849 100644
--- a/opends/src/server/org/opends/server/tools/DBTest.java
+++ b/opends/src/server/org/opends/server/tools/DBTest.java
@@ -434,7 +434,7 @@
// Make sure that we have a sub-command.
if (parser.getSubCommand() == null)
{
- Message message = ERR_DSCFG_ERROR_MISSING_SUBCOMMAND.get();
+ Message message = ERR_DBTEST_MISSING_SUBCOMMAND.get();
displayMessageAndUsageReference(message);
return 1;
}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java b/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
index 5a9c9f0..85cc99c 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
@@ -25,12 +25,12 @@
* Portions Copyright 2007 Sun Microsystems, Inc.
*/
package org.opends.server.tools.dsconfig;
+
+
+
+import static org.opends.messages.DSConfigMessages.*;
+
import org.opends.messages.Message;
-
-
-
-import static org.opends.messages.ToolMessages.*;
-
import org.opends.server.admin.AbstractManagedObjectDefinition;
import org.opends.server.admin.DefaultBehaviorException;
import org.opends.server.admin.IllegalPropertyValueException;
@@ -47,6 +47,7 @@
import org.opends.server.admin.client.MissingMandatoryPropertiesException;
import org.opends.server.util.args.Argument;
import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.cli.CLIException;
@@ -57,16 +58,16 @@
public final class ArgumentExceptionFactory {
/**
- * Creates an argument exception from an illegal managed object name
+ * Creates a CLI exception from an illegal managed object name
* exception.
*
* @param e
* The illegal managed object name exception.
* @param d
* The managed object definition.
- * @return Returns an argument exception.
+ * @return Returns a CLI exception.
*/
- public static ArgumentException adaptIllegalManagedObjectNameException(
+ public static CLIException adaptIllegalManagedObjectNameException(
IllegalManagedObjectNameException e,
AbstractManagedObjectDefinition<?, ?> d) {
String illegalName = e.getIllegalName();
@@ -75,11 +76,11 @@
if (illegalName.length() == 0) {
Message message =
ERR_DSCFG_ERROR_ILLEGAL_NAME_EMPTY.get(d.getUserFriendlyPluralName());
- return new ArgumentException(message);
+ return new CLIException(message);
} else if (illegalName.trim().length() == 0) {
Message message =
ERR_DSCFG_ERROR_ILLEGAL_NAME_BLANK.get(d.getUserFriendlyPluralName());
- return new ArgumentException(message);
+ return new CLIException(message);
} else if (pd != null) {
try {
pd.decodeValue(illegalName);
@@ -90,13 +91,13 @@
Message message = ERR_DSCFG_ERROR_ILLEGAL_NAME_SYNTAX.get(
illegalName, d.getUserFriendlyName(), syntax);
- return new ArgumentException(message);
+ return new CLIException(message);
}
}
Message message = ERR_DSCFG_ERROR_ILLEGAL_NAME_UNKNOWN.get(
illegalName, d.getUserFriendlyName());
- return new ArgumentException(message);
+ return new CLIException(message);
}
@@ -320,16 +321,18 @@
/**
- * Creates an argument exception which should be used when the bind
- * password could not be read from the standard input.
+ * Creates an argument exception which should be used when the
+ * connection parameters could not be read from the standard input.
*
* @param cause
- * The reason why the bind password could not be read.
+ * The reason why the connection parameters could not be
+ * read.
* @return Returns an argument exception.
*/
- public static ArgumentException unableToReadBindPassword(Exception cause) {
- Message message =
- ERR_DSCFG_ERROR_CANNOT_READ_LDAP_BIND_PASSWORD.get(cause.getMessage());
+ public static ArgumentException unableToReadConnectionParameters(
+ Exception cause) {
+ Message message = ERR_DSCFG_ERROR_CANNOT_READ_CONNECTION_PARAMETERS
+ .get(cause.getMessage());
return new ArgumentException(message, cause);
}
@@ -350,22 +353,6 @@
/**
- * Creates an argument exception which should be used when
- * interaction with the console fails due to an IO exception.
- *
- * @param cause
- * The reason why console input failed.
- * @return Returns an argument exception.
- */
- public static ArgumentException unableToReadConsoleInput(Exception cause) {
- Message message =
- ERR_DSCFG_ERROR_CANNOT_READ_CONSOLE_INPUT.get(cause.getMessage());
- return new ArgumentException(message, cause);
- }
-
-
-
- /**
* Creates an argument exception which should be used when an
* attempt is made to reset a mandatory property that does not have
* any default values.
@@ -513,7 +500,7 @@
/**
- * Creates an argument exception which should be used when a managed
+ * Creates a CLI exception which should be used when a managed
* object is retrieved but does not have the correct type
* appropriate for the associated sub-command.
*
@@ -521,13 +508,13 @@
* The relation definition.
* @param d
* The definition of the managed object that was retrieved.
- * @return Returns an argument exception.
+ * @return Returns a CLI exception.
*/
- public static ArgumentException wrongManagedObjectType(
- RelationDefinition<?, ?> r, ManagedObjectDefinition<?, ?> d) {
- Message msg = ERR_DSCFG_ERROR_TYPE_UNRECOGNIZED.get(
- d.getUserFriendlyName());
- return new ArgumentException(msg);
+ public static CLIException wrongManagedObjectType(RelationDefinition<?, ?> r,
+ ManagedObjectDefinition<?, ?> d) {
+ Message msg = ERR_DSCFG_ERROR_TYPE_UNRECOGNIZED
+ .get(d.getUserFriendlyName());
+ return new CLIException(msg);
}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/ConsoleApplication.java b/opends/src/server/org/opends/server/tools/dsconfig/ConsoleApplication.java
deleted file mode 100644
index e197ce2..0000000
--- a/opends/src/server/org/opends/server/tools/dsconfig/ConsoleApplication.java
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * 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.messages.Message;
-import org.opends.messages.MessageBuilder;
-
-
-import static org.opends.messages.ToolMessages.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-import java.io.BufferedReader;
-import java.io.EOFException;
-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.List;
-
-import org.opends.server.admin.client.ManagementContext;
-import org.opends.server.tools.ClientException;
-import org.opends.server.types.NullOutputStream;
-import org.opends.server.util.PasswordReader;
-import org.opends.server.util.Validator;
-import org.opends.server.util.args.ArgumentException;
-import org.opends.server.util.table.TableBuilder;
-import org.opends.server.util.table.TextTablePrinter;
-
-
-
-/**
- * This class provides an abstract base class which can be used as the
- * basis of a console-based application.
- */
-public abstract class ConsoleApplication {
-
- // The error stream which this application should use.
- private final PrintStream err;
-
- // The input stream reader which this application should use.
- private final BufferedReader in;
-
- // The output stream which this application should use.
- private final PrintStream out;
-
-
-
- /**
- * Creates a new console application instance.
- *
- * @param in
- * The application input stream.
- * @param out
- * The application output stream.
- * @param err
- * The application error stream.
- */
- protected ConsoleApplication(InputStream in, OutputStream out,
- OutputStream err) {
- if (in != null) {
- this.in = new BufferedReader(new InputStreamReader(in));
- } else {
- this.in = new BufferedReader(new Reader() {
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void close() throws IOException {
- // Do nothing.
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @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();
- }
- }
-
-
-
- /**
- * 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.
- * @throws ArgumentException
- * If the user's response could not be read from the
- * console for some reason.
- */
- public final boolean confirmAction(Message prompt) throws ArgumentException {
- if (!isInteractive()) {
- return true;
- }
-
- final Message yes = INFO_DSCFG_GENERAL_CONFIRM_YES.get();
- final Message no = INFO_DSCFG_GENERAL_CONFIRM_NO.get();
- final Message errMsg = ERR_DSCFG_ERROR_GENERAL_CONFIRM.get(yes, no);
- MessageBuilder mb = new MessageBuilder();
- mb.append(prompt);
- mb.append(String.format(" (%s / %s): ", yes, no));
- prompt = mb.toMessage();
-
- ValidationCallback<Boolean> validator = new ValidationCallback<Boolean>() {
-
- public Boolean validate(ConsoleApplication app, String input) {
- String ninput = input.toLowerCase().trim();
- if (ninput.length() == 0) {
- // Empty input.
- app.println();
- app.printMessage(errMsg);
- } else if (no.toString().startsWith(ninput)) {
- return false;
- } else if (yes.toString().startsWith(ninput)) {
- return true;
- } else {
- // Try again...
- app.println();
- app.printMessage(errMsg);
- }
-
- return null;
- }
- };
-
- try {
- return readValidatedInput(prompt, validator);
- } catch (ClientException e) {
- // Should never happen.
- throw new RuntimeException(e);
- }
- }
-
-
-
- /**
- * Displays a message to the error stream.
- *
- * @param msg
- * The message.
- */
- public final void printMessage(Message msg) {
- err.println(wrapText(msg.toString(), MAX_LINE_WIDTH));
- }
-
-
-
- /**
- * Displays a blank line to the error stream.
- */
- public final void println() {
- err.println();
- }
-
-
-
- /**
- * Displays a message to the error stream if verbose mode is
- * enabled.
- *
- * @param msg
- * The verbose message.
- */
- public final void printVerboseMessage(Message msg) {
- if (isVerbose() || isInteractive()) {
- err.println(wrapText(msg, MAX_LINE_WIDTH));
- }
- }
-
-
-
- /**
- * Gets the application error stream.
- *
- * @return Returns the application error stream.
- */
- public final PrintStream getErrorStream() {
- return err;
- }
-
-
-
- /**
- * Gets the application input stream.
- *
- * @return Returns the application input stream.
- */
- public final BufferedReader getInputStream() {
- return in;
- }
-
-
-
- /**
- * 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.
- */
- public abstract ManagementContext getManagementContext()
- throws ArgumentException, ClientException;
-
-
-
- /**
- * Gets the application output stream.
- *
- * @return Returns the application output stream.
- */
- public final PrintStream getOutputStream() {
- return out;
- }
-
-
-
- /**
- * Indicates whether or not the user has requested interactive
- * behavior.
- *
- * @return Returns <code>true</code> if the user has requested
- * interactive behavior.
- */
- public abstract boolean isInteractive();
-
-
-
- /**
- * Indicates whether or not the user has requested quiet output.
- *
- * @return Returns <code>true</code> if the user has requested
- * quiet output.
- */
- public abstract boolean isQuiet();
-
-
-
- /**
- * 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 abstract boolean isScriptFriendly();
-
-
-
- /**
- * Indicates whether or not the user has requested verbose output.
- *
- * @return Returns <code>true</code> if the user has requested
- * verbose output.
- */
- public abstract boolean isVerbose();
-
-
-
- /**
- * Interactively prompts the user to select from a choice of
- * options.
- *
- * @param <T>
- * The type of the values represented by each choice.
- * @param prompt
- * The prompt which should appear before the list of
- * choices.
- * @param descriptions
- * The descriptions of each choice.
- * @param values
- * The choices.
- * @param helpCallback
- * An optional help call-back which can be used to display
- * additional help.
- * @return Returns the selected value.
- * @throws ArgumentException
- * If the user input could not be retrieved for some
- * reason.
- */
- public final <T> T readChoice(
- final Message prompt, List<Message> descriptions,
- List<T> values, final HelpCallback helpCallback)
- throws ArgumentException {
- Validator.ensureTrue(descriptions.size() == values.size());
-
- // Output main prompt.
- println();
- printMessage(prompt);
- println();
-
- // Build the table of choices.
- final TableBuilder builder = new TableBuilder();
- final int size = descriptions.size();
- for (int i = 0; i < size; i++) {
- builder.startRow();
- builder.appendCell("[" + (i + 1) + "]");
- builder.appendCell(descriptions.get(i));
- }
-
- // Display the table of choices.
- final TextTablePrinter printer = new TextTablePrinter(err);
- printer.setDisplayHeadings(false);
- printer.setColumnWidth(1, 0);
- builder.print(printer);
-
- // Get the user input.
- Message promptMsg;
- if (helpCallback != null) {
- promptMsg = INFO_DSCFG_GENERAL_CHOICE_PROMPT_HELP.get(size);
- } else {
- promptMsg = INFO_DSCFG_GENERAL_CHOICE_PROMPT_NOHELP.get(size);
- }
-
- ValidationCallback<Integer> validator = new ValidationCallback<Integer>() {
-
- public Integer validate(ConsoleApplication app, String input) {
- String ninput = input.trim();
-
- if (ninput.equals("?") && helpCallback != null) {
- app.println();
- helpCallback.display(app);
- app.println();
-
- // Output main prompt.
- printMessage(prompt);
- println();
- builder.print(printer);
-
- return null;
- } else {
- try {
- int i = Integer.parseInt(ninput);
- if (i < 1 || i > size) {
- throw new NumberFormatException();
- }
- return i;
- } catch (NumberFormatException e) {
- app.println();
- Message errMsg = ERR_DSCFG_ERROR_GENERAL_CHOICE.get(size);
- app.printMessage(errMsg);
- return null;
- }
- }
- }
- };
-
- // Get the choice.
- int choice;
- try {
- choice = readValidatedInput(promptMsg, validator);
- } catch (ClientException e) {
- // Should never happen.
- throw new RuntimeException(e);
- }
- return values.get(choice - 1);
- }
-
-
-
- /**
- * 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 ArgumentException
- * If the line of input could not be retrieved for some
- * reason.
- */
- public final String readLineOfInput(Message prompt) throws ArgumentException {
- err.println();
- err.print(wrapText(prompt.toString().trim() + " ", MAX_LINE_WIDTH));
- try {
- return in.readLine();
- } catch (IOException e) {
- throw ArgumentExceptionFactory.unableToReadConsoleInput(e);
- }
- }
-
-
-
- /**
- * Interactively retrieves a password from the console.
- *
- * @param prompt
- * The password prompt.
- * @return Returns the password.
- * @throws ArgumentException
- * If the password could not be retrieved for some reason.
- */
- public final String readPassword(Message prompt) throws ArgumentException {
- err.print(wrapText(prompt + " ", MAX_LINE_WIDTH));
- char[] pwChars;
- try {
- pwChars = PasswordReader.readPassword();
- } catch (Exception e) {
- throw ArgumentExceptionFactory.unableToReadConsoleInput(e);
- }
- return new String(pwChars);
- }
-
-
-
- /**
- * Interactively prompts for user input and continues until valid
- * input is provided.
- *
- * @param <T>
- * The type of decoded user input.
- * @param prompt
- * The interactive prompt which should be displayed on each
- * input attempt.
- * @param validator
- * An input validator responsible for validating and
- * decoding the user's response.
- * @return Returns the decoded user's response.
- * @throws ArgumentException
- * If the line of input could not be retrieved for some
- * reason.
- * @throws ClientException
- * If an unexpected error occurred which prevented
- * validation.
- */
- public final <T> T readValidatedInput(Message prompt,
- ValidationCallback<T> validator) throws ArgumentException,
- ClientException {
- while (true) {
- String response = readLineOfInput(prompt);
-
- if (response == null) {
- throw ArgumentExceptionFactory
- .unableToReadConsoleInput(new EOFException("End of input"));
- }
-
- T value = validator.validate(this, response);
- if (value != null) {
- return value;
- }
- }
- }
-}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
index 0b2034e..21bb850 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
@@ -25,13 +25,11 @@
* Portions Copyright 2007 Sun Microsystems, Inc.
*/
package org.opends.server.tools.dsconfig;
-import org.opends.messages.Message;
-import static org.opends.messages.ToolMessages.*;
+import static org.opends.messages.DSConfigMessages.*;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -44,6 +42,7 @@
import java.util.TreeMap;
import java.util.TreeSet;
+import org.opends.messages.Message;
import org.opends.server.admin.AbstractManagedObjectDefinition;
import org.opends.server.admin.Configuration;
import org.opends.server.admin.ConfigurationClient;
@@ -57,6 +56,7 @@
import org.opends.server.admin.ManagedObjectPath;
import org.opends.server.admin.OptionalRelationDefinition;
import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyDefinitionUsageBuilder;
import org.opends.server.admin.PropertyException;
import org.opends.server.admin.PropertyIsSingleValuedException;
import org.opends.server.admin.PropertyOption;
@@ -68,6 +68,7 @@
import org.opends.server.admin.client.IllegalManagedObjectNameException;
import org.opends.server.admin.client.ManagedObject;
import org.opends.server.admin.client.ManagedObjectDecodingException;
+import org.opends.server.admin.client.ManagementContext;
import org.opends.server.admin.client.MissingMandatoryPropertiesException;
import org.opends.server.admin.client.OperationRejectedException;
import org.opends.server.protocols.ldap.LDAPResultCode;
@@ -76,6 +77,13 @@
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.cli.CLIException;
+import org.opends.server.util.cli.ConsoleApplication;
+import org.opends.server.util.cli.HelpCallback;
+import org.opends.server.util.cli.Menu;
+import org.opends.server.util.cli.MenuBuilder;
+import org.opends.server.util.cli.MenuResult;
+import org.opends.server.util.cli.ValidationCallback;
import org.opends.server.util.table.TableBuilder;
import org.opends.server.util.table.TextTablePrinter;
@@ -94,7 +102,6 @@
final class CreateSubCommandHandler<C extends ConfigurationClient,
S extends Configuration> extends SubCommandHandler {
-
/**
* A property provider which uses the command-line arguments to
* provide initial property values.
@@ -220,7 +227,8 @@
/**
- * A help call-back which displays help about available component types.
+ * A help call-back which displays help about available component
+ * types.
*/
private final class TypeHelpCallback implements HelpCallback {
@@ -228,14 +236,15 @@
* {@inheritDoc}
*/
public void display(ConsoleApplication app) {
- // Create a table containing a description of each component type.
+ // Create a table containing a description of each component
+ // type.
TableBuilder builder = new TableBuilder();
- builder.appendHeading(
- INFO_DSCFG_DESCRIPTION_CREATE_HELP_HEADING_TYPE.get());
+ builder.appendHeading(INFO_DSCFG_DESCRIPTION_CREATE_HELP_HEADING_TYPE
+ .get());
- builder.appendHeading(
- INFO_DSCFG_DESCRIPTION_CREATE_HELP_HEADING_DESCR.get());
+ builder.appendHeading(INFO_DSCFG_DESCRIPTION_CREATE_HELP_HEADING_DESCR
+ .get());
boolean isFirst = true;
for (ManagedObjectDefinition<?, ?> d : types.values()) {
@@ -261,6 +270,8 @@
printer.setColumnWidth(1, 0);
printer.setColumnSeparator(":");
builder.print(printer);
+ app.println();
+ app.pressReturnToContinue();
}
}
@@ -300,8 +311,6 @@
* The type of managed object which can be created.
* @param <S>
* The type of server managed object which can be created.
- * @param app
- * The console application.
* @param parser
* The sub-command argument parser.
* @param p
@@ -314,10 +323,9 @@
*/
public static <C extends ConfigurationClient, S extends Configuration>
CreateSubCommandHandler<C, S> create(
- ConsoleApplication app, SubCommandArgumentParser parser,
- ManagedObjectPath<?, ?> p, InstantiableRelationDefinition<C, S> r)
- throws ArgumentException {
- return new CreateSubCommandHandler<C, S>(app, parser, p, r, r
+ SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
+ InstantiableRelationDefinition<C, S> r) throws ArgumentException {
+ return new CreateSubCommandHandler<C, S>(parser, p, r, r
.getNamingPropertyDefinition(), p.child(r, "DUMMY"));
}
@@ -330,8 +338,6 @@
* The type of managed object which can be created.
* @param <S>
* The type of server managed object which can be created.
- * @param app
- * The console application.
* @param parser
* The sub-command argument parser.
* @param p
@@ -344,11 +350,9 @@
*/
public static <C extends ConfigurationClient, S extends Configuration>
CreateSubCommandHandler<C, S> create(
- ConsoleApplication app, SubCommandArgumentParser parser,
- ManagedObjectPath<?, ?> p, OptionalRelationDefinition<C, S> r)
- throws ArgumentException {
- return new CreateSubCommandHandler<C, S>(app, parser, p, r, null, p
- .child(r));
+ SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
+ OptionalRelationDefinition<C, S> r) throws ArgumentException {
+ return new CreateSubCommandHandler<C, S>(parser, p, r, null, p.child(r));
}
// The sub-commands naming arguments.
@@ -377,7 +381,7 @@
// The set of instantiable managed object definitions and their
// associated type option value.
private final SortedMap<String,
- ManagedObjectDefinition<? extends C, ? extends S>> types;
+ ManagedObjectDefinition<? extends C, ? extends S>> types;
// The syntax of the type argument.
private final String typeUsage;
@@ -385,24 +389,20 @@
// Common constructor.
- private CreateSubCommandHandler(ConsoleApplication app,
- SubCommandArgumentParser parser,
- ManagedObjectPath<?, ?> p, RelationDefinition<C, S> r,
- PropertyDefinition<?> pd, ManagedObjectPath<?, ?> c)
- throws ArgumentException {
- super(app);
-
+ private CreateSubCommandHandler(
+ SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
+ RelationDefinition<C, S> r, PropertyDefinition<?> pd,
+ ManagedObjectPath<?, ?> c) throws ArgumentException {
this.path = p;
this.relation = r;
this.namingPropertyDefinition = pd;
// Create the sub-command.
String name = "create-" + r.getName();
- Message description = INFO_DSCFG_DESCRIPTION_SUBCMD_CREATE.get(
- r.getChildDefinition().getUserFriendlyPluralName()
- );
- this.subCommand = new SubCommand(parser, name, false, 0,
- 0, null, description);
+ Message description = INFO_DSCFG_DESCRIPTION_SUBCMD_CREATE.get(r
+ .getChildDefinition().getUserFriendlyPluralName());
+ this.subCommand = new SubCommand(parser, name, false, 0, 0, null,
+ description);
// Create the -t argument which is used to specify the type of
// managed object to be created.
@@ -418,9 +418,8 @@
// 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,
- INFO_DSCFG_DESCRIPTION_PROP_VAL.get());
+ OPTION_DSCFG_SHORT_SET, OPTION_DSCFG_LONG_SET, false, true, true,
+ "{PROP:VALUE}", null, null, INFO_DSCFG_DESCRIPTION_PROP_VAL.get());
this.subCommand.addArgument(this.propertySetArgument);
// Build the -t option usage.
@@ -463,6 +462,19 @@
/**
+ * Gets the relation definition associated with the type of
+ * component that this sub-command handles.
+ *
+ * @return Returns the relation definition associated with the type
+ * of component that this sub-command handles.
+ */
+ public RelationDefinition<?, ?> getRelationDefinition() {
+ return relation;
+ }
+
+
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -476,27 +488,57 @@
* {@inheritDoc}
*/
@Override
- public int run() throws ArgumentException, ClientException {
+ public MenuResult<Integer> run(ConsoleApplication app,
+ ManagementContextFactory factory) throws ArgumentException,
+ ClientException, CLIException {
// Determine the type of managed object to be created.
String typeName;
if (!typeArgument.isPresent()) {
- if (getConsoleApplication().isInteractive()) {
+ if (app.isInteractive()) {
// Let the user choose.
// If there is only one choice then return immediately.
if (types.size() == 1) {
typeName = types.keySet().iterator().next();
} else {
- List<String> values = new ArrayList<String>(types.keySet());
- List<Message> descriptions = new ArrayList<Message>(values.size());
- for (ManagedObjectDefinition<?, ?> d : types.values()) {
- descriptions.add(d.getUserFriendlyName());
+ MenuBuilder<String> builder = new MenuBuilder<String>(app);
+ Message msg = INFO_DSCFG_CREATE_TYPE_PROMPT.get(relation
+ .getChildDefinition().getUserFriendlyName());
+ builder.setMultipleColumnThreshold(MULTI_COLUMN_THRESHOLD);
+ builder.setPrompt(msg);
+
+ for (String type : types.keySet()) {
+ ManagedObjectDefinition<?, ?> d = types.get(type);
+ Message option = d.getUserFriendlyName();
+ if (type.equals(GENERIC_TYPE)) {
+ option = INFO_DSCFG_GENERIC_TYPE_OPTION.get(option);
+ }
+ builder.addNumberedOption(option, MenuResult.success(type));
}
- Message msg = INFO_DSCFG_CREATE_TYPE_PROMPT.get(
- relation.getChildDefinition().getUserFriendlyName());
- typeName = getConsoleApplication().readChoice(msg, descriptions,
- values, new TypeHelpCallback());
+ builder.addHelpOption(new TypeHelpCallback());
+ if (app.isMenuDrivenMode()) {
+ builder.addCancelOption(true);
+ }
+ builder.addQuitOption();
+
+ Menu<String> menu = builder.toMenu();
+ app.println();
+ app.println();
+ MenuResult<String> result = menu.run();
+ if (result.isSuccess()) {
+ typeName = result.getValue();
+ } else if (result.isCancel()) {
+ return MenuResult.cancel();
+ } else {
+ // Must be quit.
+ if (!app.isMenuDrivenMode()) {
+ msg = INFO_DSCFG_CONFIRM_CREATE_FAIL.get(relation
+ .getUserFriendlyName());
+ app.printVerboseMessage(msg);
+ }
+ return MenuResult.quit();
+ }
}
} else if (typeArgument.getDefaultValue() != null) {
typeName = typeArgument.getDefaultValue();
@@ -515,7 +557,7 @@
}
// Get the naming argument values.
- List<String> names = getNamingArgValues(namingArgs);
+ List<String> names = getNamingArgValues(app, namingArgs);
// Encode the provided properties.
List<String> propertyArgs = propertySetArgument.getValues();
@@ -523,13 +565,13 @@
namingPropertyDefinition, propertyArgs);
// Add the child managed object.
- ManagedObject<?> parent;
+ ManagementContext context = factory.getManagementContext(app);
+ MenuResult<ManagedObject<?>> result;
try {
- parent = getManagedObject(path, names);
+ result = getManagedObject(app, context, path, names);
} catch (AuthorizationException e) {
Message msg = ERR_DSCFG_ERROR_CREATE_AUTHZ.get(d.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
- msg);
+ throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS, msg);
} catch (DefinitionDecodingException e) {
Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_PARENT_DDE.get(ufn, ufn, ufn);
@@ -539,19 +581,32 @@
Message msg = ERR_DSCFG_ERROR_GET_PARENT_MODE.get(ufn);
throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
} catch (CommunicationException e) {
- Message msg = ERR_DSCFG_ERROR_CREATE_CE.get(
- d.getUserFriendlyName(), e.getMessage());
+ Message msg = ERR_DSCFG_ERROR_CREATE_CE.get(d.getUserFriendlyName(), e
+ .getMessage());
throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msg);
} catch (ConcurrentModificationException e) {
Message msg = ERR_DSCFG_ERROR_CREATE_CME.get(d.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
- msg);
+ throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
} catch (ManagedObjectNotFoundException e) {
Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_PARENT_MONFE.get(ufn);
throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msg);
}
+ if (result.isQuit()) {
+ if (!app.isMenuDrivenMode()) {
+ // User chose to cancel creation.
+ Message msg = INFO_DSCFG_CONFIRM_CREATE_FAIL.get(d
+ .getUserFriendlyName());
+ app.printVerboseMessage(msg);
+ }
+ return MenuResult.quit();
+ } else if (result.isCancel()) {
+ // Must be menu driven, so no need for error message.
+ return MenuResult.cancel();
+ }
+
+ ManagedObject<?> parent = result.getValue();
try {
ManagedObject<? extends C> child;
List<DefaultBehaviorException> exceptions =
@@ -561,8 +616,9 @@
(InstantiableRelationDefinition<C, S>) relation;
String name = names.get(names.size() - 1);
if (name == null) {
- if (getConsoleApplication().isInteractive()) {
- child = createChildInteractively(parent, irelation, d, exceptions);
+ if (app.isInteractive()) {
+ child = createChildInteractively(app, parent, irelation,
+ d, exceptions);
} else {
throw ArgumentExceptionFactory
.missingMandatoryNonInteractiveArgument(namingArgs.get(names
@@ -570,7 +626,8 @@
}
} else {
try {
- child = parent.createChild(irelation, d, name, exceptions);
+ child = parent.createChild(irelation, d, name,
+ exceptions);
} catch (IllegalManagedObjectNameException e) {
throw ArgumentExceptionFactory
.adaptIllegalManagedObjectNameException(e, d);
@@ -591,7 +648,7 @@
}
// Interactively set properties if applicable.
- if (getConsoleApplication().isInteractive()) {
+ if (app.isInteractive()) {
SortedSet<PropertyDefinition<?>> properties =
new TreeSet<PropertyDefinition<?>>();
@@ -600,10 +657,6 @@
continue;
}
- if (pd.hasOption(PropertyOption.MONITORING)) {
- continue;
- }
-
if (!isAdvancedMode() && pd.hasOption(PropertyOption.ADVANCED)) {
continue;
}
@@ -611,72 +664,65 @@
properties.add(pd);
}
- PropertyValueReader reader =
- new PropertyValueReader(getConsoleApplication());
- reader.readAll(child, properties);
- }
-
- // Confirm commit.
- Message prompt = INFO_DSCFG_CONFIRM_CREATE.get(d.getUserFriendlyName());
- if (!getConsoleApplication().confirmAction(prompt)) {
- // Output failure message.
- Message msg =
- INFO_DSCFG_CONFIRM_CREATE_FAIL.get(d.getUserFriendlyName());
- getConsoleApplication().printVerboseMessage(msg);
- return 1;
+ PropertyValueEditor editor = new PropertyValueEditor(app);
+ MenuResult<Void> result2 = editor.edit(child, properties, true);
+ if (result2.isQuit()) {
+ if (!app.isMenuDrivenMode()) {
+ Message msg = INFO_DSCFG_CONFIRM_CREATE_FAIL.get(d
+ .getUserFriendlyName());
+ app.printVerboseMessage(msg);
+ }
+ return MenuResult.quit();
+ } else if (result2.isCancel()) {
+ return MenuResult.cancel();
+ }
}
// Add the managed object.
child.commit();
// Output success message.
- Message msg =
- INFO_DSCFG_CONFIRM_CREATE_SUCCESS.get(d.getUserFriendlyName());
- getConsoleApplication().printVerboseMessage(msg);
+ Message msg = INFO_DSCFG_CONFIRM_CREATE_SUCCESS.get(d
+ .getUserFriendlyName());
+ app.printVerboseMessage(msg);
} catch (MissingMandatoryPropertiesException e) {
throw ArgumentExceptionFactory.adaptMissingMandatoryPropertiesException(
e, d);
} catch (AuthorizationException e) {
Message msg = ERR_DSCFG_ERROR_CREATE_AUTHZ.get(d.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
- msg);
+ throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS, msg);
} catch (ManagedObjectAlreadyExistsException e) {
Message msg = ERR_DSCFG_ERROR_CREATE_MOAEE.get(d.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.ENTRY_ALREADY_EXISTS,
- msg);
+ throw new ClientException(LDAPResultCode.ENTRY_ALREADY_EXISTS, msg);
} catch (ConcurrentModificationException e) {
Message msg = ERR_DSCFG_ERROR_CREATE_CME.get(d.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
- msg);
+ throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
} catch (OperationRejectedException e) {
- Message msg = ERR_DSCFG_ERROR_CREATE_ORE.get(
- d.getUserFriendlyName(), e.getMessage());
- throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
- msg);
+ Message msg = ERR_DSCFG_ERROR_CREATE_ORE.get(d.getUserFriendlyName(), e
+ .getMessage());
+ throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
} catch (CommunicationException e) {
- Message msg = ERR_DSCFG_ERROR_CREATE_CE.get(
- d.getUserFriendlyName(), e.getMessage());
+ Message msg = ERR_DSCFG_ERROR_CREATE_CE.get(d.getUserFriendlyName(), e
+ .getMessage());
throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msg);
}
- return 0;
+ return MenuResult.success(0);
}
// Interactively create the child by prompting for the name.
private ManagedObject<? extends C> createChildInteractively(
- final ManagedObject<?> parent,
+ ConsoleApplication app, final ManagedObject<?> parent,
final InstantiableRelationDefinition<C, S> irelation,
final ManagedObjectDefinition<? extends C, ? extends S> d,
- final List<DefaultBehaviorException> exceptions)
- throws ArgumentException, ClientException {
- Message msg = INFO_DSCFG_CREATE_NAME_PROMPT.get(d.getUserFriendlyName());
+ final List<DefaultBehaviorException> exceptions) throws CLIException {
ValidationCallback<ManagedObject<? extends C>> validator =
new ValidationCallback<ManagedObject<? extends C>>() {
public ManagedObject<? extends C> validate(ConsoleApplication app,
- String input) throws ClientException {
+ String input) throws CLIException {
ManagedObject<? extends C> child;
// First attempt to create the child, this will guarantee that
@@ -684,10 +730,11 @@
try {
child = parent.createChild(irelation, d, input, exceptions);
} catch (IllegalManagedObjectNameException e) {
- ArgumentException ae = ArgumentExceptionFactory
+ CLIException ae = ArgumentExceptionFactory
.adaptIllegalManagedObjectNameException(e, d);
app.println();
- app.printMessage(ae.getMessageObject());
+ app.println(ae.getMessageObject());
+ app.println();
return null;
}
@@ -697,19 +744,17 @@
// Attempt to retrieve a child using this name.
parent.getChild(irelation, input);
} catch (AuthorizationException e) {
- Message msg =
- ERR_DSCFG_ERROR_CREATE_AUTHZ.get(irelation.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
- msg);
+ Message msg = ERR_DSCFG_ERROR_CREATE_AUTHZ.get(irelation
+ .getUserFriendlyName());
+ throw new CLIException(msg);
} catch (ConcurrentModificationException e) {
- Message msg =
- ERR_DSCFG_ERROR_CREATE_CME.get(irelation.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
+ Message msg = ERR_DSCFG_ERROR_CREATE_CME.get(irelation
+ .getUserFriendlyName());
+ throw new CLIException(msg);
} catch (CommunicationException e) {
- Message msg = ERR_DSCFG_ERROR_CREATE_CE.get(
- irelation.getUserFriendlyName(), e.getMessage());
- throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN,
- msg);
+ Message msg = ERR_DSCFG_ERROR_CREATE_CE.get(irelation
+ .getUserFriendlyName(), e.getMessage());
+ throw new CLIException(msg);
} catch (DefinitionDecodingException e) {
// Do nothing.
} catch (ManagedObjectDecodingException e) {
@@ -720,16 +765,45 @@
}
// A child with the specified name must already exist.
- Message msg = ERR_DSCFG_ERROR_CREATE_NAME_ALREADY_EXISTS.get(
- relation.getUserFriendlyName(), input);
+ Message msg = ERR_DSCFG_ERROR_CREATE_NAME_ALREADY_EXISTS.get(relation
+ .getUserFriendlyName(), input);
app.println();
- app.printMessage(msg);
+ app.println(msg);
+ app.println();
return null;
}
};
- return getConsoleApplication().readValidatedInput(msg, validator);
+ app.println();
+ app.println();
+
+ // Display additional help if the name is a naming property.
+ Message ufn = d.getUserFriendlyName();
+ PropertyDefinition<?> pd = irelation.getNamingPropertyDefinition();
+ if (pd != null) {
+ app.println(INFO_DSCFG_CREATE_NAME_PROMPT_NAMING.get(ufn, pd.getName()));
+
+ app.println();
+ app.println(pd.getSynopsis(), 4);
+
+ if (pd.getDescription() != null) {
+ app.println();
+ app.println(pd.getDescription(), 4);
+ }
+
+ PropertyDefinitionUsageBuilder b = new PropertyDefinitionUsageBuilder(
+ true);
+ app.println();
+ app.println(INFO_EDITOR_HEADING_SYNTAX.get(b.getUsage(pd)), 4);
+ app.println();
+
+ return app.readValidatedInput(INFO_DSCFG_CREATE_NAME_PROMPT_NAMING_CONT
+ .get(ufn), validator);
+ } else {
+ return app.readValidatedInput(INFO_DSCFG_CREATE_NAME_PROMPT.get(ufn),
+ validator);
+ }
}
@@ -752,8 +826,8 @@
// Process its sub-definitions.
String suffix = "-" + d.getName();
- for (AbstractManagedObjectDefinition<? extends C, ? extends S> c :
- d.getAllChildren()) {
+ for (AbstractManagedObjectDefinition<? extends C, ? extends S> c : d
+ .getAllChildren()) {
if (c instanceof ManagedObjectDefinition) {
ManagedObjectDefinition<? extends C, ? extends S> mod =
(ManagedObjectDefinition<? extends C, ? extends S>) c;
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java b/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java
index 6b452e6..bb63ea4 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java
@@ -25,12 +25,12 @@
* Portions Copyright 2007 Sun Microsystems, Inc.
*/
package org.opends.server.tools.dsconfig;
-import org.opends.messages.Message;
-import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.messages.DSConfigMessages.*;
import static org.opends.messages.ToolMessages.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.tools.ToolConstants.*;
import static org.opends.server.util.StaticUtils.*;
@@ -39,18 +39,21 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
+import org.opends.messages.Message;
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.InstantiableRelationDefinition;
import org.opends.server.admin.PropertyException;
+import org.opends.server.admin.RelationDefinition;
import org.opends.server.admin.Tag;
import org.opends.server.admin.client.ManagedObjectDecodingException;
-import org.opends.server.admin.client.ManagementContext;
import org.opends.server.admin.client.cli.SecureConnectionCliParser;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.tools.ClientException;
@@ -62,6 +65,13 @@
import org.opends.server.util.args.BooleanArgument;
import org.opends.server.util.args.SubCommand;
import org.opends.server.util.args.SubCommandArgumentParser;
+import org.opends.server.util.cli.CLIException;
+import org.opends.server.util.cli.ConsoleApplication;
+import org.opends.server.util.cli.Menu;
+import org.opends.server.util.cli.MenuBuilder;
+import org.opends.server.util.cli.MenuCallback;
+import org.opends.server.util.cli.MenuResult;
+import org.opends.server.util.cli.OutputStreamConsoleApplication;
import org.opends.server.util.table.TableBuilder;
import org.opends.server.util.table.TextTablePrinter;
@@ -74,6 +84,172 @@
public final class DSConfig extends ConsoleApplication {
/**
+ * A menu call-back which runs a sub-command interactively.
+ */
+ public class SubCommandHandlerMenuCallback implements MenuCallback<Integer> {
+
+ // The sub-command handler.
+ private final SubCommandHandler handler;
+
+
+
+ /**
+ * Creates a new sub-command handler call-back.
+ *
+ * @param handler
+ * The sub-command handler.
+ */
+ public SubCommandHandlerMenuCallback(SubCommandHandler handler) {
+ this.handler = handler;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public MenuResult<Integer> invoke(ConsoleApplication app)
+ throws CLIException {
+ try {
+ MenuResult<Integer> result = handler.run(app, factory);
+
+ if (result.isQuit()) {
+ return result;
+ } else {
+ // Success or cancel.
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.again();
+ }
+ } catch (ArgumentException e) {
+ app.println(e.getMessageObject());
+ return MenuResult.success(1);
+ } catch (ClientException e) {
+ app.println(e.getMessageObject());
+ return MenuResult.success(e.getExitCode());
+ }
+ }
+ }
+
+
+
+ /**
+ * The interactive mode sub-menu implementation.
+ */
+ public class SubMenuCallback implements MenuCallback<Integer> {
+
+ // The menu.
+ private final Menu<Integer> menu;
+
+
+
+ /**
+ * Creates a new sub-menu implementation.
+ *
+ * @param app
+ * The console application.
+ * @param rd
+ * The relation definition.
+ * @param ch
+ * The optional create sub-command.
+ * @param dh
+ * The optional delete sub-command.
+ * @param lh
+ * The optional list sub-command.
+ * @param sh
+ * The option set-prop sub-command.
+ */
+ public SubMenuCallback(ConsoleApplication app, RelationDefinition<?, ?> rd,
+ CreateSubCommandHandler<?, ?> ch, DeleteSubCommandHandler dh,
+ ListSubCommandHandler lh, SetPropSubCommandHandler sh) {
+ Message ufn = rd.getUserFriendlyName();
+
+ Message ufpn = null;
+ if (rd instanceof InstantiableRelationDefinition) {
+ InstantiableRelationDefinition<?, ?> ir =
+ (InstantiableRelationDefinition<?, ?>) rd;
+ ufpn = ir.getUserFriendlyPluralName();
+ }
+
+ MenuBuilder<Integer> builder = new MenuBuilder<Integer>(app);
+
+ builder.setTitle(INFO_DSCFG_HEADING_COMPONENT_MENU_TITLE.get(ufn));
+ builder.setPrompt(INFO_DSCFG_HEADING_COMPONENT_MENU_PROMPT.get());
+
+ if (lh != null) {
+ SubCommandHandlerMenuCallback callback =
+ new SubCommandHandlerMenuCallback(lh);
+ if (ufpn != null) {
+ builder.addNumberedOption(
+ INFO_DSCFG_OPTION_COMPONENT_MENU_LIST_PLURAL.get(ufpn), callback);
+ } else {
+ builder
+ .addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_LIST_SINGULAR
+ .get(ufn), callback);
+ }
+ }
+
+ if (ch != null) {
+ SubCommandHandlerMenuCallback callback =
+ new SubCommandHandlerMenuCallback(ch);
+ builder.addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_CREATE
+ .get(ufn), callback);
+ }
+
+ if (sh != null) {
+ SubCommandHandlerMenuCallback callback =
+ new SubCommandHandlerMenuCallback(sh);
+ if (ufpn != null) {
+ builder
+ .addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_MODIFY_PLURAL
+ .get(ufn), callback);
+ } else {
+ builder.addNumberedOption(
+ INFO_DSCFG_OPTION_COMPONENT_MENU_MODIFY_SINGULAR.get(ufn),
+ callback);
+ }
+ }
+
+ if (dh != null) {
+ SubCommandHandlerMenuCallback callback =
+ new SubCommandHandlerMenuCallback(dh);
+ builder.addNumberedOption(INFO_DSCFG_OPTION_COMPONENT_MENU_DELETE
+ .get(ufn), callback);
+ }
+
+ builder.addBackOption(true);
+ builder.addQuitOption();
+
+ this.menu = builder.toMenu();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public final MenuResult<Integer> invoke(ConsoleApplication app)
+ throws CLIException {
+ try {
+ app.println();
+ app.println();
+
+ MenuResult<Integer> result = menu.run();
+
+ if (result.isCancel()) {
+ return MenuResult.again();
+ }
+
+ return result;
+ } catch (CLIException e) {
+ app.println(e.getMessageObject());
+ return MenuResult.success(1);
+ }
+ }
+
+ }
+
+ /**
* The tracer object for the debug logger.
*/
private static final DebugTracer TRACER = getTracer();
@@ -126,7 +302,7 @@
app.initializeClientEnvironment();
} catch (InitializationException e) {
// TODO: is this ok as an error message?
- app.printMessage(e.getMessageObject());
+ app.println(e.getMessageObject());
return 1;
}
}
@@ -147,10 +323,16 @@
// already been initialized.
private boolean globalArgumentsInitialized = false;
+ // The sub-command handler factory.
+ private SubCommandHandlerFactory handlerFactory = null;
+
// Mapping of sub-commands to their implementations;
private final Map<SubCommand, SubCommandHandler> handlers =
new HashMap<SubCommand, SubCommandHandler>();
+ // Indicates whether or not a sub-command was provided.
+ private boolean hasSubCommand = true;
+
// The argument which should be used to request non interactive
// behavior.
private BooleanArgument noPromptArgument;
@@ -168,10 +350,6 @@
// 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;
@@ -240,6 +418,16 @@
/**
* {@inheritDoc}
*/
+ @Override
+ public boolean isMenuDrivenMode() {
+ return !hasSubCommand;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
public boolean isQuiet() {
return quietArgument.isPresent();
}
@@ -264,21 +452,11 @@
- /**
- * {@inheritDoc}
- */
- public ManagementContext getManagementContext() throws ArgumentException,
- ClientException {
- return factory.getManagementContext(this);
- }
-
-
-
// Displays the provided message followed by a help usage reference.
private void displayMessageAndUsageReference(Message message) {
- printMessage(message);
- printMessage(Message.EMPTY);
- printMessage(parser.getHelpUsageReference());
+ println(message);
+ println();
+ println(parser.getHelpUsageReference());
}
@@ -297,8 +475,8 @@
quietArgument = new BooleanArgument(
SecureConnectionCliParser.QUIET_OPTION_LONG,
SecureConnectionCliParser.QUIET_OPTION_SHORT,
- SecureConnectionCliParser.QUIET_OPTION_LONG,
- INFO_DESCRIPTION_QUIET.get());
+ SecureConnectionCliParser.QUIET_OPTION_LONG, INFO_DESCRIPTION_QUIET
+ .get());
scriptFriendlyArgument = new BooleanArgument("script-friendly", 's',
"script-friendly", INFO_DESCRIPTION_SCRIPT_FRIENDLY.get());
@@ -310,8 +488,8 @@
INFO_DESCRIPTION_NO_PROMPT.get());
showUsageArgument = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
- OPTION_LONG_HELP,
- INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_SUMMARY.get());
+ OPTION_LONG_HELP, INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_SUMMARY
+ .get());
// Register the global arguments.
parser.addGlobalArgument(showUsageArgument);
@@ -340,7 +518,9 @@
* If a sub-command could not be created.
*/
private void initializeSubCommands() throws ArgumentException {
- if (subCommandsInitialized == false) {
+ if (handlerFactory == null) {
+ handlerFactory = new SubCommandHandlerFactory(parser);
+
Comparator<SubCommand> c = new Comparator<SubCommand>() {
public int compare(SubCommand o1, SubCommand o2) {
@@ -348,12 +528,11 @@
}
};
- 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(this,
- parser)) {
+ for (SubCommandHandler handler : handlerFactory
+ .getAllSubCommandHandlers()) {
SubCommand sc = handler.getSubCommand();
handlers.put(sc, handler);
@@ -391,8 +570,6 @@
parser.addGlobalArgument(arg);
parser.setUsageGroupArgument(arg, allSubCommands);
-
- subCommandsInitialized = true;
}
}
@@ -415,7 +592,7 @@
initializeSubCommands();
} catch (ArgumentException e) {
Message message = ERR_CANNOT_INITIALIZE_ARGS.get(e.getMessage());
- printMessage(message);
+ println(message);
return 1;
}
@@ -434,26 +611,18 @@
return 0;
}
- // Make sure that we have a sub-command.
- if (parser.getSubCommand() == null) {
- Message message = ERR_ERROR_PARSING_ARGS.get(
- ERR_DSCFG_ERROR_MISSING_SUBCOMMAND.get());
- displayMessageAndUsageReference(message);
- return 1;
- }
-
+ // Check for conflicting arguments.
if (quietArgument.isPresent() && verboseArgument.isPresent()) {
- Message message = ERR_TOOL_CONFLICTING_ARGS.get(
- quietArgument.getLongIdentifier(),
- verboseArgument.getLongIdentifier());
+ Message message = ERR_TOOL_CONFLICTING_ARGS.get(quietArgument
+ .getLongIdentifier(), verboseArgument.getLongIdentifier());
displayMessageAndUsageReference(message);
return 1;
}
if (quietArgument.isPresent() && !noPromptArgument.isPresent()) {
Message message = ERR_DSCFG_ERROR_QUIET_AND_INTERACTIVE_INCOMPATIBLE.get(
- quietArgument.getLongIdentifier(),
- noPromptArgument.getLongIdentifier());
+ quietArgument.getLongIdentifier(), noPromptArgument
+ .getLongIdentifier());
displayMessageAndUsageReference(message);
return 1;
}
@@ -469,28 +638,177 @@
try {
factory.validateGlobalArguments();
} catch (ArgumentException e) {
- printMessage(e.getMessageObject());
+ println(e.getMessageObject());
return 1;
}
- // Retrieve the sub-command implementation and run it.
- SubCommandHandler handler = handlers.get(parser.getSubCommand());
+ if (parser.getSubCommand() == null) {
+ hasSubCommand = false;
+
+ if (isInteractive()) {
+ // Top-level interactive mode.
+ return runInteractiveMode();
+ } else {
+ Message message = ERR_ERROR_PARSING_ARGS
+ .get(ERR_DSCFG_ERROR_MISSING_SUBCOMMAND.get());
+ displayMessageAndUsageReference(message);
+ return 1;
+ }
+ } else {
+ hasSubCommand = true;
+
+ // Retrieve the sub-command implementation and run it.
+ SubCommandHandler handler = handlers.get(parser.getSubCommand());
+ return runSubCommand(handler);
+ }
+ }
+
+
+
+ // Run the top-level interactive console.
+ private int runInteractiveMode() {
+ // In interactive mode, redirect all output to stdout.
+ ConsoleApplication app = new OutputStreamConsoleApplication(this);
+
+ // Build menu structure.
+ Comparator<RelationDefinition<?, ?>> c =
+ new Comparator<RelationDefinition<?, ?>>() {
+
+ public int compare(RelationDefinition<?, ?> rd1,
+ RelationDefinition<?, ?> rd2) {
+ String s1 = rd1.getUserFriendlyName().toString();
+ String s2 = rd2.getUserFriendlyName().toString();
+
+ return s1.compareToIgnoreCase(s2);
+ }
+
+ };
+
+ Set<RelationDefinition<?, ?>> relations;
+ Map<RelationDefinition<?, ?>, CreateSubCommandHandler<?, ?>> createHandlers;
+ Map<RelationDefinition<?, ?>, DeleteSubCommandHandler> deleteHandlers;
+ Map<RelationDefinition<?, ?>, ListSubCommandHandler> listHandlers;
+ Map<RelationDefinition<?, ?>, GetPropSubCommandHandler> getPropHandlers;
+ Map<RelationDefinition<?, ?>, SetPropSubCommandHandler> setPropHandlers;
+
+ relations = new TreeSet<RelationDefinition<?, ?>>(c);
+ createHandlers =
+ new HashMap<RelationDefinition<?, ?>, CreateSubCommandHandler<?, ?>>();
+ deleteHandlers =
+ new HashMap<RelationDefinition<?, ?>, DeleteSubCommandHandler>();
+ listHandlers =
+ new HashMap<RelationDefinition<?, ?>, ListSubCommandHandler>();
+ getPropHandlers =
+ new HashMap<RelationDefinition<?, ?>, GetPropSubCommandHandler>();
+ setPropHandlers =
+ new HashMap<RelationDefinition<?, ?>, SetPropSubCommandHandler>();
+
+ for (CreateSubCommandHandler<?, ?> ch : handlerFactory
+ .getCreateSubCommandHandlers()) {
+ relations.add(ch.getRelationDefinition());
+ createHandlers.put(ch.getRelationDefinition(), ch);
+ }
+
+ for (DeleteSubCommandHandler dh : handlerFactory
+ .getDeleteSubCommandHandlers()) {
+ relations.add(dh.getRelationDefinition());
+ deleteHandlers.put(dh.getRelationDefinition(), dh);
+ }
+
+ for (ListSubCommandHandler lh :
+ handlerFactory.getListSubCommandHandlers()) {
+ relations.add(lh.getRelationDefinition());
+ listHandlers.put(lh.getRelationDefinition(), lh);
+ }
+
+ for (GetPropSubCommandHandler gh : handlerFactory
+ .getGetPropSubCommandHandlers()) {
+ relations.add(gh.getRelationDefinition());
+ getPropHandlers.put(gh.getRelationDefinition(), gh);
+ }
+
+ for (SetPropSubCommandHandler sh : handlerFactory
+ .getSetPropSubCommandHandlers()) {
+ relations.add(sh.getRelationDefinition());
+ setPropHandlers.put(sh.getRelationDefinition(), sh);
+ }
+
+ // Main menu.
+ MenuBuilder<Integer> builder = new MenuBuilder<Integer>(app);
+
+ builder.setTitle(INFO_DSCFG_HEADING_MAIN_MENU_TITLE.get());
+ builder.setPrompt(INFO_DSCFG_HEADING_MAIN_MENU_PROMPT.get());
+ builder.setMultipleColumnThreshold(0);
+
+ for (RelationDefinition<?, ?> rd : relations) {
+ MenuCallback<Integer> callback = new SubMenuCallback(app, rd,
+ createHandlers.get(rd), deleteHandlers.get(rd), listHandlers.get(rd),
+ setPropHandlers.get(rd));
+ builder.addNumberedOption(rd.getUserFriendlyName(), callback);
+ }
+
+ builder.addQuitOption();
+
+ Menu<Integer> menu = builder.toMenu();
+
try {
- return handler.run();
+ // Force retrieval of management context.
+ factory.getManagementContext(app);
} catch (ArgumentException e) {
- printMessage(e.getMessageObject());
+ app.println(e.getMessageObject());
+ return 1;
+ } catch (ClientException e) {
+ app.println(e.getMessageObject());
+ return 1;
+ }
+
+ try {
+ app.println();
+ app.println();
+
+ MenuResult<Integer> result = menu.run();
+
+ if (result.isQuit()) {
+ return 0;
+ } else {
+ return result.getValue();
+ }
+ } catch (CLIException e) {
+ app.println(e.getMessageObject());
+ return 1;
+ }
+ }
+
+
+
+ // Run the provided sub-command handler.
+ private int runSubCommand(SubCommandHandler handler) {
+ try {
+ MenuResult<Integer> result = handler.run(this, factory);
+
+ if (result.isSuccess()) {
+ return result.getValue();
+ } else {
+ // User must have quit.
+ return 1;
+ }
+ } catch (ArgumentException e) {
+ println(e.getMessageObject());
+ return 1;
+ } catch (CLIException e) {
+ println(e.getMessageObject());
return 1;
} catch (ClientException e) {
// If the client exception was caused by a decoding exception
// then we should display the causes.
- printMessage(e.getMessageObject());
+ println(e.getMessageObject());
Throwable cause = e.getCause();
if (cause instanceof ManagedObjectDecodingException) {
ManagedObjectDecodingException de =
(ManagedObjectDecodingException) cause;
- printMessage(Message.EMPTY);
+ println();
TableBuilder builder = new TableBuilder();
for (PropertyException pe : de.getCauses()) {
AbstractManagedObjectDefinition<?, ?> d = de
@@ -506,7 +824,7 @@
printer.setDisplayHeadings(false);
printer.setColumnWidth(1, 0);
builder.print(printer);
- printMessage(Message.EMPTY);
+ println();
}
return 1;
@@ -514,7 +832,7 @@
if (debugEnabled()) {
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
- printMessage(Message.raw(StaticUtils.stackTraceToString(e)));
+ println(Message.raw(StaticUtils.stackTraceToString(e)));
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
index cced653..e24bbfd 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/DeleteSubCommandHandler.java
@@ -25,14 +25,14 @@
* Portions Copyright 2007 Sun Microsystems, Inc.
*/
package org.opends.server.tools.dsconfig;
-import org.opends.messages.Message;
-import static org.opends.messages.ToolMessages.*;
+import static org.opends.messages.DSConfigMessages.*;
import java.util.List;
+import org.opends.messages.Message;
import org.opends.server.admin.DefinitionDecodingException;
import org.opends.server.admin.InstantiableRelationDefinition;
import org.opends.server.admin.ManagedObjectNotFoundException;
@@ -44,6 +44,7 @@
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;
@@ -52,6 +53,9 @@
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.cli.CLIException;
+import org.opends.server.util.cli.ConsoleApplication;
+import org.opends.server.util.cli.MenuResult;
@@ -79,8 +83,6 @@
* Creates a new delete-xxx sub-command for an instantiable
* relation.
*
- * @param app
- * The console application.
* @param parser
* The sub-command argument parser.
* @param p
@@ -91,10 +93,10 @@
* @throws ArgumentException
* If the sub-command could not be created successfully.
*/
- public static DeleteSubCommandHandler create(ConsoleApplication app,
+ public static DeleteSubCommandHandler create(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
InstantiableRelationDefinition<?, ?> r) throws ArgumentException {
- return new DeleteSubCommandHandler(app, parser, p, r, p.child(r, "DUMMY"));
+ return new DeleteSubCommandHandler(parser, p, r, p.child(r, "DUMMY"));
}
@@ -102,8 +104,6 @@
/**
* Creates a new delete-xxx sub-command for an optional relation.
*
- * @param app
- * The console application.
* @param parser
* The sub-command argument parser.
* @param p
@@ -114,10 +114,10 @@
* @throws ArgumentException
* If the sub-command could not be created successfully.
*/
- public static DeleteSubCommandHandler create(ConsoleApplication app,
+ public static DeleteSubCommandHandler create(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
OptionalRelationDefinition<?, ?> r) throws ArgumentException {
- return new DeleteSubCommandHandler(app, parser, p, r, p.child(r));
+ return new DeleteSubCommandHandler(parser, p, r, p.child(r));
}
// The argument which should be used to force deletion.
@@ -139,12 +139,10 @@
// Private constructor.
- private DeleteSubCommandHandler(ConsoleApplication app,
+ private DeleteSubCommandHandler(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
RelationDefinition<?, ?> r, ManagedObjectPath<?, ?> c)
throws ArgumentException {
- super(app);
-
this.path = p;
this.relation = r;
@@ -171,6 +169,19 @@
/**
+ * Gets the relation definition associated with the type of
+ * component that this sub-command handles.
+ *
+ * @return Returns the relation definition associated with the type
+ * of component that this sub-command handles.
+ */
+ public RelationDefinition<?, ?> getRelationDefinition() {
+ return relation;
+ }
+
+
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -184,19 +195,21 @@
* {@inheritDoc}
*/
@Override
- public int run() throws ArgumentException, ClientException {
+ public MenuResult<Integer> run(ConsoleApplication app,
+ ManagementContextFactory factory) throws ArgumentException,
+ ClientException, CLIException {
// Get the naming argument values.
- List<String> names = getNamingArgValues(namingArgs);
+ List<String> names = getNamingArgValues(app, namingArgs);
// Delete the child managed object.
- ManagedObject<?> parent = null;
+ ManagementContext context = factory.getManagementContext(app);
+ MenuResult<ManagedObject<?>> result;
try {
- parent = getManagedObject(path, names);
+ result = getManagedObject(app, context, path, names);
} catch (AuthorizationException e) {
- Message msg =
- ERR_DSCFG_ERROR_DELETE_AUTHZ.get(relation.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
- msg);
+ Message msg = ERR_DSCFG_ERROR_DELETE_AUTHZ.get(relation
+ .getUserFriendlyName());
+ throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS, msg);
} catch (DefinitionDecodingException e) {
Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_PARENT_DDE.get(ufn, ufn, ufn);
@@ -206,95 +219,124 @@
Message msg = ERR_DSCFG_ERROR_GET_PARENT_MODE.get(ufn);
throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
} catch (CommunicationException e) {
- Message msg = ERR_DSCFG_ERROR_DELETE_CE.get(
- relation.getUserFriendlyName(), e.getMessage());
+ Message msg = ERR_DSCFG_ERROR_DELETE_CE.get(relation
+ .getUserFriendlyName(), e.getMessage());
throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msg);
} catch (ConcurrentModificationException e) {
- Message msg =
- ERR_DSCFG_ERROR_DELETE_CME.get(relation.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
- msg);
+ Message msg = ERR_DSCFG_ERROR_DELETE_CME.get(relation
+ .getUserFriendlyName());
+ throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
} catch (ManagedObjectNotFoundException e) {
// Ignore the error if the deletion is being forced.
if (!forceArgument.isPresent()) {
Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_PARENT_MONFE.get(ufn);
throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msg);
+ } else {
+ return MenuResult.success(0);
}
}
- if (parent != null) {
- try {
- if (relation instanceof InstantiableRelationDefinition) {
- InstantiableRelationDefinition<?, ?> irelation =
- (InstantiableRelationDefinition<?, ?>) relation;
- String childName = names.get(names.size() - 1);
- if (childName == null) {
- childName = readChildName(parent, irelation, null);
- }
-
- if (confirmDeletion()) {
- parent.removeChild(irelation, childName);
- } else {
- return 1;
- }
- } else if (relation instanceof OptionalRelationDefinition) {
- OptionalRelationDefinition<?, ?> orelation =
- (OptionalRelationDefinition<?, ?>) relation;
-
- if (confirmDeletion()) {
- parent.removeChild(orelation);
- } else {
- return 1;
- }
- }
- } catch (AuthorizationException e) {
- Message msg =
- ERR_DSCFG_ERROR_DELETE_AUTHZ.get(relation.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
- msg);
- } catch (OperationRejectedException e) {
- Message msg = ERR_DSCFG_ERROR_DELETE_ORE.get(
- relation.getUserFriendlyName(), e.getMessage());
- throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
- } catch (ManagedObjectNotFoundException e) {
- // Ignore the error if the deletion is being forced.
- if (!forceArgument.isPresent()) {
- Message msg =
- ERR_DSCFG_ERROR_DELETE_MONFE.get(relation.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msg);
- }
- } catch (ConcurrentModificationException e) {
- Message msg =
- ERR_DSCFG_ERROR_DELETE_CME.get(relation.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
- } catch (CommunicationException e) {
- Message msg = ERR_DSCFG_ERROR_DELETE_CE.get(
- relation.getUserFriendlyName(), e.getMessage());
- throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN,
- msg);
+ if (result.isQuit()) {
+ if (!app.isMenuDrivenMode()) {
+ // User chose to cancel deletion.
+ Message msg = INFO_DSCFG_CONFIRM_DELETE_FAIL.get(relation
+ .getUserFriendlyName());
+ app.printVerboseMessage(msg);
}
+ return MenuResult.quit();
+ } else if (result.isCancel()) {
+ // Must be menu driven, so no need for error message.
+ return MenuResult.cancel();
+ }
+
+ ManagedObject<?> parent = result.getValue();
+ try {
+ if (relation instanceof InstantiableRelationDefinition) {
+ InstantiableRelationDefinition<?, ?> irelation =
+ (InstantiableRelationDefinition<?, ?>) relation;
+ String childName = names.get(names.size() - 1);
+
+ if (childName == null) {
+ MenuResult<String> sresult =
+ readChildName(app, parent, irelation, null);
+
+ if (sresult.isQuit()) {
+ if (!app.isMenuDrivenMode()) {
+ // User chose to cancel deletion.
+ Message msg = INFO_DSCFG_CONFIRM_DELETE_FAIL.get(relation
+ .getUserFriendlyName());
+ app.printVerboseMessage(msg);
+ }
+ return MenuResult.quit();
+ } else if (sresult.isCancel()) {
+ // Must be menu driven, so no need for error message.
+ return MenuResult.cancel();
+ } else {
+ childName = sresult.getValue();
+ }
+ }
+
+ if (confirmDeletion(app)) {
+ parent.removeChild(irelation, childName);
+ } else {
+ return MenuResult.cancel();
+ }
+ } else if (relation instanceof OptionalRelationDefinition) {
+ OptionalRelationDefinition<?, ?> orelation =
+ (OptionalRelationDefinition<?, ?>) relation;
+
+ if (confirmDeletion(app)) {
+ parent.removeChild(orelation);
+ } else {
+ return MenuResult.cancel();
+ }
+ }
+ } catch (AuthorizationException e) {
+ Message msg = ERR_DSCFG_ERROR_DELETE_AUTHZ.get(relation
+ .getUserFriendlyName());
+ throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS, msg);
+ } catch (OperationRejectedException e) {
+ Message msg = ERR_DSCFG_ERROR_DELETE_ORE.get(relation
+ .getUserFriendlyName(), e.getMessage());
+ throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
+ } catch (ManagedObjectNotFoundException e) {
+ // Ignore the error if the deletion is being forced.
+ if (!forceArgument.isPresent()) {
+ Message msg = ERR_DSCFG_ERROR_DELETE_MONFE.get(relation
+ .getUserFriendlyName());
+ throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msg);
+ }
+ } catch (ConcurrentModificationException e) {
+ Message msg = ERR_DSCFG_ERROR_DELETE_CME.get(relation
+ .getUserFriendlyName());
+ throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
+ } catch (CommunicationException e) {
+ Message msg = ERR_DSCFG_ERROR_DELETE_CE.get(relation
+ .getUserFriendlyName(), e.getMessage());
+ throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msg);
}
// Output success message.
- Message msg =
- INFO_DSCFG_CONFIRM_DELETE_SUCCESS.get(relation.getUserFriendlyName());
- getConsoleApplication().printVerboseMessage(msg);
+ Message msg = INFO_DSCFG_CONFIRM_DELETE_SUCCESS.get(relation
+ .getUserFriendlyName());
+ app.printVerboseMessage(msg);
- return 0;
+ return MenuResult.success(0);
}
// Confirm deletion.
- private boolean confirmDeletion() throws ArgumentException {
- Message prompt =
- INFO_DSCFG_CONFIRM_DELETE.get(relation.getUserFriendlyName());
- if (!getConsoleApplication().confirmAction(prompt)) {
+ private boolean confirmDeletion(ConsoleApplication app) throws CLIException {
+ Message prompt = INFO_DSCFG_CONFIRM_DELETE.get(relation
+ .getUserFriendlyName());
+ app.println();
+ if (!app.confirmAction(prompt, false)) {
// Output failure message.
- Message msg =
- INFO_DSCFG_CONFIRM_DELETE_FAIL.get(relation.getUserFriendlyName());
- getConsoleApplication().printVerboseMessage(msg);
+ Message msg = INFO_DSCFG_CONFIRM_DELETE_FAIL.get(relation
+ .getUserFriendlyName());
+ app.printVerboseMessage(msg);
return false;
} else {
return true;
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java
index ad325ce..ac1049b 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/GetPropSubCommandHandler.java
@@ -25,11 +25,10 @@
* Portions Copyright 2007 Sun Microsystems, Inc.
*/
package org.opends.server.tools.dsconfig;
-import org.opends.messages.Message;
-import static org.opends.messages.ToolMessages.*;
+import static org.opends.messages.DSConfigMessages.*;
import java.io.PrintStream;
import java.util.Collection;
@@ -38,6 +37,7 @@
import java.util.Set;
import java.util.SortedSet;
+import org.opends.messages.Message;
import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
import org.opends.server.admin.AliasDefaultBehaviorProvider;
import org.opends.server.admin.DefaultBehaviorProviderVisitor;
@@ -59,12 +59,16 @@
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.cli.CLIException;
+import org.opends.server.util.cli.ConsoleApplication;
+import org.opends.server.util.cli.MenuResult;
import org.opends.server.util.table.TableBuilder;
import org.opends.server.util.table.TablePrinter;
import org.opends.server.util.table.TextTablePrinter;
@@ -83,8 +87,6 @@
* Creates a new get-xxx-prop sub-command for an instantiable
* relation.
*
- * @param app
- * The console application.
* @param parser
* The sub-command argument parser.
* @param path
@@ -95,10 +97,10 @@
* @throws ArgumentException
* If the sub-command could not be created successfully.
*/
- public static GetPropSubCommandHandler create(ConsoleApplication app,
+ public static GetPropSubCommandHandler create(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
InstantiableRelationDefinition<?, ?> r) throws ArgumentException {
- return new GetPropSubCommandHandler(app, parser, path.child(r, "DUMMY"), r);
+ return new GetPropSubCommandHandler(parser, path.child(r, "DUMMY"), r);
}
@@ -106,8 +108,6 @@
/**
* Creates a new get-xxx-prop sub-command for an optional relation.
*
- * @param app
- * The console application.
* @param parser
* The sub-command argument parser.
* @param path
@@ -118,10 +118,10 @@
* @throws ArgumentException
* If the sub-command could not be created successfully.
*/
- public static GetPropSubCommandHandler create(ConsoleApplication app,
+ public static GetPropSubCommandHandler create(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
OptionalRelationDefinition<?, ?> r) throws ArgumentException {
- return new GetPropSubCommandHandler(app, parser, path.child(r), r);
+ return new GetPropSubCommandHandler(parser, path.child(r), r);
}
@@ -129,8 +129,6 @@
/**
* Creates a new get-xxx-prop sub-command for a singleton relation.
*
- * @param app
- * The console application.
* @param parser
* The sub-command argument parser.
* @param path
@@ -141,10 +139,10 @@
* @throws ArgumentException
* If the sub-command could not be created successfully.
*/
- public static GetPropSubCommandHandler create(ConsoleApplication app,
+ public static GetPropSubCommandHandler create(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
SingletonRelationDefinition<?, ?> r) throws ArgumentException {
- return new GetPropSubCommandHandler(app, parser, path.child(r), r);
+ return new GetPropSubCommandHandler(parser, path.child(r), r);
}
// The sub-commands naming arguments.
@@ -159,17 +157,15 @@
// Private constructor.
- private GetPropSubCommandHandler(ConsoleApplication app,
+ private GetPropSubCommandHandler(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
RelationDefinition<?, ?> r) throws ArgumentException {
- super(app);
-
this.path = path;
// Create the sub-command.
String name = "get-" + r.getName() + "-prop";
- Message message = INFO_DSCFG_DESCRIPTION_SUBCMD_GETPROP.get(
- r.getChildDefinition().getUserFriendlyName());
+ Message message = INFO_DSCFG_DESCRIPTION_SUBCMD_GETPROP.get(r
+ .getChildDefinition().getUserFriendlyName());
this.subCommand = new SubCommand(parser, name, false, 0, 0, null, message);
// Create the naming arguments.
@@ -190,6 +186,19 @@
/**
+ * Gets the relation definition associated with the type of
+ * component that this sub-command handles.
+ *
+ * @return Returns the relation definition associated with the type
+ * of component that this sub-command handles.
+ */
+ public RelationDefinition<?, ?> getRelationDefinition() {
+ return path.getRelationDefinition();
+ }
+
+
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -203,47 +212,51 @@
* {@inheritDoc}
*/
@Override
- public int run() throws ArgumentException, ClientException {
+ public MenuResult<Integer> run(ConsoleApplication app,
+ ManagementContextFactory factory) throws ArgumentException,
+ ClientException, CLIException {
// Get the property names.
Set<String> propertyNames = getPropertyNames();
PropertyValuePrinter valuePrinter = new PropertyValuePrinter(getSizeUnit(),
- getTimeUnit(), getConsoleApplication().isScriptFriendly());
+ getTimeUnit(), app.isScriptFriendly());
// Get the naming argument values.
- List<String> names = getNamingArgValues(namingArgs);
+ List<String> names = getNamingArgValues(app, namingArgs);
// Get the targeted managed object.
- ManagedObject<?> child;
+ Message ufn = path.getRelationDefinition().getUserFriendlyName();
+ ManagementContext context = factory.getManagementContext(app);
+ MenuResult<ManagedObject<?>> result;
try {
- child = getManagedObject(path, names);
+ result = getManagedObject(app, context, path, names);
} catch (AuthorizationException e) {
- Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_CHILD_AUTHZ.get(ufn);
- throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
- msg);
+ throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS, msg);
} catch (DefinitionDecodingException e) {
- Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_CHILD_DDE.get(ufn, ufn, ufn);
throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
} catch (ManagedObjectDecodingException e) {
- Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_CHILD_MODE.get(ufn);
throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
} catch (CommunicationException e) {
- Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_CHILD_CE.get(ufn, e.getMessage());
throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN, msg);
} catch (ConcurrentModificationException e) {
- Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_CHILD_CME.get(ufn);
throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
} catch (ManagedObjectNotFoundException e) {
- Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
- Message msg = ERR_DSCFG_ERROR_GET_CHILD_MONFE.get(ufn);
+ Message msg = ERR_DSCFG_ERROR_GET_CHILD_MONFE.get(ufn);
throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msg);
}
+ if (result.isQuit()) {
+ return MenuResult.quit();
+ } else if (result.isCancel()) {
+ return MenuResult.cancel();
+ }
+
// Validate the property names.
+ ManagedObject<?> child = result.getValue();
ManagedObjectDefinition<?, ?> d = child.getManagedObjectDefinition();
Collection<PropertyDefinition<?>> pdList;
if (propertyNames.isEmpty()) {
@@ -274,12 +287,12 @@
}
if (propertyNames.isEmpty() || propertyNames.contains(pd.getName())) {
- displayProperty(builder, child, pd, valuePrinter);
+ displayProperty(app, builder, child, pd, valuePrinter);
}
}
- PrintStream out = getConsoleApplication().getOutputStream();
- if (getConsoleApplication().isScriptFriendly()) {
+ PrintStream out = app.getOutputStream();
+ if (app.isScriptFriendly()) {
TablePrinter printer = createScriptFriendlyTablePrinter(out);
builder.print(printer);
} else {
@@ -289,14 +302,15 @@
builder.print(printer);
}
- return 0;
+ return MenuResult.success(0);
}
// Display the set of values associated with a property.
- private <T> void displayProperty(TableBuilder builder, ManagedObject<?> mo,
- PropertyDefinition<T> pd, PropertyValuePrinter valuePrinter) {
+ private <T> void displayProperty(final ConsoleApplication 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
@@ -314,7 +328,7 @@
public Message visitAlias(AliasDefaultBehaviorProvider<T> d, Void p) {
- if (getConsoleApplication().isVerbose()) {
+ if (app.isVerbose()) {
return d.getSynopsis();
} else {
return null;
@@ -352,7 +366,7 @@
Message content = pd.getDefaultBehaviorProvider().accept(visitor, null);
if (content == null) {
- if (getConsoleApplication().isScriptFriendly()) {
+ if (app.isScriptFriendly()) {
builder.appendCell();
} else {
builder.appendCell("-");
@@ -371,7 +385,7 @@
builder.startRow();
builder.appendCell(pd.getName());
- if (getConsoleApplication().isScriptFriendly()) {
+ if (app.isScriptFriendly()) {
for (T value : values) {
builder.appendCell(valuePrinter.print(pd, value));
}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java
index 5ea9b41..1fe6c6e 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java
@@ -26,16 +26,14 @@
*/
package org.opends.server.tools.dsconfig;
-import org.opends.messages.MessageBuilder;
-import org.opends.messages.Message;
-import static org.opends.messages.ToolMessages.*;
+import static org.opends.messages.DSConfigMessages.*;
+import static org.opends.messages.UtilityMessages.*;
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.EnumSet;
import java.util.HashMap;
import java.util.LinkedList;
@@ -45,6 +43,8 @@
import java.util.TreeMap;
import java.util.TreeSet;
+import org.opends.messages.Message;
+import org.opends.messages.MessageBuilder;
import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
import org.opends.server.admin.AbstractManagedObjectDefinition;
import org.opends.server.admin.AdministratorAction;
@@ -67,6 +67,10 @@
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.cli.CLIException;
+import org.opends.server.util.cli.ConsoleApplication;
+import org.opends.server.util.cli.MenuResult;
+import org.opends.server.util.cli.OutputStreamConsoleApplication;
import org.opends.server.util.table.TableBuilder;
import org.opends.server.util.table.TablePrinter;
import org.opends.server.util.table.TextTablePrinter;
@@ -101,9 +105,9 @@
public Message visitAbsoluteInherited(
AbsoluteInheritedDefaultBehaviorProvider<T> d,
PropertyDefinition<T> p) {
- return INFO_DSCFG_HELP_FIELD_INHERITED_ABS.get(d
- .getPropertyName(), d.getManagedObjectPath()
- .getRelationDefinition().getUserFriendlyName());
+ return INFO_DSCFG_HELP_FIELD_INHERITED_ABS.get(d.getPropertyName(), d
+ .getManagedObjectPath().getRelationDefinition()
+ .getUserFriendlyName());
}
@@ -148,13 +152,12 @@
RelativeInheritedDefaultBehaviorProvider<T> d,
PropertyDefinition<T> p) {
if (d.getRelativeOffset() == 0) {
- return INFO_DSCFG_HELP_FIELD_INHERITED_THIS.get(d
- .getPropertyName(), d.getManagedObjectDefinition()
- .getUserFriendlyName());
+ return INFO_DSCFG_HELP_FIELD_INHERITED_THIS.get(d.getPropertyName(),
+ d.getManagedObjectDefinition().getUserFriendlyName());
} else {
- return INFO_DSCFG_HELP_FIELD_INHERITED_PARENT.get(d
- .getPropertyName(), d.getManagedObjectDefinition()
- .getUserFriendlyName());
+ return INFO_DSCFG_HELP_FIELD_INHERITED_PARENT.get(
+ d.getPropertyName(), d.getManagedObjectDefinition()
+ .getUserFriendlyName());
}
}
@@ -298,7 +301,7 @@
* {@inheritDoc}
*/
@Override
- public Void visitUnknown(PropertyDefinition<?> d, PrintStream p)
+ public <T> Void visitUnknown(PropertyDefinition<T> d, PrintStream p)
throws UnknownPropertyDefinitionException {
PropertyDefinitionUsageBuilder usageBuilder =
new PropertyDefinitionUsageBuilder(true);
@@ -367,44 +370,41 @@
private final static int HEADING_WIDTH;
/**
+ * The value for the long option category.
+ */
+ private static final String OPTION_DSCFG_LONG_CATEGORY = "category";
+
+ /**
* The value for the long option inherited.
*/
private static final String OPTION_DSCFG_LONG_INHERITED = "inherited";
/**
- * The value for the short option inherited.
- */
- private static final Character OPTION_DSCFG_SHORT_INHERITED = null;
-
- /**
* 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';
-
- /**
- * The value for the long option category.
- */
- private static final String OPTION_DSCFG_LONG_CATEGORY = "category";
-
- /**
* The value for the short option category.
*/
private static final Character OPTION_DSCFG_SHORT_CATEGORY = 'c';
+ /**
+ * The value for the short option inherited.
+ */
+ private static final Character OPTION_DSCFG_SHORT_INHERITED = null;
+
+ /**
+ * The value for the short option type.
+ */
+ private static final Character OPTION_DSCFG_SHORT_TYPE = 't';
+
static {
int tmp = INFO_DSCFG_HELP_HEADING_SYNTAX.get().length();
tmp = Math.max(tmp, INFO_DSCFG_HELP_HEADING_DEFAULT.get().length());
- tmp = Math.max(tmp, INFO_DSCFG_HELP_HEADING_MULTI_VALUED.get()
- .length());
- tmp = Math
- .max(tmp, INFO_DSCFG_HELP_HEADING_MANDATORY.get().length());
- tmp = Math
- .max(tmp, INFO_DSCFG_HELP_HEADING_READ_ONLY.get().length());
+ tmp = Math.max(tmp, INFO_DSCFG_HELP_HEADING_MULTI_VALUED.get().length());
+ tmp = Math.max(tmp, INFO_DSCFG_HELP_HEADING_MANDATORY.get().length());
+ tmp = Math.max(tmp, INFO_DSCFG_HELP_HEADING_READ_ONLY.get().length());
HEADING_WIDTH = tmp;
}
@@ -413,17 +413,79 @@
/**
* Creates a new help-properties sub-command.
*
- * @param app
- * The console application.
* @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(ConsoleApplication app,
- SubCommandArgumentParser parser) throws ArgumentException {
- return new HelpSubCommandHandler(app, parser);
+ public static HelpSubCommandHandler create(SubCommandArgumentParser parser)
+ throws ArgumentException {
+ return new HelpSubCommandHandler(parser);
+ }
+
+
+
+ /**
+ * Displays detailed help about a single component to the specified
+ * output stream.
+ *
+ * @param app
+ * The application console.
+ * @param d
+ * The managed object definition.
+ * @param c
+ * The collection of properties to be displayed.
+ */
+ public static void displaySingleComponent(ConsoleApplication app,
+ AbstractManagedObjectDefinition<?, ?> d,
+ Collection<PropertyDefinition<?>> c) {
+ // Display the title.
+ app.println(INFO_DSCFG_HELP_HEADING_COMPONENT.get(d.getUserFriendlyName()));
+
+ app.println();
+ app.println(d.getSynopsis());
+ if (d.getDescription() != null) {
+ app.println();
+ app.println(d.getDescription());
+ }
+
+ app.println();
+ app.println();
+ displayPropertyOptionKey(app);
+
+ app.println();
+ app.println();
+
+ // Headings.
+ TableBuilder builder = new TableBuilder();
+
+ builder.appendHeading(INFO_DSCFG_HEADING_PROPERTY_NAME.get());
+ builder.appendHeading(INFO_DSCFG_HEADING_PROPERTY_OPTIONS.get());
+ builder.appendHeading(INFO_DSCFG_HEADING_PROPERTY_SYNTAX.get());
+
+ // Sort keys.
+ builder.addSortKey(0);
+
+ // Output summary of each property.
+ for (PropertyDefinition<?> pd : c) {
+ // Display the property.
+ builder.startRow();
+
+ // 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 = new TextTablePrinter(app.getErrorStream());
+ builder.print(printer);
}
@@ -432,35 +494,35 @@
* Displays detailed help about a single property to the specified
* output stream.
*
+ * @param app
+ * The application console.
* @param d
* The managed object definition.
* @param name
* The name of the property definition.
- * @param out
- * The output stream.
*/
- public static void displayVerboseSingleProperty(
- AbstractManagedObjectDefinition<?, ?> d, String name, PrintStream out) {
+ public static void displayVerboseSingleProperty(ConsoleApplication app,
+ AbstractManagedObjectDefinition<?, ?> d, String name) {
PropertyDefinition<?> pd = d.getPropertyDefinition(name);
// Display the title.
- out.println(INFO_DSCFG_HELP_HEADING_PROPERTY.get(name));
+ app.println(INFO_DSCFG_HELP_HEADING_PROPERTY.get(name));
// Display the property synopsis and description.
- out.println();
- out.println(wrapText(pd.getSynopsis(), MAX_LINE_WIDTH));
+ app.println();
+ app.println(pd.getSynopsis(), 4);
if (pd.getDescription() != null) {
- out.println();
- out.println(wrapText(pd.getDescription(), MAX_LINE_WIDTH));
+ app.println();
+ app.println(pd.getDescription(), 4);
}
// Display the syntax.
- out.println();
+ app.println();
SyntaxPrinter syntaxPrinter = new SyntaxPrinter();
- syntaxPrinter.print(out, pd);
+ syntaxPrinter.print(app.getErrorStream(), pd);
// Display remaining information in a table.
- out.println();
+ app.println();
TableBuilder builder = new TableBuilder();
// Display the default behavior.
@@ -476,27 +538,27 @@
builder.appendCell(INFO_DSCFG_HELP_HEADING_ADVANCED.get());
builder.appendCell(HEADING_SEPARATOR);
if (pd.hasOption(PropertyOption.ADVANCED)) {
- builder.appendCell(INFO_DSCFG_GENERAL_CONFIRM_YES.get());
+ builder.appendCell(INFO_GENERAL_YES.get());
} else {
- builder.appendCell(INFO_DSCFG_GENERAL_CONFIRM_NO.get());
+ builder.appendCell(INFO_GENERAL_NO.get());
}
builder.startRow();
builder.appendCell(INFO_DSCFG_HELP_HEADING_MULTI_VALUED.get());
builder.appendCell(HEADING_SEPARATOR);
if (pd.hasOption(PropertyOption.MULTI_VALUED)) {
- builder.appendCell(INFO_DSCFG_GENERAL_CONFIRM_YES.get());
+ builder.appendCell(INFO_GENERAL_YES.get());
} else {
- builder.appendCell(INFO_DSCFG_GENERAL_CONFIRM_NO.get());
+ builder.appendCell(INFO_GENERAL_NO.get());
}
builder.startRow();
builder.appendCell(INFO_DSCFG_HELP_HEADING_MANDATORY.get());
builder.appendCell(HEADING_SEPARATOR);
if (pd.hasOption(PropertyOption.MANDATORY)) {
- builder.appendCell(INFO_DSCFG_GENERAL_CONFIRM_YES.get());
+ builder.appendCell(INFO_GENERAL_YES.get());
} else {
- builder.appendCell(INFO_DSCFG_GENERAL_CONFIRM_NO.get());
+ builder.appendCell(INFO_GENERAL_NO.get());
}
builder.startRow();
@@ -508,10 +570,10 @@
builder.appendCell(INFO_DSCFG_HELP_FIELD_READ_ONLY.get(d
.getUserFriendlyName()));
} else {
- builder.appendCell(INFO_DSCFG_GENERAL_CONFIRM_NO.get());
+ builder.appendCell(INFO_GENERAL_NO.get());
}
- TextTablePrinter factory = new TextTablePrinter(out);
+ TextTablePrinter factory = new TextTablePrinter(app.getErrorStream());
factory.setDisplayHeadings(false);
factory.setColumnWidth(0, HEADING_WIDTH);
factory.setColumnWidth(2, 0);
@@ -524,8 +586,8 @@
if (synopsis == null) {
switch (action.getType()) {
case COMPONENT_RESTART:
- synopsis = INFO_DSCFG_HELP_FIELD_COMPONENT_RESTART.get(
- d.getUserFriendlyName());
+ synopsis = INFO_DSCFG_HELP_FIELD_COMPONENT_RESTART.get(d
+ .getUserFriendlyName());
break;
case SERVER_RESTART:
synopsis = INFO_DSCFG_HELP_FIELD_SERVER_RESTART.get();
@@ -537,42 +599,110 @@
}
if (synopsis != null) {
- out.println();
- out.println(wrapText(synopsis, MAX_LINE_WIDTH));
+ app.println();
+ app.println(synopsis);
}
}
- // The sub-command associated with this handler.
- private final SubCommand subCommand;
+
+
+ // Displays the property option summary key.
+ private static void displayPropertyOptionKey(ConsoleApplication app) {
+ MessageBuilder builder;
+
+ app.println(INFO_DSCFG_HELP_DESCRIPTION_OPTION.get());
+ app.println();
+
+ builder = new MessageBuilder();
+ builder.append(" r -- ");
+ builder.append(INFO_DSCFG_HELP_DESCRIPTION_READ.get());
+ app.println(builder.toMessage());
+
+ builder = new MessageBuilder();
+ builder.append(" w -- ");
+ builder.append(INFO_DSCFG_HELP_DESCRIPTION_WRITE.get());
+ app.println(builder.toMessage());
+
+ builder = new MessageBuilder();
+ builder.append(" m -- ");
+ builder.append(INFO_DSCFG_HELP_DESCRIPTION_MANDATORY.get());
+ app.println(builder.toMessage());
+
+ builder = new MessageBuilder();
+ builder.append(" s -- ");
+ builder.append(INFO_DSCFG_HELP_DESCRIPTION_SINGLE_VALUED.get());
+ app.println(builder.toMessage());
+
+ builder = new MessageBuilder();
+ builder.append(" a -- ");
+ builder.append(INFO_DSCFG_HELP_DESCRIPTION_ADMIN_ACTION.get());
+ app.println(builder.toMessage());
+ }
+
+
+
+ // Compute the options field.
+ private static String getPropertyOptionSummary(PropertyDefinition<?> pd) {
+ StringBuilder b = new StringBuilder();
+
+ if (pd.hasOption(PropertyOption.MONITORING)
+ || pd.hasOption(PropertyOption.READ_ONLY)) {
+ b.append("r-");
+ } else {
+ b.append("rw");
+ }
+
+ 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();
+ }
// The argument which should be used to specify the category of
// managed object to be retrieved.
private final StringArgument categoryArgument;
- //The argument which should be used to display inherited properties.
+ // A table listing all the available types of managed object indexed
+ // on their parent type.
+ private final Map<String, Map<String,
+ AbstractManagedObjectDefinition<?, ?>>> categoryMap;
+
+ // The argument which should be used to display inherited
+ // properties.
private BooleanArgument inheritedModeArgument;
+ // The sub-command associated with this handler.
+ private final SubCommand subCommand;
+
+ // A table listing all the available types of managed object indexed
+ // on their tag(s).
+ private final Map<Tag, Map<String,
+ AbstractManagedObjectDefinition<?, ?>>> tagMap;
+
// The argument which should be used to specify the sub-type of
// managed object to be retrieved.
private final StringArgument typeArgument;
- // A table listing all the available types of managed object indexed
- // on their parent type.
- private final Map<String,
- Map<String, AbstractManagedObjectDefinition<?, ?>>> categoryMap;
-
- // A table listing all the available types of managed object indexed
- // on their tag(s).
- private final Map<Tag,
- Map<String, AbstractManagedObjectDefinition<?, ?>>> tagMap;
-
// Private constructor.
- private HelpSubCommandHandler(ConsoleApplication app,
- SubCommandArgumentParser parser) throws ArgumentException {
- super(app);
-
+ private HelpSubCommandHandler(SubCommandArgumentParser parser)
+ throws ArgumentException {
// Create the sub-command.
String name = "list-properties";
Message desc = INFO_DSCFG_DESCRIPTION_SUBCMD_HELPPROP.get();
@@ -580,8 +710,8 @@
this.categoryArgument = new StringArgument(OPTION_DSCFG_LONG_CATEGORY,
OPTION_DSCFG_SHORT_CATEGORY, OPTION_DSCFG_LONG_CATEGORY, false, false,
- true, "{CATEGORY}", null, null,
- INFO_DSCFG_DESCRIPTION_HELP_CATEGORY.get());
+ true, "{CATEGORY}", null, null, INFO_DSCFG_DESCRIPTION_HELP_CATEGORY
+ .get());
this.subCommand.addArgument(this.categoryArgument);
this.typeArgument = new StringArgument(OPTION_DSCFG_LONG_TYPE,
@@ -591,8 +721,8 @@
this.inheritedModeArgument = new BooleanArgument(
OPTION_DSCFG_LONG_INHERITED, OPTION_DSCFG_SHORT_INHERITED,
- OPTION_DSCFG_LONG_INHERITED,
- INFO_DSCFG_DESCRIPTION_HELP_INHERITED.get());
+ OPTION_DSCFG_LONG_INHERITED, INFO_DSCFG_DESCRIPTION_HELP_INHERITED
+ .get());
subCommand.addArgument(inheritedModeArgument);
// Register common arguments.
@@ -600,10 +730,10 @@
INFO_DSCFG_DESCRIPTION_ADVANCED_HELP.get());
registerPropertyNameArgument(this.subCommand);
- this.categoryMap = new TreeMap<String,
- Map<String, AbstractManagedObjectDefinition<?, ?>>>();
- this.tagMap = new HashMap<Tag,
- Map<String, AbstractManagedObjectDefinition<?, ?>>>();
+ this.categoryMap =
+ new TreeMap<String, Map<String, AbstractManagedObjectDefinition<?, ?>>>();
+ this.tagMap =
+ new HashMap<Tag, Map<String, AbstractManagedObjectDefinition<?, ?>>>();
}
@@ -676,7 +806,9 @@
* {@inheritDoc}
*/
@Override
- public int run() throws ArgumentException, ClientException {
+ public MenuResult<Integer> run(ConsoleApplication app,
+ ManagementContextFactory factory) throws ArgumentException,
+ ClientException, CLIException {
String categoryName = categoryArgument.getValue();
String typeName = typeArgument.getValue();
Tag tag = null;
@@ -774,36 +906,26 @@
}
}
- if (!getConsoleApplication().isVerbose()) {
- displayNonVerbose(categoryName, typeName, tag, propertyNames);
+ // Output everything to the output stream.
+ app = new OutputStreamConsoleApplication(app);
+ if (!app.isVerbose()) {
+ displayNonVerbose(app, categoryName, typeName, tag, propertyNames);
} else {
- displayVerbose(categoryName, typeName, tag, propertyNames);
+ displayVerbose(app, categoryName, typeName, tag, propertyNames);
}
- return 0;
+ return MenuResult.success(0);
}
// Output property summary table.
- private void displayNonVerbose(String categoryName, String typeName,
- Tag tag, Set<String> propertyNames) {
- PrintStream out = getConsoleApplication().getOutputStream();
- if (!getConsoleApplication().isScriptFriendly()) {
- out.println(INFO_DSCFG_HELP_DESCRIPTION_OPTION.get());
- out.println();
- out.print(" r -- ");
- out.println(INFO_DSCFG_HELP_DESCRIPTION_READ.get());
- out.print(" w -- ");
- out.println(INFO_DSCFG_HELP_DESCRIPTION_WRITE.get());
- out.print(" m -- ");
- out.println(INFO_DSCFG_HELP_DESCRIPTION_MANDATORY.get());
- out.print(" s -- ");
- out.println(INFO_DSCFG_HELP_DESCRIPTION_SINGLE_VALUED.get());
- out.print(" a -- ");
- out.println(INFO_DSCFG_HELP_DESCRIPTION_ADMIN_ACTION.get());
- out.println();
- out.println();
+ private void displayNonVerbose(ConsoleApplication app, String categoryName,
+ String typeName, Tag tag, Set<String> propertyNames) {
+ if (!app.isScriptFriendly()) {
+ displayPropertyOptionKey(app);
+ app.println();
+ app.println();
}
// Headings.
@@ -894,10 +1016,10 @@
}
TablePrinter printer;
- if (getConsoleApplication().isScriptFriendly()) {
- printer = createScriptFriendlyTablePrinter(out);
+ if (app.isScriptFriendly()) {
+ printer = createScriptFriendlyTablePrinter(app.getOutputStream());
} else {
- printer = new TextTablePrinter(out);
+ printer = new TextTablePrinter(app.getOutputStream());
}
builder.print(printer);
}
@@ -905,15 +1027,22 @@
// Display detailed help on managed objects and their properties.
- private void displayVerbose(String categoryName, String typeName,
- Tag tag, Set<String> propertyNames) {
- PrintStream out = getConsoleApplication().getOutputStream();
-
+ private void displayVerbose(ConsoleApplication app, String categoryName,
+ String typeName, Tag tag, 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, '-');
+ MessageBuilder mb;
+
+ mb = new MessageBuilder();
+ for (int i = 0; i < MAX_LINE_WIDTH; i++) {
+ mb.append('=');
+ }
+ Message c1 = mb.toMessage();
+
+ mb = new MessageBuilder();
+ for (int i = 0; i < MAX_LINE_WIDTH; i++) {
+ mb.append('-');
+ }
+ Message c2 = mb.toMessage();
// Display help for each managed object.
boolean isFirstManagedObject = true;
@@ -973,67 +1102,33 @@
// managed
// object.
if (!isFirstManagedObject) {
- out.println();
- out.println(c1);
- out.println();
+ app.println();
+ app.println(c1);
+ app.println();
} else {
isFirstManagedObject = false;
}
// Display the title.
- out.println(wrapText(INFO_DSCFG_HELP_HEADING_COMPONENT.get(
- mod.getUserFriendlyName()), MAX_LINE_WIDTH));
+ app.println(INFO_DSCFG_HELP_HEADING_COMPONENT.get(mod
+ .getUserFriendlyName()));
- out.println();
- out.println(wrapText(mod.getSynopsis(), MAX_LINE_WIDTH));
+ app.println();
+ app.println(mod.getSynopsis());
if (mod.getDescription() != null) {
- out.println();
- out.println(wrapText(mod.getDescription(), MAX_LINE_WIDTH));
+ app.println();
+ app.println(mod.getDescription());
}
}
- out.println();
- out.println(c2);
- out.println();
+ app.println();
+ app.println(c2);
+ app.println();
- displayVerboseSingleProperty(mod, pd.getName(), out);
+ displayVerboseSingleProperty(app, mod, pd.getName());
isFirstProperty = false;
}
}
}
}
-
-
-
- // 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-");
- } else {
- b.append("rw");
- }
-
- 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
index 27874ed..64b9a82 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/InternalManagementContextFactory.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/InternalManagementContextFactory.java
@@ -32,6 +32,7 @@
import org.opends.server.tools.ClientException;
import org.opends.server.util.args.ArgumentException;
import org.opends.server.util.args.SubCommandArgumentParser;
+import org.opends.server.util.cli.ConsoleApplication;
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/LDAPManagementContextFactory.java b/opends/src/server/org/opends/server/tools/dsconfig/LDAPManagementContextFactory.java
index ae00d60..d8ce86f 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/LDAPManagementContextFactory.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/LDAPManagementContextFactory.java
@@ -25,13 +25,17 @@
* Portions Copyright 2007 Sun Microsystems, Inc.
*/
package org.opends.server.tools.dsconfig;
-import org.opends.messages.Message;
+import static org.opends.messages.DSConfigMessages.*;
import static org.opends.messages.ToolMessages.*;
import static org.opends.server.tools.ToolConstants.*;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.opends.messages.Message;
import org.opends.server.admin.client.AuthenticationException;
import org.opends.server.admin.client.AuthenticationNotSupportedException;
import org.opends.server.admin.client.CommunicationException;
@@ -46,6 +50,9 @@
import org.opends.server.util.args.IntegerArgument;
import org.opends.server.util.args.StringArgument;
import org.opends.server.util.args.SubCommandArgumentParser;
+import org.opends.server.util.cli.CLIException;
+import org.opends.server.util.cli.ConsoleApplication;
+import org.opends.server.util.cli.ValidationCallback;
@@ -98,14 +105,132 @@
throws ArgumentException, ClientException {
// Lazily create the LDAP management context.
if (context == null) {
+ boolean isHeadingDisplayed = false;
+
// Get the LDAP host.
String hostName = hostArgument.getValue();
+ final String tmpHostName = hostName;
+ if (app.isInteractive() && !hostArgument.isPresent()) {
+ if (!isHeadingDisplayed) {
+ app.println();
+ app.println();
+ app.println(INFO_DSCFG_HEADING_CONNECTION_PARAMETERS.get());
+ isHeadingDisplayed = true;
+ }
+
+ ValidationCallback<String> callback = new ValidationCallback<String>() {
+
+ public String validate(ConsoleApplication app, String input)
+ throws CLIException {
+ String ninput = input.trim();
+ if (ninput.length() == 0) {
+ return tmpHostName;
+ } else {
+ try {
+ InetAddress.getByName(ninput);
+ return ninput;
+ } catch (UnknownHostException e) {
+ // Try again...
+ app.println();
+ app.println(ERR_DSCFG_BAD_HOST_NAME.get(ninput));
+ app.println();
+ return null;
+ }
+ }
+ }
+
+ };
+
+ try {
+ app.println();
+ hostName = app.readValidatedInput(INFO_DSCFG_PROMPT_HOST_NAME
+ .get(hostName), callback);
+ } catch (CLIException e) {
+ throw ArgumentExceptionFactory.unableToReadConnectionParameters(e);
+ }
+ }
// Get the LDAP port.
int portNumber = portArgument.getIntValue();
+ final int tmpPortNumber = portNumber;
+ if (app.isInteractive() && !portArgument.isPresent()) {
+ if (!isHeadingDisplayed) {
+ app.println();
+ app.println();
+ app.println(INFO_DSCFG_HEADING_CONNECTION_PARAMETERS.get());
+ isHeadingDisplayed = true;
+ }
+
+ ValidationCallback<Integer> callback =
+ new ValidationCallback<Integer>() {
+
+ public Integer validate(ConsoleApplication app, String input)
+ throws CLIException {
+ String ninput = input.trim();
+ if (ninput.length() == 0) {
+ return tmpPortNumber;
+ } else {
+ try {
+ int i = Integer.parseInt(ninput);
+ if (i < 1 || i > 65535) {
+ throw new NumberFormatException();
+ }
+ return i;
+ } catch (NumberFormatException e) {
+ // Try again...
+ app.println();
+ app.println(ERR_DSCFG_BAD_PORT_NUMBER.get(ninput));
+ app.println();
+ return null;
+ }
+ }
+ }
+
+ };
+
+ try {
+ app.println();
+ portNumber = app.readValidatedInput(INFO_DSCFG_PROMPT_PORT_NUMBER
+ .get(portNumber), callback);
+ } catch (CLIException e) {
+ throw ArgumentExceptionFactory.unableToReadConnectionParameters(e);
+ }
+ }
// Get the LDAP bind credentials.
String bindDN = bindDNArgument.getValue();
+ final String tmpBindDN = bindDN;
+ if (app.isInteractive() && !bindDNArgument.isPresent()) {
+ if (!isHeadingDisplayed) {
+ app.println();
+ app.println();
+ app.println(INFO_DSCFG_HEADING_CONNECTION_PARAMETERS.get());
+ isHeadingDisplayed = true;
+ }
+
+ ValidationCallback<String> callback = new ValidationCallback<String>() {
+
+ public String validate(ConsoleApplication app, String input)
+ throws CLIException {
+ String ninput = input.trim();
+ if (ninput.length() == 0) {
+ return tmpBindDN;
+ } else {
+ return ninput;
+ }
+ }
+
+ };
+
+ try {
+ app.println();
+ bindDN = app.readValidatedInput(
+ INFO_DSCFG_PROMPT_BIND_DN.get(bindDN), callback);
+ } catch (CLIException e) {
+ throw ArgumentExceptionFactory.unableToReadConnectionParameters(e);
+ }
+ }
+
String bindPassword = bindPasswordArgument.getValue();
if (bindPasswordFileArgument.isPresent()) {
@@ -122,11 +247,19 @@
.unableToReadBindPasswordInteractively();
}
+ if (!isHeadingDisplayed) {
+ app.println();
+ app.println();
+ app.println(INFO_DSCFG_HEADING_CONNECTION_PARAMETERS.get());
+ isHeadingDisplayed = true;
+ }
+
try {
+ app.println();
Message prompt = INFO_LDAPAUTH_PASSWORD_PROMPT.get(bindDN);
bindPassword = app.readPassword(prompt);
} catch (Exception e) {
- throw ArgumentExceptionFactory.unableToReadBindPassword(e);
+ throw ArgumentExceptionFactory.unableToReadConnectionParameters(e);
}
}
@@ -143,9 +276,8 @@
Message message = ERR_DSCFG_ERROR_LDAP_SIMPLE_BIND_FAILED.get(bindDN);
throw new ClientException(LDAPResultCode.INVALID_CREDENTIALS, message);
} catch (CommunicationException e) {
- Message message =
- ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(
- hostName, String.valueOf(portNumber));
+ Message message = ERR_DSCFG_ERROR_LDAP_FAILED_TO_CONNECT.get(hostName,
+ String.valueOf(portNumber));
throw new ClientException(LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR,
message);
}
@@ -200,9 +332,8 @@
// arguments.
if (bindPasswordArgument.isPresent()
&& bindPasswordFileArgument.isPresent()) {
- Message message = ERR_TOOL_CONFLICTING_ARGS.
- get(bindPasswordArgument.getLongIdentifier(),
- bindPasswordFileArgument.getLongIdentifier());
+ Message message = ERR_TOOL_CONFLICTING_ARGS.get(bindPasswordArgument
+ .getLongIdentifier(), bindPasswordFileArgument.getLongIdentifier());
throw new ArgumentException(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
index 9181105..63df154 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java
@@ -25,11 +25,10 @@
* Portions Copyright 2007 Sun Microsystems, Inc.
*/
package org.opends.server.tools.dsconfig;
-import org.opends.messages.Message;
-import static org.opends.messages.ToolMessages.*;
+import static org.opends.messages.DSConfigMessages.*;
import java.io.PrintStream;
import java.util.List;
@@ -38,6 +37,7 @@
import java.util.SortedSet;
import java.util.TreeMap;
+import org.opends.messages.Message;
import org.opends.server.admin.DefinitionDecodingException;
import org.opends.server.admin.InstantiableRelationDefinition;
import org.opends.server.admin.ManagedObjectDefinition;
@@ -51,12 +51,16 @@
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.cli.CLIException;
+import org.opends.server.util.cli.ConsoleApplication;
+import org.opends.server.util.cli.MenuResult;
import org.opends.server.util.table.TableBuilder;
import org.opends.server.util.table.TablePrinter;
import org.opends.server.util.table.TextTablePrinter;
@@ -74,8 +78,6 @@
/**
* Creates a new list-xxx sub-command for an instantiable relation.
*
- * @param app
- * The console application.
* @param parser
* The sub-command argument parser.
* @param p
@@ -86,10 +88,10 @@
* @throws ArgumentException
* If the sub-command could not be created successfully.
*/
- public static ListSubCommandHandler create(ConsoleApplication app,
+ public static ListSubCommandHandler create(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
InstantiableRelationDefinition<?, ?> r) throws ArgumentException {
- return new ListSubCommandHandler(app, parser, p, r, r.getPluralName(), r
+ return new ListSubCommandHandler(parser, p, r, r.getPluralName(), r
.getUserFriendlyPluralName());
}
@@ -98,8 +100,6 @@
/**
* Creates a new list-xxx sub-command for an optional relation.
*
- * @param app
- * The console application.
* @param parser
* The sub-command argument parser.
* @param p
@@ -110,10 +110,10 @@
* @throws ArgumentException
* If the sub-command could not be created successfully.
*/
- public static ListSubCommandHandler create(ConsoleApplication app,
+ public static ListSubCommandHandler create(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
OptionalRelationDefinition<?, ?> r) throws ArgumentException {
- return new ListSubCommandHandler(app, parser, p, r, r.getName(), r
+ return new ListSubCommandHandler(parser, p, r, r.getName(), r
.getUserFriendlyName());
}
@@ -132,12 +132,10 @@
// Private constructor.
- private ListSubCommandHandler(ConsoleApplication app,
+ private ListSubCommandHandler(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
RelationDefinition<?, ?> r, String rname, Message rufn)
throws ArgumentException {
- super(app);
-
this.path = p;
this.relation = r;
@@ -161,6 +159,19 @@
/**
+ * Gets the relation definition associated with the type of
+ * component that this sub-command handles.
+ *
+ * @return Returns the relation definition associated with the type
+ * of component that this sub-command handles.
+ */
+ public RelationDefinition<?, ?> getRelationDefinition() {
+ return relation;
+ }
+
+
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -174,8 +185,9 @@
* {@inheritDoc}
*/
@Override
- public int run()
- throws ArgumentException, ClientException {
+ public MenuResult<Integer> run(ConsoleApplication app,
+ ManagementContextFactory factory) throws ArgumentException,
+ ClientException, CLIException {
// Get the property names.
Set<String> propertyNames = getPropertyNames();
@@ -186,10 +198,10 @@
}
PropertyValuePrinter valuePrinter = new PropertyValuePrinter(getSizeUnit(),
- getTimeUnit(), getConsoleApplication().isScriptFriendly());
+ getTimeUnit(), app.isScriptFriendly());
// Get the naming argument values.
- List<String> names = getNamingArgValues(namingArgs);
+ List<String> names = getNamingArgValues(app, namingArgs);
Message ufn;
if (relation instanceof InstantiableRelationDefinition) {
@@ -201,20 +213,19 @@
}
// List the children.
- ManagedObject<?> parent;
+ ManagementContext context = factory.getManagementContext(app);
+ MenuResult<ManagedObject<?>> result;
try {
- parent = getManagedObject(path, names);
+ result = getManagedObject(app, context, path, names);
} catch (AuthorizationException e) {
Message msg = ERR_DSCFG_ERROR_LIST_AUTHZ.get(ufn);
throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
msg);
} catch (DefinitionDecodingException e) {
-
ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_PARENT_DDE.get(ufn, ufn, ufn);
throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
} catch (ManagedObjectDecodingException e) {
-
ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_PARENT_MODE.get(ufn);
throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
@@ -225,12 +236,18 @@
Message msg = ERR_DSCFG_ERROR_LIST_CME.get(ufn);
throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
} catch (ManagedObjectNotFoundException e) {
-
ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_PARENT_MONFE.get(ufn);
throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msg);
}
+ if (result.isQuit()) {
+ return MenuResult.quit();
+ } else if (result.isCancel()) {
+ return MenuResult.cancel();
+ }
+
+ ManagedObject<?> parent = result.getValue();
SortedMap<String, ManagedObject<?>> children =
new TreeMap<String, ManagedObject<?>>();
if (relation instanceof InstantiableRelationDefinition) {
@@ -301,11 +318,10 @@
}
// Output the results.
- if (getConsoleApplication().isScriptFriendly()) {
+ if (app.isScriptFriendly()) {
// Output just the names of the children.
- PrintStream out = getConsoleApplication().getOutputStream();
for (String name : children.keySet()) {
- out.println(name);
+ app.println(Message.raw(name));
}
} else {
// Create a table of their properties.
@@ -313,8 +329,6 @@
builder.appendHeading(relation.getUserFriendlyName());
builder
.appendHeading(INFO_DSCFG_HEADING_COMPONENT_TYPE.get());
- if (!propertyNames.isEmpty()) {
- }
for (String propertyName : propertyNames) {
builder.appendHeading(Message.raw(propertyName));
}
@@ -346,11 +360,11 @@
for (String propertyName : propertyNames) {
try {
PropertyDefinition<?> pd = d.getPropertyDefinition(propertyName);
- displayProperty(builder, child, pd, valuePrinter);
+ displayProperty(app, builder, child, pd, valuePrinter);
} catch (IllegalArgumentException e) {
// Assume this child managed object does not support this
// property.
- if (getConsoleApplication().isScriptFriendly()) {
+ if (app.isScriptFriendly()) {
builder.appendCell();
} else {
builder.appendCell("-");
@@ -359,28 +373,35 @@
}
}
- PrintStream out = getConsoleApplication().getOutputStream();
- if (getConsoleApplication().isScriptFriendly()) {
+ PrintStream out = app.getOutputStream();
+ if (app.isScriptFriendly()) {
TablePrinter printer = createScriptFriendlyTablePrinter(out);
builder.print(printer);
} else {
+ if (app.isInteractive()) {
+ // Make interactive mode prettier.
+ app.println();
+ app.println();
+ }
+
TextTablePrinter printer = new TextTablePrinter(out);
printer.setColumnSeparator(":");
builder.print(printer);
}
}
- return 0;
+ return MenuResult.success(0);
}
// Display the set of values associated with a property.
- private <T> void displayProperty(TableBuilder builder, ManagedObject<?> mo,
- PropertyDefinition<T> pd, PropertyValuePrinter valuePrinter) {
+ private <T> void displayProperty(ConsoleApplication app,
+ TableBuilder builder, ManagedObject<?> mo, PropertyDefinition<T> pd,
+ PropertyValuePrinter valuePrinter) {
SortedSet<T> values = mo.getPropertyValues(pd);
if (values.isEmpty()) {
- if (getConsoleApplication().isScriptFriendly()) {
+ if (app.isScriptFriendly()) {
builder.appendCell();
} else {
builder.appendCell("-");
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/ManagementContextFactory.java b/opends/src/server/org/opends/server/tools/dsconfig/ManagementContextFactory.java
index 05aa008..c1c2669 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/ManagementContextFactory.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/ManagementContextFactory.java
@@ -32,6 +32,7 @@
import org.opends.server.tools.ClientException;
import org.opends.server.util.args.ArgumentException;
import org.opends.server.util.args.SubCommandArgumentParser;
+import org.opends.server.util.cli.ConsoleApplication;
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/PropertyValueEditor.java b/opends/src/server/org/opends/server/tools/dsconfig/PropertyValueEditor.java
new file mode 100644
index 0000000..d1ec4c7
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/PropertyValueEditor.java
@@ -0,0 +1,1888 @@
+/*
+ * 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.messages.DSConfigMessages.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.opends.messages.Message;
+import org.opends.messages.MessageBuilder;
+import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
+import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.AliasDefaultBehaviorProvider;
+import org.opends.server.admin.BooleanPropertyDefinition;
+import org.opends.server.admin.DefaultBehaviorProviderVisitor;
+import org.opends.server.admin.DefinedDefaultBehaviorProvider;
+import org.opends.server.admin.EnumPropertyDefinition;
+import org.opends.server.admin.IllegalPropertyValueException;
+import org.opends.server.admin.IllegalPropertyValueStringException;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyDefinitionUsageBuilder;
+import org.opends.server.admin.PropertyDefinitionVisitor;
+import org.opends.server.admin.PropertyIsMandatoryException;
+import org.opends.server.admin.PropertyIsReadOnlyException;
+import org.opends.server.admin.PropertyIsSingleValuedException;
+import org.opends.server.admin.PropertyOption;
+import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider;
+import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
+import org.opends.server.admin.UnknownPropertyDefinitionException;
+import org.opends.server.admin.client.ManagedObject;
+import org.opends.server.util.Validator;
+import org.opends.server.util.cli.CLIException;
+import org.opends.server.util.cli.ConsoleApplication;
+import org.opends.server.util.cli.HelpCallback;
+import org.opends.server.util.cli.Menu;
+import org.opends.server.util.cli.MenuBuilder;
+import org.opends.server.util.cli.MenuCallback;
+import org.opends.server.util.cli.MenuResult;
+import org.opends.server.util.table.TableBuilder;
+import org.opends.server.util.table.TextTablePrinter;
+
+
+
+/**
+ * Common methods used for interactively editing properties.
+ */
+public final class PropertyValueEditor {
+
+ /**
+ * A help call-back which displays a description and summary of a
+ * component and its properties.
+ */
+ private static final class ComponentHelpCallback implements HelpCallback {
+
+ // The managed object being edited.
+ private final ManagedObject<?> mo;
+
+ // The properties that can be edited.
+ private final Collection<PropertyDefinition<?>> properties;
+
+
+
+ // Creates a new component helper for the specified property.
+ private ComponentHelpCallback(ManagedObject<?> mo,
+ Collection<PropertyDefinition<?>> c) {
+ this.mo = mo;
+ this.properties = c;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void display(ConsoleApplication app) {
+ app.println();
+ HelpSubCommandHandler.displaySingleComponent(app, mo
+ .getManagedObjectDefinition(), properties);
+ app.println();
+ app.pressReturnToContinue();
+ }
+ }
+
+
+
+ /**
+ * A simple interface for querying and retrieving common default
+ * behavior properties.
+ */
+ private static final class DefaultBehaviorQuery<T> {
+
+ /**
+ * The type of default behavior.
+ */
+ private enum Type {
+ /**
+ * Alias default behavior.
+ */
+ ALIAS,
+
+ /**
+ * Defined default behavior.
+ */
+ DEFINED,
+
+ /**
+ * Inherited default behavior.
+ */
+ INHERITED,
+
+ /**
+ * Undefined default behavior.
+ */
+ UNDEFINED;
+ };
+
+
+
+ /**
+ * Create a new default behavior query object based on the provied
+ * property definition.
+ *
+ * @param <T>
+ * The type of property definition.
+ * @param pd
+ * The property definition.
+ * @return The default behavior query object.
+ */
+ public static <T> DefaultBehaviorQuery<T> query(PropertyDefinition<T> pd) {
+ DefaultBehaviorProviderVisitor<T, DefaultBehaviorQuery<T>,
+ PropertyDefinition<T>> visitor =
+ new DefaultBehaviorProviderVisitor<T, DefaultBehaviorQuery<T>,
+ PropertyDefinition<T>>() {
+
+ /**
+ * {@inheritDoc}
+ */
+ public DefaultBehaviorQuery<T> visitAbsoluteInherited(
+ AbsoluteInheritedDefaultBehaviorProvider<T> d,
+ PropertyDefinition<T> p) {
+ AbstractManagedObjectDefinition<?, ?> mod = d
+ .getManagedObjectDefinition();
+ String propertyName = d.getPropertyName();
+ PropertyDefinition<?> pd2 = mod.getPropertyDefinition(propertyName);
+
+ DefaultBehaviorQuery<?> query = query(pd2);
+ return new DefaultBehaviorQuery<T>(Type.INHERITED, query
+ .getAliasDescription());
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public DefaultBehaviorQuery<T> visitAlias(
+ AliasDefaultBehaviorProvider<T> d, PropertyDefinition<T> p) {
+ return new DefaultBehaviorQuery<T>(Type.ALIAS, d.getSynopsis());
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public DefaultBehaviorQuery<T> visitDefined(
+ DefinedDefaultBehaviorProvider<T> d, PropertyDefinition<T> p) {
+ return new DefaultBehaviorQuery<T>(Type.DEFINED, null);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public DefaultBehaviorQuery<T> visitRelativeInherited(
+ RelativeInheritedDefaultBehaviorProvider<T> d,
+ PropertyDefinition<T> p) {
+ AbstractManagedObjectDefinition<?, ?> mod = d
+ .getManagedObjectDefinition();
+ String propertyName = d.getPropertyName();
+ PropertyDefinition<?> pd2 = mod.getPropertyDefinition(propertyName);
+
+ DefaultBehaviorQuery<?> query = query(pd2);
+ return new DefaultBehaviorQuery<T>(Type.INHERITED, query
+ .getAliasDescription());
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public DefaultBehaviorQuery<T> visitUndefined(
+ UndefinedDefaultBehaviorProvider<T> d, PropertyDefinition<T> p) {
+ return new DefaultBehaviorQuery<T>(Type.UNDEFINED, null);
+ }
+ };
+
+ return pd.getDefaultBehaviorProvider().accept(visitor, pd);
+ }
+
+ // The description of the behavior if it is an alias default
+ // behavior.
+ private final Message aliasDescription;
+
+ // The type of behavior.
+ private final Type type;
+
+
+
+ // Private constructor.
+ private DefaultBehaviorQuery(Type type, Message aliasDescription) {
+ this.type = type;
+ this.aliasDescription = aliasDescription;
+ }
+
+
+
+ /**
+ * Gets the detailed description of this default behavior if it is
+ * an alias default behavior or if it inherits from an alias
+ * default behavior.
+ *
+ * @return Returns the detailed description of this default
+ * behavior if it is an alias default behavior or if it
+ * inherits from an alias default behavior, otherwise
+ * <code>null</code>.
+ */
+ public Message getAliasDescription() {
+ return aliasDescription;
+ }
+
+
+
+ /**
+ * Determines whether or not the default behavior is alias.
+ *
+ * @return Returns <code>true</code> if the default behavior is
+ * alias.
+ */
+ public boolean isAlias() {
+ return type == Type.ALIAS;
+ }
+
+
+
+ /**
+ * Determines whether or not the default behavior is defined.
+ *
+ * @return Returns <code>true</code> if the default behavior is
+ * defined.
+ */
+ public boolean isDefined() {
+ return type == Type.DEFINED;
+ }
+
+
+
+ /**
+ * Determines whether or not the default behavior is inherited.
+ *
+ * @return Returns <code>true</code> if the default behavior is
+ * inherited.
+ */
+ public boolean isInherited() {
+ return type == Type.INHERITED;
+ }
+
+
+
+ /**
+ * Determines whether or not the default behavior is undefined.
+ *
+ * @return Returns <code>true</code> if the default behavior is
+ * undefined.
+ */
+ public boolean isUndefined() {
+ return type == Type.UNDEFINED;
+ }
+
+ }
+
+
+
+ /**
+ * A property definition visitor which initializes mandatory
+ * properties.
+ */
+ private final class MandatoryPropertyInitializer extends
+ PropertyDefinitionVisitor<MenuResult<Void>, ManagedObject<?>> {
+
+ // Any exception that was caught during processing.
+ private CLIException e = null;
+
+
+
+ // Private constructor.
+ private MandatoryPropertyInitializer() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * Read the initial value(s) for a mandatory property.
+ *
+ * @param mo
+ * The managed object.
+ * @param pd
+ * The property definition.
+ * @return Returns <code>true</code> if new values were read
+ * successfully, or <code>false</code> if no values were
+ * read and the user chose to quit.
+ * @throws CLIException
+ * If the user input could not be retrieved for some
+ * reason.
+ */
+ public MenuResult<Void> read(ManagedObject<?> mo, PropertyDefinition<?> pd)
+ throws CLIException {
+ displayPropertyHeader(app, pd);
+
+ MenuResult<Void> result = pd.accept(this, mo);
+
+ if (e != null) {
+ throw e;
+ } else {
+ return result;
+ }
+ }
+
+
+
+ /**
+ * /** {@inheritDoc}
+ */
+ @Override
+ public MenuResult<Void> visitBoolean(BooleanPropertyDefinition d,
+ ManagedObject<?> p) {
+ MenuBuilder<Boolean> builder = new MenuBuilder<Boolean>(app);
+
+ builder
+ .setPrompt(INFO_EDITOR_PROMPT_SELECT_VALUE_SINGLE.get(d.getName()));
+
+ builder
+ .addNumberedOption(INFO_VALUE_TRUE.get(), MenuResult.success(true));
+ builder.addNumberedOption(INFO_VALUE_FALSE.get(), MenuResult
+ .success(false));
+
+ builder.addHelpOption(new PropertyHelpCallback(p
+ .getManagedObjectDefinition(), d));
+ if (app.isMenuDrivenMode()) {
+ builder.addCancelOption(true);
+ }
+ builder.addQuitOption();
+
+ Menu<Boolean> menu = builder.toMenu();
+ try {
+ app.println();
+ MenuResult<Boolean> result = menu.run();
+
+ if (result.isQuit()) {
+ return MenuResult.quit();
+ } else if (result.isCancel()) {
+ return MenuResult.cancel();
+ } else {
+ p.setPropertyValue(d, result.getValue());
+ return MenuResult.success();
+ }
+ } catch (CLIException e) {
+ this.e = e;
+ return MenuResult.cancel();
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <E extends Enum<E>> MenuResult<Void> visitEnum(
+ EnumPropertyDefinition<E> d, ManagedObject<?> p) {
+ MenuBuilder<E> builder = new MenuBuilder<E>(app);
+ builder.setMultipleColumnThreshold(MULTI_COLUMN_THRESHOLD);
+
+ if (d.hasOption(PropertyOption.MULTI_VALUED)) {
+ builder
+ .setPrompt(INFO_EDITOR_PROMPT_SELECT_VALUE_MULTI.get(d.getName()));
+ builder.setAllowMultiSelect(true);
+ } else {
+ builder.setPrompt(INFO_EDITOR_PROMPT_SELECT_VALUE_SINGLE
+ .get(d.getName()));
+ }
+
+ Set<E> values = new TreeSet<E>(d);
+ values.addAll(EnumSet.allOf(d.getEnumClass()));
+ for (E value : values) {
+ Message option = getPropertyValues(d, Collections.singleton(value));
+ builder.addNumberedOption(option, MenuResult.success(value));
+ }
+
+ builder.addHelpOption(new PropertyHelpCallback(p
+ .getManagedObjectDefinition(), d));
+ if (app.isMenuDrivenMode()) {
+ builder.addCancelOption(true);
+ }
+ builder.addQuitOption();
+
+ Menu<E> menu = builder.toMenu();
+ try {
+ app.println();
+ MenuResult<E> result = menu.run();
+
+ if (result.isQuit()) {
+ return MenuResult.quit();
+ } else if (result.isCancel()) {
+ return MenuResult.cancel();
+ } else {
+ p.setPropertyValues(d, result.getValues());
+ return MenuResult.success();
+ }
+ } catch (CLIException e) {
+ this.e = e;
+ return MenuResult.cancel();
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <T> MenuResult<Void> visitUnknown(PropertyDefinition<T> d,
+ ManagedObject<?> p) throws UnknownPropertyDefinitionException {
+ PropertyDefinitionUsageBuilder b = new PropertyDefinitionUsageBuilder(
+ true);
+ app.println();
+ app.println(INFO_EDITOR_HEADING_SYNTAX.get(b.getUsage(d)), 4);
+
+ // Set the new property value(s).
+ try {
+ p.setPropertyValues(d, readPropertyValues(app, p
+ .getManagedObjectDefinition(), d));
+ return MenuResult.success();
+ } catch (CLIException e) {
+ this.e = e;
+ return MenuResult.cancel();
+ }
+ }
+
+ }
+
+
+
+ /**
+ * A menu call-back for editing a modifiable multi-valued property.
+ */
+ private static final class MultiValuedPropertyEditor extends
+ PropertyDefinitionVisitor<MenuResult<Boolean>, ConsoleApplication>
+ implements MenuCallback<Boolean> {
+
+ // Any exception that was caught during processing.
+ private CLIException e = null;
+
+ // The managed object being edited.
+ private final ManagedObject<?> mo;
+
+ // The property to be edited.
+ private final PropertyDefinition<?> pd;
+
+
+
+ // Creates a new property editor for the specified property.
+ private MultiValuedPropertyEditor(ManagedObject<?> mo,
+ PropertyDefinition<?> pd) {
+ Validator.ensureTrue(pd.hasOption(PropertyOption.MULTI_VALUED));
+
+ this.mo = mo;
+ this.pd = pd;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public MenuResult<Boolean> invoke(ConsoleApplication app)
+ throws CLIException {
+ displayPropertyHeader(app, pd);
+
+ MenuResult<Boolean> result = pd.accept(this, app);
+ if (e != null) {
+ throw e;
+ } else {
+ return result;
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <T extends Enum<T>> MenuResult<Boolean> visitEnum(
+ final EnumPropertyDefinition<T> d, ConsoleApplication app) {
+ final SortedSet<T> defaultValues = mo.getPropertyDefaultValues(d);
+ final SortedSet<T> oldValues = mo.getPropertyValues(d);
+ final SortedSet<T> currentValues = mo.getPropertyValues(d);
+
+ boolean isFirst = true;
+ while (true) {
+ if (!isFirst) {
+ app.println();
+ app.println(INFO_EDITOR_HEADING_CONFIGURE_PROPERTY_CONT.get(d
+ .getName()));
+ } else {
+ isFirst = false;
+ }
+
+ if (currentValues.size() > 1) {
+ app.println();
+ app.println(INFO_EDITOR_HEADING_VALUES_SUMMARY.get(d.getName()));
+ app.println();
+ displayPropertyValues(app, d, currentValues);
+ }
+
+ // Create the add values call-back.
+ MenuCallback<Boolean> addCallback = null;
+
+ final EnumSet<T> values = EnumSet.allOf(d.getEnumClass());
+ values.removeAll(currentValues);
+
+ if (!values.isEmpty()) {
+ addCallback = new MenuCallback<Boolean>() {
+
+ public MenuResult<Boolean> invoke(ConsoleApplication app)
+ throws CLIException {
+ MenuBuilder<T> builder = new MenuBuilder<T>(app);
+
+ builder.setPrompt(INFO_EDITOR_PROMPT_SELECT_VALUES_ADD.get());
+ builder.setAllowMultiSelect(true);
+ builder.setMultipleColumnThreshold(MULTI_COLUMN_THRESHOLD);
+
+ for (T value : values) {
+ Message svalue = getPropertyValues(d, Collections
+ .singleton(value));
+ builder.addNumberedOption(svalue, MenuResult.success(value));
+ }
+
+ if (values.size() > 1) {
+ // No point in having this option if there's only one
+ // possible value.
+ builder.addNumberedOption(INFO_EDITOR_OPTION_ADD_ALL_VALUES
+ .get(), MenuResult.success(values));
+ }
+
+ builder.addHelpOption(new PropertyHelpCallback(mo
+ .getManagedObjectDefinition(), d));
+
+ builder.addCancelOption(true);
+ builder.addQuitOption();
+
+ app.println();
+ app.println();
+ Menu<T> menu = builder.toMenu();
+ MenuResult<T> result = menu.run();
+
+ if (result.isSuccess()) {
+ // Set the new property value(s).
+ currentValues.addAll(result.getValues());
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.success(false);
+ } else if (result.isCancel()) {
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.success(false);
+ } else {
+ return MenuResult.quit();
+ }
+ }
+
+ };
+ }
+
+ // Create the remove values call-back.
+ MenuCallback<Boolean> removeCallback = new MenuCallback<Boolean>() {
+
+ public MenuResult<Boolean> invoke(ConsoleApplication app)
+ throws CLIException {
+ MenuBuilder<T> builder = new MenuBuilder<T>(app);
+
+ builder.setPrompt(INFO_EDITOR_PROMPT_SELECT_VALUES_REMOVE.get());
+ builder.setAllowMultiSelect(true);
+ builder.setMultipleColumnThreshold(MULTI_COLUMN_THRESHOLD);
+
+ for (T value : currentValues) {
+ Message svalue = getPropertyValues(d, Collections
+ .singleton(value));
+ builder.addNumberedOption(svalue, MenuResult.success(value));
+ }
+
+ builder.addHelpOption(new PropertyHelpCallback(mo
+ .getManagedObjectDefinition(), d));
+
+ builder.addCancelOption(true);
+ builder.addQuitOption();
+
+ app.println();
+ app.println();
+ Menu<T> menu = builder.toMenu();
+ MenuResult<T> result = menu.run();
+
+ if (result.isSuccess()) {
+ // Set the new property value(s).
+ currentValues.removeAll(result.getValues());
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.success(false);
+ } else if (result.isCancel()) {
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.success(false);
+ } else {
+ return MenuResult.quit();
+ }
+ }
+
+ };
+
+ MenuResult<Boolean> result = runMenu(d, app, defaultValues, oldValues,
+ currentValues, addCallback, removeCallback);
+ if (!result.isAgain()) {
+ return result;
+ }
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <T> MenuResult<Boolean> visitUnknown(final PropertyDefinition<T> d,
+ ConsoleApplication app) {
+ PropertyDefinitionUsageBuilder b = new PropertyDefinitionUsageBuilder(
+ true);
+ app.println();
+ app.println(INFO_EDITOR_HEADING_SYNTAX.get(b.getUsage(d)), 4);
+
+ final SortedSet<T> defaultValues = mo.getPropertyDefaultValues(d);
+ final SortedSet<T> oldValues = mo.getPropertyValues(d);
+ final SortedSet<T> currentValues = mo.getPropertyValues(d);
+
+ boolean isFirst = true;
+ while (true) {
+ if (!isFirst) {
+ app.println();
+ app.println(INFO_EDITOR_HEADING_CONFIGURE_PROPERTY_CONT.get(d
+ .getName()));
+ } else {
+ isFirst = false;
+ }
+
+ if (currentValues.size() > 1) {
+ app.println();
+ app.println(INFO_EDITOR_HEADING_VALUES_SUMMARY.get(d.getName()));
+ app.println();
+ displayPropertyValues(app, d, currentValues);
+ }
+
+ // Create the add values call-back.
+ MenuCallback<Boolean> addCallback = new MenuCallback<Boolean>() {
+
+ public MenuResult<Boolean> invoke(ConsoleApplication app)
+ throws CLIException {
+ app.println();
+ readPropertyValues(app, mo.getManagedObjectDefinition(), d,
+ currentValues);
+ return MenuResult.success(false);
+ }
+
+ };
+
+ // Create the remove values call-back.
+ MenuCallback<Boolean> removeCallback = new MenuCallback<Boolean>() {
+
+ public MenuResult<Boolean> invoke(ConsoleApplication app)
+ throws CLIException {
+ MenuBuilder<T> builder = new MenuBuilder<T>(app);
+
+ builder.setPrompt(INFO_EDITOR_PROMPT_SELECT_VALUES_REMOVE.get());
+ builder.setAllowMultiSelect(true);
+ builder.setMultipleColumnThreshold(MULTI_COLUMN_THRESHOLD);
+
+ for (T value : currentValues) {
+ Message svalue = getPropertyValues(d, Collections
+ .singleton(value));
+ builder.addNumberedOption(svalue, MenuResult.success(value));
+ }
+
+ builder.addHelpOption(new PropertyHelpCallback(mo
+ .getManagedObjectDefinition(), d));
+
+ builder.addCancelOption(true);
+ builder.addQuitOption();
+
+ app.println();
+ app.println();
+ Menu<T> menu = builder.toMenu();
+ MenuResult<T> result = menu.run();
+
+ if (result.isSuccess()) {
+ // Set the new property value(s).
+ currentValues.removeAll(result.getValues());
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.success(false);
+ } else if (result.isCancel()) {
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.success(false);
+ } else {
+ return MenuResult.quit();
+ }
+ }
+
+ };
+
+ MenuResult<Boolean> result = runMenu(d, app, defaultValues, oldValues,
+ currentValues, addCallback, removeCallback);
+ if (!result.isAgain()) {
+ return result;
+ }
+ }
+ }
+
+
+
+ /**
+ * Generate an appropriate menu option for a property which asks
+ * the user whether or not they want to keep the property's
+ * current settings.
+ */
+ private <T> Message getKeepDefaultValuesMenuOption(
+ PropertyDefinition<T> pd, SortedSet<T> defaultValues,
+ SortedSet<T> oldValues, SortedSet<T> currentValues) {
+ DefaultBehaviorQuery<T> query = DefaultBehaviorQuery.query(pd);
+
+ boolean isModified = !currentValues.equals(oldValues);
+ boolean isDefault = currentValues.equals(defaultValues);
+
+ if (isModified) {
+ switch (currentValues.size()) {
+ case 0:
+ if (query.isAlias()) {
+ return INFO_EDITOR_OPTION_USE_DEFAULT_ALIAS.get(query
+ .getAliasDescription());
+ } else if (query.isInherited()) {
+ if (query.getAliasDescription() != null) {
+ return INFO_EDITOR_OPTION_USE_DEFAULT_INHERITED_ALIAS.get(query
+ .getAliasDescription());
+ } else {
+ return INFO_EDITOR_OPTION_USE_DEFAULT_INHERITED_ALIAS_UNDEFINED
+ .get();
+ }
+ } else {
+ return INFO_EDITOR_OPTION_LEAVE_UNDEFINED.get();
+ }
+ case 1:
+ Message svalue = getPropertyValues(pd, currentValues);
+ if (isDefault) {
+ if (query.isInherited()) {
+ return INFO_EDITOR_OPTION_USE_INHERITED_DEFAULT_VALUE.get(svalue);
+ } else {
+ return INFO_EDITOR_OPTION_USE_DEFAULT_VALUE.get(svalue);
+ }
+ } else {
+ return INFO_EDITOR_OPTION_USE_VALUE.get(svalue);
+ }
+ default:
+ if (isDefault) {
+ if (query.isInherited()) {
+ return INFO_EDITOR_OPTION_USE_INHERITED_DEFAULT_VALUES.get();
+ } else {
+ return INFO_EDITOR_OPTION_USE_DEFAULT_VALUES.get();
+ }
+ } else {
+ return INFO_EDITOR_OPTION_USE_VALUES.get();
+ }
+ }
+ } else {
+ switch (currentValues.size()) {
+ case 0:
+ if (query.isAlias()) {
+ return INFO_EDITOR_OPTION_KEEP_DEFAULT_ALIAS.get(query
+ .getAliasDescription());
+ } else if (query.isInherited()) {
+ if (query.getAliasDescription() != null) {
+ return INFO_EDITOR_OPTION_KEEP_DEFAULT_INHERITED_ALIAS.get(query
+ .getAliasDescription());
+ } else {
+ return INFO_EDITOR_OPTION_KEEP_DEFAULT_INHERITED_ALIAS_UNDEFINED
+ .get();
+ }
+ } else {
+ return INFO_EDITOR_OPTION_LEAVE_UNDEFINED.get();
+ }
+ case 1:
+ Message svalue = getPropertyValues(pd, currentValues);
+ if (isDefault) {
+ if (query.isInherited()) {
+ return INFO_EDITOR_OPTION_KEEP_INHERITED_DEFAULT_VALUE
+ .get(svalue);
+ } else {
+ return INFO_EDITOR_OPTION_KEEP_DEFAULT_VALUE.get(svalue);
+ }
+ } else {
+ return INFO_EDITOR_OPTION_KEEP_VALUE.get(svalue);
+ }
+ default:
+ if (isDefault) {
+ if (query.isInherited()) {
+ return INFO_EDITOR_OPTION_KEEP_INHERITED_DEFAULT_VALUES.get();
+ } else {
+ return INFO_EDITOR_OPTION_KEEP_DEFAULT_VALUES.get();
+ }
+ } else {
+ return INFO_EDITOR_OPTION_KEEP_VALUES.get();
+ }
+ }
+ }
+ }
+
+
+
+ /**
+ * Generate an appropriate menu option which should be used in the
+ * case where a property can be reset to its default behavior.
+ */
+ private <T> Message getResetToDefaultValuesMenuOption(
+ PropertyDefinition<T> pd, SortedSet<T> defaultValues,
+ SortedSet<T> currentValues) {
+ DefaultBehaviorQuery<T> query = DefaultBehaviorQuery.query(pd);
+ boolean isMandatory = pd.hasOption(PropertyOption.MANDATORY);
+
+ if (!isMandatory && query.isAlias()) {
+ return INFO_EDITOR_OPTION_RESET_DEFAULT_ALIAS.get(query
+ .getAliasDescription());
+ } else if (query.isDefined()) {
+ // Only show this option if the current value is different
+ // to the default.
+ if (!currentValues.equals(defaultValues)) {
+ Message svalue = getPropertyValues(pd, defaultValues);
+ if (defaultValues.size() > 1) {
+ return INFO_EDITOR_OPTION_RESET_DEFAULT_VALUES.get(svalue);
+ } else {
+ return INFO_EDITOR_OPTION_RESET_DEFAULT_VALUE.get(svalue);
+ }
+ } else {
+ return null;
+ }
+ } else if (!isMandatory && query.isInherited()) {
+ if (defaultValues.isEmpty()) {
+ if (query.getAliasDescription() != null) {
+ return INFO_EDITOR_OPTION_RESET_DEFAULT_INHERITED_ALIAS.get(query
+ .getAliasDescription());
+ } else {
+ return INFO_EDITOR_OPTION_RESET_DEFAULT_INHERITED_ALIAS_UNDEFINED
+ .get();
+ }
+ } else {
+ Message svalue = getPropertyValues(pd, defaultValues);
+ if (defaultValues.size() > 1) {
+ return INFO_EDITOR_OPTION_RESET_INHERITED_DEFAULT_VALUES
+ .get(svalue);
+ } else {
+ return INFO_EDITOR_OPTION_RESET_INHERITED_DEFAULT_VALUE.get(svalue);
+ }
+ }
+ } else if (!isMandatory && query.isUndefined()) {
+ return INFO_EDITOR_OPTION_LEAVE_UNDEFINED.get();
+ } else {
+ return null;
+ }
+ }
+
+
+
+ // Common menu processing.
+ private <T> MenuResult<Boolean> runMenu(final PropertyDefinition<T> d,
+ ConsoleApplication app, final SortedSet<T> defaultValues,
+ final SortedSet<T> oldValues, final SortedSet<T> currentValues,
+ MenuCallback<Boolean> addCallback,
+ MenuCallback<Boolean> removeCallback) {
+ // Construct a menu of actions.
+ MenuBuilder<Boolean> builder = new MenuBuilder<Boolean>(app);
+ builder.setPrompt(INFO_EDITOR_PROMPT_MODIFY_MENU.get(d.getName()));
+
+ // First option is for leaving the property unchanged or
+ // applying changes, but only if the state of the property is
+ // valid.
+ if (!(d.hasOption(PropertyOption.MANDATORY) && currentValues.isEmpty())) {
+ MenuResult<Boolean> result;
+ if (!oldValues.equals(currentValues)) {
+ result = MenuResult.success(true);
+ } else {
+ result = MenuResult.<Boolean> cancel();
+ }
+
+ Message option = getKeepDefaultValuesMenuOption(d, defaultValues,
+ oldValues, currentValues);
+ builder.addNumberedOption(option, result);
+ builder.setDefault(Message.raw("1"), result);
+ }
+
+ // Add an option for adding some values.
+ if (addCallback != null) {
+ int i = builder.addNumberedOption(
+ INFO_EDITOR_OPTION_ADD_ONE_OR_MORE_VALUES.get(), addCallback);
+ if (d.hasOption(PropertyOption.MANDATORY) && currentValues.isEmpty()) {
+ builder.setDefault(Message.raw("%d", i), addCallback);
+ }
+ }
+
+ // Add options for removing values if applicable.
+ if (!currentValues.isEmpty()) {
+ builder.addNumberedOption(INFO_EDITOR_OPTION_REMOVE_ONE_OR_MORE_VALUES
+ .get(), removeCallback);
+ }
+
+ // Add options for removing all values and for resetting the
+ // property to its default behavior.
+ Message resetOption = null;
+ if (!currentValues.equals(defaultValues)) {
+ resetOption = getResetToDefaultValuesMenuOption(d, defaultValues,
+ currentValues);
+ }
+
+ if (!currentValues.isEmpty()) {
+ if (resetOption == null || !defaultValues.isEmpty()) {
+ MenuCallback<Boolean> callback = new MenuCallback<Boolean>() {
+
+ public MenuResult<Boolean> invoke(ConsoleApplication app)
+ throws CLIException {
+ currentValues.clear();
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.success(false);
+ }
+
+ };
+
+ builder.addNumberedOption(INFO_EDITOR_OPTION_REMOVE_ALL_VALUES.get(),
+ callback);
+ }
+ }
+
+ if (resetOption != null) {
+ MenuCallback<Boolean> callback = new MenuCallback<Boolean>() {
+
+ public MenuResult<Boolean> invoke(ConsoleApplication app)
+ throws CLIException {
+ currentValues.clear();
+ currentValues.addAll(defaultValues);
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.success(false);
+ }
+
+ };
+
+ builder.addNumberedOption(resetOption, callback);
+ }
+
+ // Add an option for undoing any changes.
+ if (!oldValues.equals(currentValues)) {
+ MenuCallback<Boolean> callback = new MenuCallback<Boolean>() {
+
+ public MenuResult<Boolean> invoke(ConsoleApplication app)
+ throws CLIException {
+ currentValues.clear();
+ currentValues.addAll(oldValues);
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.success(false);
+ }
+
+ };
+
+ builder.addNumberedOption(INFO_EDITOR_OPTION_REVERT_CHANGES.get(),
+ callback);
+ }
+
+ builder.addHelpOption(new PropertyHelpCallback(mo
+ .getManagedObjectDefinition(), d));
+ builder.addQuitOption();
+
+ Menu<Boolean> menu = builder.toMenu();
+ MenuResult<Boolean> result;
+ try {
+ app.println();
+ result = menu.run();
+ } catch (CLIException e) {
+ this.e = e;
+ return null;
+ }
+
+ if (result.isSuccess()) {
+ if (result.getValue() == true) {
+ // Set the new property value(s).
+ mo.setPropertyValues(d, currentValues);
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.success(false);
+ } else {
+ // Continue until cancel/apply changes.
+ app.println();
+ return MenuResult.again();
+ }
+ } else if (result.isCancel()) {
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.success(false);
+ } else {
+ return MenuResult.quit();
+ }
+ }
+ }
+
+
+
+ /**
+ * A help call-back which displays a description and summary of a
+ * single property.
+ */
+ private static final class PropertyHelpCallback implements HelpCallback {
+
+ // The managed object definition.
+ private final ManagedObjectDefinition<?, ?> d;
+
+ // The property to be edited.
+ private final PropertyDefinition<?> pd;
+
+
+
+ // Creates a new property helper for the specified property.
+ private PropertyHelpCallback(ManagedObjectDefinition<?, ?> d,
+ PropertyDefinition<?> pd) {
+ this.d = d;
+ this.pd = pd;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void display(ConsoleApplication app) {
+ app.println();
+ HelpSubCommandHandler.displayVerboseSingleProperty(app, d, pd.getName());
+ app.println();
+ app.pressReturnToContinue();
+ }
+ }
+
+
+
+ /**
+ * A menu call-back for viewing a read-only properties.
+ */
+ private static final class ReadOnlyPropertyViewer extends
+ PropertyDefinitionVisitor<MenuResult<Boolean>, ConsoleApplication>
+ implements MenuCallback<Boolean> {
+
+ // Any exception that was caught during processing.
+ private CLIException e = null;
+
+ // The managed object being edited.
+ private final ManagedObject<?> mo;
+
+ // The property to be edited.
+ private final PropertyDefinition<?> pd;
+
+
+
+ // Creates a new property editor for the specified property.
+ private ReadOnlyPropertyViewer(ManagedObject<?> mo,
+ PropertyDefinition<?> pd) {
+ Validator.ensureTrue(!pd.hasOption(PropertyOption.MULTI_VALUED));
+
+ this.mo = mo;
+ this.pd = pd;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public MenuResult<Boolean> invoke(ConsoleApplication app)
+ throws CLIException {
+ MenuResult<Boolean> result = pd.accept(this, app);
+ if (e != null) {
+ throw e;
+ } else {
+ return result;
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <T> MenuResult<Boolean> visitUnknown(PropertyDefinition<T> pd,
+ ConsoleApplication app) {
+ SortedSet<T> values = mo.getPropertyValues(pd);
+
+ app.println();
+ app.println();
+ switch (values.size()) {
+ case 0:
+ // Only alias, undefined, or inherited alias or undefined
+ // properties should apply here.
+ DefaultBehaviorQuery<T> query = DefaultBehaviorQuery.query(pd);
+ Message aliasDescription = query.getAliasDescription();
+ if (aliasDescription == null) {
+ app.println(INFO_EDITOR_HEADING_READ_ONLY_ALIAS_UNDEFINED.get(pd
+ .getName()));
+ } else {
+ app.println(INFO_EDITOR_HEADING_READ_ONLY_ALIAS.get(pd.getName(),
+ aliasDescription));
+ }
+ break;
+ case 1:
+ Message svalue = getPropertyValues(pd, mo);
+ app.println(INFO_EDITOR_HEADING_READ_ONLY_VALUE.get(pd.getName(),
+ svalue));
+ break;
+ default:
+ app.println(INFO_EDITOR_HEADING_READ_ONLY_VALUES.get(pd.getName()));
+ app.println();
+ displayPropertyValues(app, pd, values);
+ break;
+ }
+
+ app.println();
+ boolean result;
+ try {
+ result = app.confirmAction(INFO_EDITOR_PROMPT_READ_ONLY.get(), false);
+ } catch (CLIException e) {
+ this.e = e;
+ return null;
+ }
+
+ if (result) {
+ app.println();
+ HelpSubCommandHandler.displayVerboseSingleProperty(app, mo
+ .getManagedObjectDefinition(), pd.getName());
+ app.println();
+ app.pressReturnToContinue();
+ }
+
+ return MenuResult.again();
+ }
+ }
+
+
+
+ /**
+ * A menu call-back for editing a modifiable single-valued property.
+ */
+ private static final class SingleValuedPropertyEditor extends
+ PropertyDefinitionVisitor<MenuResult<Boolean>, ConsoleApplication>
+ implements MenuCallback<Boolean> {
+
+ // Any exception that was caught during processing.
+ private CLIException e = null;
+
+ // The managed object being edited.
+ private final ManagedObject<?> mo;
+
+ // The property to be edited.
+ private final PropertyDefinition<?> pd;
+
+
+
+ // Creates a new property editor for the specified property.
+ private SingleValuedPropertyEditor(ManagedObject<?> mo,
+ PropertyDefinition<?> pd) {
+ Validator.ensureTrue(!pd.hasOption(PropertyOption.MULTI_VALUED));
+
+ this.mo = mo;
+ this.pd = pd;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public MenuResult<Boolean> invoke(ConsoleApplication app)
+ throws CLIException {
+ displayPropertyHeader(app, pd);
+
+ MenuResult<Boolean> result = pd.accept(this, app);
+ if (e != null) {
+ throw e;
+ } else {
+ return result;
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public MenuResult<Boolean> visitBoolean(BooleanPropertyDefinition d,
+ ConsoleApplication app) {
+ // Construct a menu of actions.
+ MenuBuilder<Boolean> builder = new MenuBuilder<Boolean>(app);
+ builder.setPrompt(INFO_EDITOR_PROMPT_MODIFY_MENU.get(d.getName()));
+
+ DefaultBehaviorQuery<Boolean> query = DefaultBehaviorQuery.query(d);
+ SortedSet<Boolean> currentValues = mo.getPropertyValues(d);
+ SortedSet<Boolean> defaultValues = mo.getPropertyDefaultValues(d);
+
+ Boolean currentValue = currentValues.isEmpty() ? null : currentValues
+ .first();
+ Boolean defaultValue = defaultValues.isEmpty() ? null : defaultValues
+ .first();
+
+ // First option is for leaving the property unchanged.
+ Message option = getKeepDefaultValuesMenuOption(d);
+ builder.addNumberedOption(option, MenuResult.<Boolean> cancel());
+ builder.setDefault(Message.raw("1"), MenuResult.<Boolean> cancel());
+
+ // The second (and possibly third) option is to always change
+ // the property's value.
+ if (currentValue == null || currentValue == false) {
+ Message svalue = getPropertyValues(d, Collections.singleton(true));
+
+ if (defaultValue != null && defaultValue == true) {
+ option = INFO_EDITOR_OPTION_CHANGE_TO_DEFAULT_VALUE.get(svalue);
+ } else {
+ option = INFO_EDITOR_OPTION_CHANGE_TO_VALUE.get(svalue);
+ }
+
+ builder.addNumberedOption(option, MenuResult.success(true));
+ }
+
+ if (currentValue == null || currentValue == true) {
+ Message svalue = getPropertyValues(d, Collections.singleton(false));
+
+ if (defaultValue != null && defaultValue == false) {
+ option = INFO_EDITOR_OPTION_CHANGE_TO_DEFAULT_VALUE.get(svalue);
+ } else {
+ option = INFO_EDITOR_OPTION_CHANGE_TO_VALUE.get(svalue);
+ }
+
+ builder.addNumberedOption(option, MenuResult.success(false));
+ }
+
+ // Final option is to reset the value back to its default.
+ if (mo.isPropertyPresent(d) && !query.isDefined()) {
+ option = getResetToDefaultValuesMenuOption(d);
+ if (option != null) {
+ builder.addNumberedOption(option, MenuResult.<Boolean> success());
+ }
+ }
+
+ return runMenu(app, d, builder);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <E extends Enum<E>> MenuResult<Boolean> visitEnum(
+ EnumPropertyDefinition<E> d, ConsoleApplication app) {
+ // Construct a menu of actions.
+ MenuBuilder<E> builder = new MenuBuilder<E>(app);
+ builder.setMultipleColumnThreshold(MULTI_COLUMN_THRESHOLD);
+ builder.setPrompt(INFO_EDITOR_PROMPT_MODIFY_MENU.get(d.getName()));
+
+ DefaultBehaviorQuery<E> query = DefaultBehaviorQuery.query(d);
+ SortedSet<E> currentValues = mo.getPropertyValues(d);
+ SortedSet<E> defaultValues = mo.getPropertyDefaultValues(d);
+ E currentValue = currentValues.isEmpty() ? null : currentValues.first();
+ E defaultValue = defaultValues.isEmpty() ? null : defaultValues.first();
+
+ // First option is for leaving the property unchanged.
+ Message option = getKeepDefaultValuesMenuOption(d);
+ builder.addNumberedOption(option, MenuResult.<E> cancel());
+ builder.setDefault(Message.raw("1"), MenuResult.<E> cancel());
+
+ // Create options for changing to other values.
+ Set<E> values = new TreeSet<E>(d);
+ values.addAll(EnumSet.allOf(d.getEnumClass()));
+ for (E value : values) {
+ if (value.equals(currentValue) && query.isDefined()) {
+ // This option is unnecessary.
+ continue;
+ }
+
+ Message svalue = getPropertyValues(d, Collections.singleton(value));
+
+ if (value.equals(defaultValue) && query.isDefined()) {
+ option = INFO_EDITOR_OPTION_CHANGE_TO_DEFAULT_VALUE.get(svalue);
+ } else {
+ option = INFO_EDITOR_OPTION_CHANGE_TO_VALUE.get(svalue);
+ }
+
+ builder.addNumberedOption(option, MenuResult.success(value));
+ }
+
+ // Third option is to reset the value back to its default.
+ if (mo.isPropertyPresent(d) && !query.isDefined()) {
+ option = getResetToDefaultValuesMenuOption(d);
+ if (option != null) {
+ builder.addNumberedOption(option, MenuResult.<E> success());
+ }
+ }
+
+ return runMenu(app, d, builder);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <T> MenuResult<Boolean> visitUnknown(final PropertyDefinition<T> d,
+ ConsoleApplication app) {
+ PropertyDefinitionUsageBuilder b = new PropertyDefinitionUsageBuilder(
+ true);
+ app.println();
+ app.println(INFO_EDITOR_HEADING_SYNTAX.get(b.getUsage(d)), 4);
+
+ // Construct a menu of actions.
+ MenuBuilder<T> builder = new MenuBuilder<T>(app);
+ builder.setPrompt(INFO_EDITOR_PROMPT_MODIFY_MENU.get(d.getName()));
+
+ // First option is for leaving the property unchanged.
+ Message option = getKeepDefaultValuesMenuOption(d);
+ builder.addNumberedOption(option, MenuResult.<T> cancel());
+ builder.setDefault(Message.raw("1"), MenuResult.<T> cancel());
+
+ // The second option is to always change the property's value.
+ builder.addNumberedOption(INFO_EDITOR_OPTION_CHANGE_VALUE.get(),
+ new MenuCallback<T>() {
+
+ public MenuResult<T> invoke(ConsoleApplication app)
+ throws CLIException {
+ app.println();
+ Set<T> values = readPropertyValues(app, mo
+ .getManagedObjectDefinition(), d);
+ return MenuResult.success(values);
+ }
+
+ });
+
+ // Third option is to reset the value back to its default.
+ if (mo.isPropertyPresent(d)) {
+ option = getResetToDefaultValuesMenuOption(d);
+ if (option != null) {
+ builder.addNumberedOption(option, MenuResult.<T> success());
+ }
+ }
+
+ return runMenu(app, d, builder);
+ }
+
+
+
+ /**
+ * Generate an appropriate menu option for a property which asks
+ * the user whether or not they want to keep the property's
+ * current settings.
+ */
+ private <T> Message getKeepDefaultValuesMenuOption(
+ PropertyDefinition<T> pd) {
+ DefaultBehaviorQuery<T> query = DefaultBehaviorQuery.query(pd);
+ SortedSet<T> currentValues = mo.getPropertyValues(pd);
+ SortedSet<T> defaultValues = mo.getPropertyDefaultValues(pd);
+
+ if (query.isDefined() && currentValues.equals(defaultValues)) {
+ Message svalue = getPropertyValues(pd, currentValues);
+ return INFO_EDITOR_OPTION_KEEP_DEFAULT_VALUE.get(svalue);
+ } else if (mo.isPropertyPresent(pd)) {
+ Message svalue = getPropertyValues(pd, currentValues);
+ return INFO_EDITOR_OPTION_KEEP_VALUE.get(svalue);
+ } else if (query.isAlias()) {
+ return INFO_EDITOR_OPTION_KEEP_DEFAULT_ALIAS.get(query
+ .getAliasDescription());
+ } else if (query.isInherited()) {
+ if (defaultValues.isEmpty()) {
+ if (query.getAliasDescription() != null) {
+ return INFO_EDITOR_OPTION_KEEP_DEFAULT_INHERITED_ALIAS.get(query
+ .getAliasDescription());
+ } else {
+ return INFO_EDITOR_OPTION_KEEP_DEFAULT_INHERITED_ALIAS_UNDEFINED
+ .get();
+ }
+ } else {
+ Message svalue = getPropertyValues(pd, defaultValues);
+ return INFO_EDITOR_OPTION_KEEP_INHERITED_DEFAULT_VALUE.get(svalue);
+ }
+ } else {
+ return INFO_EDITOR_OPTION_LEAVE_UNDEFINED.get();
+ }
+ }
+
+
+
+ /**
+ * Generate an appropriate menu option which should be used in the
+ * case where a property can be reset to its default behavior.
+ */
+ private <T> Message getResetToDefaultValuesMenuOption(
+ PropertyDefinition<T> pd) {
+ DefaultBehaviorQuery<T> query = DefaultBehaviorQuery.query(pd);
+ SortedSet<T> currentValues = mo.getPropertyValues(pd);
+ SortedSet<T> defaultValues = mo.getPropertyDefaultValues(pd);
+
+ boolean isMandatory = pd.hasOption(PropertyOption.MANDATORY);
+
+ if (!isMandatory && query.isAlias()) {
+ return INFO_EDITOR_OPTION_RESET_DEFAULT_ALIAS.get(query
+ .getAliasDescription());
+ } else if (query.isDefined()) {
+ // Only show this option if the current value is different
+ // to the default.
+ if (!currentValues.equals(defaultValues)) {
+ Message svalue = getPropertyValues(pd, defaultValues);
+ return INFO_EDITOR_OPTION_RESET_DEFAULT_VALUE.get(svalue);
+ } else {
+ return null;
+ }
+ } else if (!isMandatory && query.isInherited()) {
+ if (defaultValues.isEmpty()) {
+ if (query.getAliasDescription() != null) {
+ return INFO_EDITOR_OPTION_RESET_DEFAULT_INHERITED_ALIAS.get(query
+ .getAliasDescription());
+ } else {
+ return INFO_EDITOR_OPTION_RESET_DEFAULT_INHERITED_ALIAS_UNDEFINED
+ .get();
+ }
+ } else {
+ Message svalue = getPropertyValues(pd, defaultValues);
+ return INFO_EDITOR_OPTION_RESET_INHERITED_DEFAULT_VALUE.get(svalue);
+ }
+ } else if (!isMandatory && query.isUndefined()) {
+ return INFO_EDITOR_OPTION_LEAVE_UNDEFINED.get();
+ } else {
+ return null;
+ }
+ }
+
+
+
+ // Common menu processing.
+ private <T> MenuResult<Boolean> runMenu(ConsoleApplication app,
+ final PropertyDefinition<T> d, MenuBuilder<T> builder)
+ throws IllegalPropertyValueException, PropertyIsSingleValuedException,
+ PropertyIsReadOnlyException, PropertyIsMandatoryException,
+ IllegalArgumentException {
+ builder.addHelpOption(new PropertyHelpCallback(mo
+ .getManagedObjectDefinition(), d));
+ builder.addQuitOption();
+
+ Menu<T> menu = builder.toMenu();
+ MenuResult<T> result;
+ try {
+ app.println();
+ result = menu.run();
+ } catch (CLIException e) {
+ this.e = e;
+ return null;
+ }
+
+ if (result.isSuccess()) {
+ // Set the new property value(s).
+ mo.setPropertyValues(d, result.getValues());
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.success(false);
+ } else if (result.isCancel()) {
+ app.println();
+ app.pressReturnToContinue();
+ return MenuResult.success(false);
+ } else {
+ return MenuResult.quit();
+ }
+ }
+ }
+
+
+
+ // Display a title and a description of the property.
+ private static void displayPropertyHeader(ConsoleApplication app,
+ PropertyDefinition<?> pd) {
+ app.println();
+ app.println();
+ app.println(INFO_EDITOR_HEADING_CONFIGURE_PROPERTY.get(pd.getName()));
+ app.println();
+ app.println(pd.getSynopsis(), 4);
+ if (pd.getDescription() != null) {
+ app.println();
+ app.println(pd.getDescription(), 4);
+ }
+ }
+
+
+
+ // Display a table of property values.
+ private static <T> void displayPropertyValues(ConsoleApplication app,
+ PropertyDefinition<T> pd, Collection<T> values)
+ throws IllegalArgumentException {
+ TableBuilder builder = new TableBuilder();
+ PropertyValuePrinter valuePrinter = new PropertyValuePrinter(null,
+ null, false);
+
+ int sz = values.size();
+ boolean useMultipleColumns = (sz >= MULTI_COLUMN_THRESHOLD);
+ int rows = sz;
+ if (useMultipleColumns) {
+ // Display in two columns the first column should contain
+ // half the values. If there are an odd number of columns
+ // then the first column should contain an additional value
+ // (e.g. if there are 23 values, the first column should
+ // contain 12 values and the second column 11 values).
+ rows /= 2;
+ rows += sz % 2;
+ }
+
+ List<T> vl = new ArrayList<T>(values);
+ for (int i = 0, j = rows; i < rows; i++, j++) {
+ builder.startRow();
+ builder.appendCell();
+ builder.appendCell(INFO_EDITOR_OPTION_VALUES.get(i + 1));
+ builder.appendCell(valuePrinter.print(pd, vl.get(i)));
+
+ if (useMultipleColumns && (j < sz)) {
+ builder.appendCell();
+ builder.appendCell(INFO_EDITOR_OPTION_VALUES.get(j + 1));
+ builder.appendCell(valuePrinter.print(pd, vl.get(j)));
+ }
+ }
+
+ TextTablePrinter printer = new TextTablePrinter(app.getErrorStream());
+ printer.setDisplayHeadings(false);
+ printer.setColumnWidth(0, 2);
+ printer.setColumnWidth(2, 0);
+ if (useMultipleColumns) {
+ printer.setColumnWidth(3, 2);
+ printer.setColumnWidth(5, 0);
+ }
+ builder.print(printer);
+ }
+
+
+
+ // Display the set of values associated with a property.
+ private static <T> Message getPropertyValues(PropertyDefinition<T> pd,
+ Collection<T> values) {
+ if (values.isEmpty()) {
+ // There are no values or default values. Display the default
+ // behavior for alias values.
+ DefaultBehaviorQuery<T> query = DefaultBehaviorQuery.query(pd);
+ Message content = query.getAliasDescription();
+ if (content == null) {
+ return Message.raw("-");
+ } else {
+ return content;
+ }
+ } else {
+ PropertyValuePrinter printer =
+ new PropertyValuePrinter(null, null, false);
+ MessageBuilder builder = new MessageBuilder();
+
+ boolean isFirst = true;
+ for (T value : values) {
+ if (!isFirst) {
+ builder.append(", ");
+ }
+ builder.append(printer.print(pd, value));
+ isFirst = false;
+ }
+
+ return builder.toMessage();
+ }
+ }
+
+
+
+ // Display the set of values associated with a property.
+ private static <T> Message getPropertyValues(
+ PropertyDefinition<T> pd,
+ ManagedObject<?> mo) {
+ SortedSet<T> values = mo.getPropertyValues(pd);
+ return getPropertyValues(pd, values);
+ }
+
+
+
+ // Read new values for a property.
+ private static <T> SortedSet<T> readPropertyValues(ConsoleApplication app,
+ ManagedObjectDefinition<?, ?> d, PropertyDefinition<T> pd)
+ throws CLIException {
+ SortedSet<T> values = new TreeSet<T>(pd);
+ readPropertyValues(app, d, pd, values);
+ return values;
+ }
+
+
+
+ // Add values to a property.
+ private static <T> void readPropertyValues(ConsoleApplication app,
+ ManagedObjectDefinition<?, ?> d, PropertyDefinition<T> pd,
+ SortedSet<T> values) throws CLIException {
+ // Make sure there is at least one value if mandatory and empty.
+ if (values.isEmpty()) {
+ while (true) {
+ try {
+ Message prompt;
+
+ if (pd.hasOption(PropertyOption.MANDATORY)) {
+ prompt = INFO_EDITOR_PROMPT_READ_FIRST_VALUE.get(pd.getName());
+ } else {
+ prompt = INFO_EDITOR_PROMPT_READ_FIRST_VALUE_OPTIONAL.get(pd
+ .getName());
+ }
+
+ app.println();
+ String s = app.readLineOfInput(prompt);
+ if (s.trim().length() == 0) {
+ if (!pd.hasOption(PropertyOption.MANDATORY)) {
+ return;
+ }
+ }
+
+ T value = pd.decodeValue(s);
+ if (values.contains(value)) {
+ // Prevent addition of duplicates.
+ app.println();
+ app.println(ERR_EDITOR_READ_FIRST_DUPLICATE.get(s));
+ } else {
+ values.add(value);
+ }
+
+ break;
+ } catch (IllegalPropertyValueStringException e) {
+ app.println();
+ app.println(ArgumentExceptionFactory.adaptPropertyException(e, d)
+ .getMessageObject());
+ }
+ }
+ }
+
+ if (pd.hasOption(PropertyOption.MULTI_VALUED)) {
+ // Prompt for more values if multi-valued.
+ while (true) {
+ try {
+ Message prompt = INFO_EDITOR_PROMPT_READ_NEXT_VALUE.get(pd.getName());
+
+ app.println();
+ String s = app.readLineOfInput(prompt);
+ if (s.trim().length() == 0) {
+ return;
+ }
+
+ T value = pd.decodeValue(s);
+ if (values.contains(value)) {
+ // Prevent addition of duplicates.
+ app.println();
+ app.println(ERR_EDITOR_READ_NEXT_DUPLICATE.get(s));
+ } else {
+ values.add(value);
+ }
+ } catch (IllegalPropertyValueStringException e) {
+ app.println();
+ app.println(ArgumentExceptionFactory.adaptPropertyException(e, d)
+ .getMessageObject());
+ app.println();
+ }
+ }
+ }
+ }
+
+ // The threshold above which choice menus should be displayed in
+ // multiple columns.
+ private static final int MULTI_COLUMN_THRESHOLD = 8;
+
+ // The application console.
+ private final ConsoleApplication app;
+
+
+
+ /**
+ * Create a new property value editor which will read from the
+ * provided application console.
+ *
+ * @param app
+ * The application console.
+ */
+ public PropertyValueEditor(ConsoleApplication app) {
+ this.app = app;
+ }
+
+
+
+ /**
+ * Interactively edits the properties of a managed object. Only the
+ * properties listed in the provided collection will be accessible
+ * to the client. It is up to the caller to ensure that the list of
+ * properties does not include read-only, monitoring, hidden, or
+ * advanced properties as appropriate.
+ *
+ * @param mo
+ * The managed object.
+ * @param c
+ * The collection of properties which can be edited.
+ * @param isCreate
+ * Flag indicating whether or not the managed object is
+ * being created. If it is then read-only properties will
+ * be modifiable.
+ * @return Returns {@link MenuResult#success()} if the changes made
+ * to the managed object should be applied, or
+ * {@link MenuResult#cancel()} if the user to chose to
+ * cancel any changes, or {@link MenuResult#quit()} if the
+ * user chose to quit the application.
+ * @throws CLIException
+ * If the user input could not be retrieved for some
+ * reason.
+ */
+ public MenuResult<Void> edit(ManagedObject<?> mo,
+ Collection<PropertyDefinition<?>> c, boolean isCreate)
+ throws CLIException {
+ // Get values for this missing mandatory property.
+ MandatoryPropertyInitializer mpi = new MandatoryPropertyInitializer();
+ for (PropertyDefinition<?> pd : c) {
+ if (pd.hasOption(PropertyOption.MANDATORY)) {
+ if (mo.getPropertyValues(pd).isEmpty()) {
+ MenuResult<Void> result = mpi.read(mo, pd);
+ if (!result.isSuccess()) {
+ return result;
+ }
+ }
+ }
+ }
+
+ while (true) {
+ // Construct the main menu.
+ MenuBuilder<Boolean> builder = new MenuBuilder<Boolean>(app);
+
+ Message ufn = mo.getManagedObjectDefinition().getUserFriendlyName();
+ builder.setPrompt(INFO_EDITOR_HEADING_CONFIGURE_COMPONENT.get(ufn));
+
+ Message heading1 = INFO_DSCFG_HEADING_PROPERTY_NAME.get();
+ Message heading2 = INFO_DSCFG_HEADING_PROPERTY_VALUE.get();
+ builder.setColumnHeadings(heading1, heading2);
+ builder.setColumnWidths(null, 0);
+
+ // Create an option for editing/viewing each property.
+ for (PropertyDefinition<?> pd : c) {
+ // Determine whether this property should be modifiable.
+ boolean isReadOnly = false;
+
+ if (pd.hasOption(PropertyOption.MONITORING)) {
+ isReadOnly = true;
+ }
+
+ if (!isCreate && pd.hasOption(PropertyOption.READ_ONLY)) {
+ isReadOnly = true;
+ }
+
+ // Create the appropriate property action.
+ MenuCallback<Boolean> callback;
+ if (pd.hasOption(PropertyOption.MULTI_VALUED)) {
+ if (isReadOnly) {
+ callback = new ReadOnlyPropertyViewer(mo, pd);
+ } else {
+ callback = new MultiValuedPropertyEditor(mo, pd);
+ }
+ } else {
+ if (isReadOnly) {
+ callback = new ReadOnlyPropertyViewer(mo, pd);
+ } else {
+ callback = new SingleValuedPropertyEditor(mo, pd);
+ }
+ }
+
+ // Create the numeric option.
+ Message values = getPropertyValues(pd, mo);
+ builder.addNumberedOption(Message.raw("%s", pd.getName()), callback,
+ values);
+ }
+
+ // Add a help option which displays a summary of the managed
+ // object's definition.
+ HelpCallback helpCallback = new ComponentHelpCallback(mo, c);
+ builder.addHelpOption(helpCallback);
+
+ // Add an option to apply the changes.
+ if (isCreate) {
+ builder.addCharOption(INFO_EDITOR_OPTION_FINISH_KEY.get(),
+ INFO_EDITOR_OPTION_FINISH_CREATE_COMPONENT.get(ufn), MenuResult
+ .success(true));
+ } else {
+ builder.addCharOption(INFO_EDITOR_OPTION_FINISH_KEY.get(),
+ INFO_EDITOR_OPTION_FINISH_MODIFY_COMPONENT.get(ufn), MenuResult
+ .success(true));
+ }
+
+ builder.setDefault(INFO_EDITOR_OPTION_FINISH_KEY.get(), MenuResult
+ .success(true));
+
+ // Add options for canceling and quitting.
+ if (app.isMenuDrivenMode()) {
+ builder.addCancelOption(false);
+ }
+ builder.addQuitOption();
+
+ // Run the menu - success indicates that any changes should be
+ // committed.
+ app.println();
+ app.println();
+ Menu<Boolean> menu = builder.toMenu();
+ MenuResult<Boolean> result = menu.run();
+
+ if (result.isSuccess()) {
+ if (result.getValue()) {
+ return MenuResult.<Void>success();
+ }
+ } else if (result.isCancel()) {
+ return MenuResult.cancel();
+ } else {
+ return MenuResult.quit();
+ }
+ }
+ }
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/PropertyValuePrinter.java b/opends/src/server/org/opends/server/tools/dsconfig/PropertyValuePrinter.java
index 9a080e3..35023d8 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/PropertyValuePrinter.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/PropertyValuePrinter.java
@@ -29,7 +29,12 @@
import java.text.NumberFormat;
+import org.opends.messages.Message;
+import org.opends.messages.MessageBuilder;
+import static org.opends.messages.DSConfigMessages.*;
+
+import org.opends.server.admin.BooleanPropertyDefinition;
import org.opends.server.admin.DurationPropertyDefinition;
import org.opends.server.admin.DurationUnit;
import org.opends.server.admin.PropertyDefinition;
@@ -49,7 +54,7 @@
* Perform property type specific print formatting.
*/
private static class MyPropertyValueVisitor extends
- PropertyValueVisitor<String, Void> {
+ PropertyValueVisitor<Message, Void> {
// The requested size unit (null if the property's unit should be
// used).
@@ -91,31 +96,13 @@
* {@inheritDoc}
*/
@Override
- public String visitDuration(DurationPropertyDefinition d, Long v, Void p) {
- if (d.getUpperLimit() == null && (v < 0 || v == Long.MAX_VALUE)) {
- return "unlimited";
+ public Message visitBoolean(BooleanPropertyDefinition d, Boolean v,
+ Void p) {
+ if (v == false) {
+ return INFO_VALUE_FALSE.get();
+ } else {
+ return INFO_VALUE_TRUE.get();
}
-
- 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();
}
@@ -124,9 +111,42 @@
* {@inheritDoc}
*/
@Override
- public String visitSize(SizePropertyDefinition d, Long v, Void p) {
+ public Message visitDuration(DurationPropertyDefinition d, Long v, Void p) {
+ if (d.getUpperLimit() == null && (v < 0 || v == Long.MAX_VALUE)) {
+ return INFO_VALUE_UNLIMITED.get();
+ }
+
+ MessageBuilder builder = new MessageBuilder();
+ long ms = d.getBaseUnit().toMilliSeconds(v);
+
+ if (timeUnit == null && !isScriptFriendly && ms != 0) {
+ // Use human-readable string representation by default.
+ builder.append(DurationUnit.toString(ms));
+ } else {
+ // Use either the specified unit or the property definition's
+ // base unit.
+ DurationUnit unit = timeUnit;
+ if (unit == null) {
+ unit = d.getBaseUnit();
+ }
+
+ builder.append(numberFormat.format(unit.fromMilliSeconds(ms)));
+ builder.append(' ');
+ builder.append(unit.getShortName());
+ }
+
+ return builder.toMessage();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Message visitSize(SizePropertyDefinition d, Long v, Void p) {
if (d.isAllowUnlimited() && v < 0) {
- return "unlimited";
+ return INFO_VALUE_UNLIMITED.get();
}
SizeUnit unit = sizeUnit;
@@ -139,12 +159,12 @@
}
}
- StringBuilder builder = new StringBuilder();
+ MessageBuilder builder = new MessageBuilder();
builder.append(numberFormat.format(unit.fromBytes(v)));
builder.append(' ');
builder.append(unit.getShortName());
- return builder.toString();
+ return builder.toMessage();
}
@@ -153,18 +173,18 @@
* {@inheritDoc}
*/
@Override
- public <T> String visitUnknown(PropertyDefinition<T> d, T v, Void p) {
+ public <T> Message visitUnknown(PropertyDefinition<T> d, T v, Void p) {
// For all other property definition types the default encoding
// will do.
String s = d.encodeValue(v);
if (isScriptFriendly) {
- return s;
+ return Message.raw("%s", s);
} else if (s.trim().length() == 0 || s.contains(",")) {
// Quote empty strings or strings containing commas
// non-scripting mode.
- return "\"" + s + "\"";
+ return Message.raw("\"%s\"", s);
} else {
- return s;
+ return Message.raw("%s", s);
}
}
@@ -210,7 +230,7 @@
* encoded according to the rules of this property value
* printer.
*/
- public <T> String print(PropertyDefinition<T> pd, T value) {
+ public <T> Message print(PropertyDefinition<T> pd, T value) {
return pd.accept(pimpl, value, null);
}
}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/PropertyValueReader.java b/opends/src/server/org/opends/server/tools/dsconfig/PropertyValueReader.java
deleted file mode 100644
index 2607fb8..0000000
--- a/opends/src/server/org/opends/server/tools/dsconfig/PropertyValueReader.java
+++ /dev/null
@@ -1,630 +0,0 @@
-/*
- * 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.messages.Message;
-import org.opends.messages.MessageBuilder;
-
-
-import static org.opends.messages.ToolMessages.*;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.SortedMap;
-import java.util.SortedSet;
-import java.util.TreeMap;
-
-import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
-import org.opends.server.admin.AliasDefaultBehaviorProvider;
-import org.opends.server.admin.BooleanPropertyDefinition;
-import org.opends.server.admin.DefaultBehaviorProviderVisitor;
-import org.opends.server.admin.DefinedDefaultBehaviorProvider;
-import org.opends.server.admin.EnumPropertyDefinition;
-import org.opends.server.admin.IllegalPropertyValueStringException;
-import org.opends.server.admin.PropertyDefinition;
-import org.opends.server.admin.PropertyDefinitionVisitor;
-import org.opends.server.admin.PropertyOption;
-import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider;
-import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
-import org.opends.server.admin.UnknownPropertyDefinitionException;
-import org.opends.server.admin.client.ManagedObject;
-import org.opends.server.tools.ClientException;
-import org.opends.server.util.args.ArgumentException;
-import org.opends.server.util.table.TableBuilder;
-import org.opends.server.util.table.TextTablePrinter;
-
-
-
-/**
- * A class responsible for interactively retrieving property values
- * from the console.
- */
-final class PropertyValueReader {
-
- /**
- * A help call-back which displays help on a property.
- */
- private static final class PropertyHelpCallback implements HelpCallback {
-
- // The managed object.
- private final ManagedObject<?> mo;
-
- // The property definition.
- private final PropertyDefinition<?> pd;
-
-
-
- /**
- * Creates a new property help call-back.
- *
- * @param mo
- * The managed object.
- * @param pd
- * The property definition.
- */
- public PropertyHelpCallback(ManagedObject<?> mo, PropertyDefinition<?> pd) {
- this.mo = mo;
- this.pd = pd;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public void display(ConsoleApplication app) {
- app.println();
- HelpSubCommandHandler.displayVerboseSingleProperty(mo
- .getManagedObjectDefinition(), pd.getName(), app.getErrorStream());
- }
-
- }
-
-
-
- /**
- * A menu call-back used for editing property values.
- */
- private interface MenuCallback {
-
- /**
- * Invoke the menu call-back.
- *
- * @param mo
- * The managed object.
- * @param pd
- * The property definition to be modified.
- * @param <T>
- * The type of property to be edited.
- * @throws ArgumentException
- * If the user input could not be retrieved for some
- * reason.
- */
- <T> void invoke(ManagedObject<?> mo, PropertyDefinition<T> pd)
- throws ArgumentException;
- }
-
-
-
- /**
- * A menu call-back for adding values to a property.
- */
- private final class AddValueMenuCallback implements MenuCallback {
-
- /**
- * {@inheritDoc}
- */
- public <T> void invoke(ManagedObject<?> mo, PropertyDefinition<T> pd)
- throws ArgumentException {
- // TODO: display error if the value already exists.
-
- // TODO: for enumerations, only display the values which are not
- // already assigned.
- T value = read(mo, pd);
- SortedSet<T> values = mo.getPropertyValues(pd);
- values.add(value);
- mo.setPropertyValues(pd, values);
- }
-
- }
-
-
-
- /**
- * A menu call-back for removing values from a property.
- */
- private final class RemoveValueMenuCallback implements MenuCallback {
-
- /**
- * {@inheritDoc}
- */
- public <T> void invoke(ManagedObject<?> mo, PropertyDefinition<T> pd)
- throws ArgumentException {
- PropertyValuePrinter printer =
- new PropertyValuePrinter(null, null, false);
- SortedSet<T> values = mo.getPropertyValues(pd);
-
- List<Message> descriptions = new ArrayList<Message>(values.size());
- List<T> lvalues = new ArrayList<T>(values.size());
-
- for (T value : values) {
- descriptions.add(Message.raw(printer.print(pd, value)));
- lvalues.add(value);
- }
-
- Message promptMsg =
- INFO_DSCFG_VALUE_READER_PROMPT_REMOVE.get(pd.getName());
- T value = app.readChoice(promptMsg, descriptions, lvalues, null);
- values.remove(value);
- mo.setPropertyValues(pd, values);
- }
-
- }
-
-
-
- /**
- * A menu call-back for resetting a property back to its defaults.
- */
- private final class ResetValueMenuCallback implements MenuCallback {
-
- /**
- * {@inheritDoc}
- */
- public <T> void invoke(ManagedObject<?> mo, PropertyDefinition<T> pd)
- throws ArgumentException {
- mo.setPropertyValue(pd, null);
- }
-
- }
-
-
-
- /**
- * A menu call-back for setting a single-valued property.
- */
- private final class SetValueMenuCallback implements MenuCallback {
-
- /**
- * {@inheritDoc}
- */
- public <T> void invoke(ManagedObject<?> mo, PropertyDefinition<T> pd)
- throws ArgumentException {
- T value = read(mo, pd);
- mo.setPropertyValue(pd, value);
- }
-
- }
-
-
-
- /**
- * The reader implementation.
- */
- private final class Visitor extends PropertyDefinitionVisitor<String, Void> {
-
- // Any argument exception that was caught during processing.
- private ArgumentException ae = null;
-
-
-
- /**
- * Read a value from the console for the provided property
- * definition.
- *
- * @param pd
- * The property definition.
- * @return Returns the string value.
- * @throws ArgumentException
- * If the user input could not be retrieved for some
- * reason.
- */
- public String read(PropertyDefinition<?> pd) throws ArgumentException {
- String result = pd.accept(this, null);
-
- if (result != null) {
- return result;
- } else if (ae != null) {
- throw ae;
- } else {
- throw new IllegalStateException(
- "No result and no ArgumentException caught");
- }
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String visitBoolean(BooleanPropertyDefinition d, Void p) {
- List<String> values = Arrays.asList(new String[] {
- "false", "true"
- });
- List<Message> descriptions = Arrays.asList(new Message[] {
- Message.raw("false"), Message.raw("true")
- });
- try {
- Message promptMsg = INFO_DSCFG_VALUE_READER_PROMPT_SELECT_VALUE.get(
- d.getName());
- return app.readChoice(promptMsg, descriptions, values, null);
- } catch (ArgumentException e) {
- ae = e;
- return null;
- }
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public <E extends Enum<E>> String visitEnum(EnumPropertyDefinition<E> d,
- Void p) {
- SortedMap<String, String> map = new TreeMap<String, String>();
- for (E value : EnumSet.allOf(d.getEnumClass())) {
- String s = String.format("%s : %s", value.toString(), d
- .getValueSynopsis(value));
- map.put(value.toString(), s);
- }
-
- List<String> descStrings = new ArrayList<String>(map.values());
- List<Message> descriptions = new ArrayList<Message>(descStrings.size());
- for (String s : descStrings) {
- descriptions.add(Message.raw(s));
- }
-
- List<String> values = new ArrayList<String>(map.keySet());
- try {
- Message promptMsg =
- INFO_DSCFG_VALUE_READER_PROMPT_SELECT_VALUE.get(d.getName());
- return app.readChoice(promptMsg, descriptions, values, null);
- } catch (ArgumentException e) {
- ae = e;
- return null;
- }
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String visitUnknown(PropertyDefinition<?> d, Void p)
- throws UnknownPropertyDefinitionException {
- try {
- Message promptMsg = INFO_DSCFG_VALUE_READER_PROMPT_ENTER_VALUE.get(
- d.getName());
- return app.readLineOfInput(promptMsg);
- } catch (ArgumentException e) {
- ae = e;
- return null;
- }
- }
-
- }
-
- // The application console.
- private final ConsoleApplication app;
-
-
-
- /**
- * Create a new property value reader which will read from the
- * provider application console.
- *
- * @param app
- * The application console.
- */
- public PropertyValueReader(ConsoleApplication app) {
- this.app = app;
- }
-
-
-
- /**
- * Asks the user to input a single value for the provided property
- * definition. The value will be validated according to the
- * constraints of the property definition and its decoded value
- * returned.
- *
- * @param <T>
- * The underlying type of the property definition.
- * @param mo
- * The managed object.
- * @param pd
- * The property definition.
- * @return Returns the validated string value.
- * @throws ArgumentException
- * If the user input could not be retrieved for some
- * reason.
- */
- public <T> T read(ManagedObject<?> mo, PropertyDefinition<T> pd)
- throws ArgumentException {
- while (true) {
- app.println();
- String value = pd.accept(new Visitor(), null);
-
- try {
- return pd.decodeValue(value);
- } catch (IllegalPropertyValueStringException e) {
- app.println();
- app.printMessage(Message.raw(
- ArgumentExceptionFactory.adaptPropertyException(e,
- mo.getManagedObjectDefinition()).getMessage()));
- }
- }
- }
-
-
-
- /**
- * Edit the properties of a managed object. Only the properties
- * listed in the provided collection will be accessible to the
- * client. It is up to the caller to ensure that the list of
- * properties does not include read-only, monitoring, hidden, or
- * advanced properties as appropriate.
- *
- * @param mo
- * The managed object.
- * @param c
- * The collection of properties which can be edited.
- * @throws ArgumentException
- * If the user input could not be retrieved for some
- * reason.
- */
- public void readAll(ManagedObject<?> mo, Collection<PropertyDefinition<?>> c)
- throws ArgumentException {
- // Get values for this missing mandatory property.
- for (PropertyDefinition<?> pd : c) {
- if (pd.hasOption(PropertyOption.MANDATORY)) {
- if (mo.getPropertyValues(pd).isEmpty()) {
- editProperty(mo, pd);
- }
- }
- }
-
- // Now let users modify remaining properties.
- boolean isFinished = false;
- PropertyValuePrinter valuePrinter = new PropertyValuePrinter(null, null,
- false);
- while (!isFinished) {
- // Display a menu allowing users to edit individual options.
- TableBuilder builder = new TableBuilder();
- builder.appendHeading();
- builder.appendHeading(INFO_DSCFG_HEADING_PROPERTY_NAME.get());
- builder.appendHeading(INFO_DSCFG_HEADING_PROPERTY_VALUE.get());
-
- int i = 0;
- List<PropertyDefinition<?>> pl = new ArrayList<PropertyDefinition<?>>(c);
- for (PropertyDefinition<?> pd : pl) {
- builder.startRow();
- builder.appendCell("[" + i + "]");
- builder.appendCell(pd.getName());
-
- Message values = getPropertyValuesAsString(mo, pd, valuePrinter);
- builder.appendCell(values);
- i++;
- }
-
- builder.startRow();
- builder.startRow();
- builder.appendCell("[" + i + "]");
- builder.appendCell(INFO_DSCFG_VALUE_READER_MENU_CONTINUE.get());
-
- // Display the menu.
- app.println();
- app.printMessage(INFO_DSCFG_VALUE_READER_MENU_TITLE.get(i));
- app.println();
-
- TextTablePrinter printer = new TextTablePrinter(app.getErrorStream());
- printer.setColumnWidth(2, 0);
- builder.print(printer);
-
- // Get the user input.
- final int size = i;
- Message promptMsg = INFO_DSCFG_GENERAL_CHOICE_PROMPT_NOHELP.get(i);
- ValidationCallback<Integer> validator =
- new ValidationCallback<Integer>() {
-
- public Integer validate(ConsoleApplication app, String input) {
- String ninput = input.trim();
-
- try {
- int j = Integer.parseInt(ninput);
- if (j < 1 || j > size) {
- throw new NumberFormatException();
- }
- return j;
- } catch (NumberFormatException e) {
- app.println();
- Message errMsg = ERR_DSCFG_ERROR_GENERAL_CHOICE.get(size);
- app.printMessage(errMsg);
- return null;
- }
- }
- };
-
- // Get the choice.
- int choice;
- try {
- choice = app.readValidatedInput(promptMsg, validator);
- } catch (ClientException e) {
- // Should never happen.
- throw new RuntimeException(e);
- }
-
- if (choice == size) {
- isFinished = true;
- } else {
- editProperty(mo, pl.get(choice));
- }
- }
- }
-
-
-
- // Interactively edit a property.
- private <T> void editProperty(ManagedObject<?> mo, PropertyDefinition<T> pd)
- throws ArgumentException {
- // If the property is mandatory then make sure we prompt for an
- // initial value.
- if (pd.hasOption(PropertyOption.MANDATORY)) {
- if (mo.getPropertyValues(pd).isEmpty()) {
- app.println();
- Message promptMsg = INFO_DSCFG_VALUE_READER_PROMPT_MANDATORY.get(
- pd.getName());
- app.printMessage(promptMsg);
- T value = read(mo, pd);
- mo.setPropertyValue(pd, value);
- }
- }
-
- boolean isFinished = false;
- while (!isFinished) {
- // Construct a list of menu options and their call-backs.
- List<Message> descriptions = new ArrayList<Message>();
- List<MenuCallback> callbacks = new ArrayList<MenuCallback>();
-
- if (pd.hasOption(PropertyOption.MULTI_VALUED)) {
- descriptions.add(INFO_DSCFG_VALUE_READER_MENU_ADD.get());
- callbacks.add(new AddValueMenuCallback());
-
- if (!mo.getPropertyValues(pd).isEmpty()) {
- descriptions.add(INFO_DSCFG_VALUE_READER_MENU_REMOVE.get());
- callbacks.add(new RemoveValueMenuCallback());
- }
- } else {
- descriptions.add(INFO_DSCFG_VALUE_READER_MENU_SET.get());
- callbacks.add(new SetValueMenuCallback());
- }
-
- if (!pd.hasOption(PropertyOption.MANDATORY)
- || !(pd.getDefaultBehaviorProvider()
- instanceof UndefinedDefaultBehaviorProvider)) {
- descriptions.add(INFO_DSCFG_VALUE_READER_MENU_RESET.get());
- callbacks.add(new ResetValueMenuCallback());
- }
-
- descriptions.add(INFO_DSCFG_VALUE_READER_MENU_CONTINUE.get());
- callbacks.add(null);
-
- // FIXME: display current values of the property.
- Message promptMsg = INFO_DSCFG_VALUE_READER_PROMPT_MODIFY_MENU.get(
- pd.getName());
- MenuCallback callback = app.readChoice(promptMsg, descriptions,
- callbacks, new PropertyHelpCallback(mo, pd));
-
- if (callback != null) {
- callback.invoke(mo, pd);
- } else {
- isFinished = true;
- }
- }
- }
-
-
-
- // Display the set of values associated with a property.
- private <T> Message getPropertyValuesAsString(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, Message, Void> visitor =
- new DefaultBehaviorProviderVisitor<T, Message, Void>() {
-
- public Message visitAbsoluteInherited(
- AbsoluteInheritedDefaultBehaviorProvider<T> d, Void p) {
- // Should not happen - inherited default values are
- // displayed as normal values.
- throw new IllegalStateException();
- }
-
-
-
- public Message visitAlias(AliasDefaultBehaviorProvider<T> d, Void p) {
- if (app.isVerbose()) {
- return d.getSynopsis();
- } else {
- return null;
- }
- }
-
-
-
- public Message visitDefined(
- DefinedDefaultBehaviorProvider<T> d, Void p) {
- // Should not happen - real default values are displayed as
- // normal values.
- throw new IllegalStateException();
- }
-
-
-
- public Message visitRelativeInherited(
- RelativeInheritedDefaultBehaviorProvider<T> d, Void p) {
- // Should not happen - inherited default values are
- // displayed as normal values.
- throw new IllegalStateException();
- }
-
-
-
- public Message visitUndefined(UndefinedDefaultBehaviorProvider<T> d,
- Void p) {
- return null;
- }
- };
-
- Message content = pd.getDefaultBehaviorProvider().accept(visitor, null);
- if (content == null) {
- return Message.raw("-");
- } else {
- return content;
- }
- } else {
- MessageBuilder sb = new MessageBuilder();
- boolean isFirst = true;
- for (T value : values) {
- if (!isFirst) {
- sb.append(", ");
- }
- sb.append(valuePrinter.print(pd, value));
- isFirst = false;
- }
-
- return sb.toMessage();
- }
- }
-}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java
index a9d9afc..1b9b5c0 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java
@@ -25,11 +25,10 @@
* Portions Copyright 2007 Sun Microsystems, Inc.
*/
package org.opends.server.tools.dsconfig;
-import org.opends.messages.Message;
-import static org.opends.messages.ToolMessages.*;
+import static org.opends.messages.DSConfigMessages.*;
import java.util.HashMap;
import java.util.List;
@@ -38,6 +37,7 @@
import java.util.SortedSet;
import java.util.TreeSet;
+import org.opends.messages.Message;
import org.opends.server.admin.DefinitionDecodingException;
import org.opends.server.admin.IllegalPropertyValueStringException;
import org.opends.server.admin.InstantiableRelationDefinition;
@@ -57,6 +57,7 @@
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;
@@ -65,6 +66,9 @@
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.cli.CLIException;
+import org.opends.server.util.cli.ConsoleApplication;
+import org.opends.server.util.cli.MenuResult;
@@ -143,8 +147,6 @@
* Creates a new set-xxx-prop sub-command for an instantiable
* relation.
*
- * @param app
- * The console application.
* @param parser
* The sub-command argument parser.
* @param path
@@ -155,10 +157,10 @@
* @throws ArgumentException
* If the sub-command could not be created successfully.
*/
- public static SetPropSubCommandHandler create(ConsoleApplication app,
+ public static SetPropSubCommandHandler create(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
InstantiableRelationDefinition<?, ?> r) throws ArgumentException {
- return new SetPropSubCommandHandler(app, parser, path.child(r, "DUMMY"), r);
+ return new SetPropSubCommandHandler(parser, path.child(r, "DUMMY"), r);
}
@@ -166,8 +168,6 @@
/**
* Creates a new set-xxx-prop sub-command for an optional relation.
*
- * @param app
- * The console application.
* @param parser
* The sub-command argument parser.
* @param path
@@ -178,10 +178,10 @@
* @throws ArgumentException
* If the sub-command could not be created successfully.
*/
- public static SetPropSubCommandHandler create(ConsoleApplication app,
+ public static SetPropSubCommandHandler create(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
OptionalRelationDefinition<?, ?> r) throws ArgumentException {
- return new SetPropSubCommandHandler(app, parser, path.child(r), r);
+ return new SetPropSubCommandHandler(parser, path.child(r), r);
}
@@ -189,8 +189,6 @@
/**
* Creates a new set-xxx-prop sub-command for a singleton relation.
*
- * @param app
- * The console application.
* @param parser
* The sub-command argument parser.
* @param path
@@ -201,10 +199,10 @@
* @throws ArgumentException
* If the sub-command could not be created successfully.
*/
- public static SetPropSubCommandHandler create(ConsoleApplication app,
+ public static SetPropSubCommandHandler create(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
SingletonRelationDefinition<?, ?> r) throws ArgumentException {
- return new SetPropSubCommandHandler(app, parser, path.child(r), r);
+ return new SetPropSubCommandHandler(parser, path.child(r), r);
}
// The sub-commands naming arguments.
@@ -235,17 +233,15 @@
// Private constructor.
- private SetPropSubCommandHandler(ConsoleApplication app,
+ private SetPropSubCommandHandler(
SubCommandArgumentParser parser, ManagedObjectPath<?, ?> path,
RelationDefinition<?, ?> r) throws ArgumentException {
- super(app);
-
this.path = path;
// Create the sub-command.
String name = "set-" + r.getName() + "-prop";
- Message description = INFO_DSCFG_DESCRIPTION_SUBCMD_SETPROP.get(
- r.getChildDefinition().getUserFriendlyName());
+ Message description = INFO_DSCFG_DESCRIPTION_SUBCMD_SETPROP.get(r
+ .getChildDefinition().getUserFriendlyName());
this.subCommand = new SubCommand(parser, name, false, 0, 0, null,
description);
@@ -287,6 +283,19 @@
/**
+ * Gets the relation definition associated with the type of
+ * component that this sub-command handles.
+ *
+ * @return Returns the relation definition associated with the type
+ * of component that this sub-command handles.
+ */
+ public RelationDefinition<?, ?> getRelationDefinition() {
+ return path.getRelationDefinition();
+ }
+
+
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -301,44 +310,52 @@
*/
@SuppressWarnings("unchecked")
@Override
- public int run()
- throws ArgumentException, ClientException {
+ public MenuResult<Integer> run(ConsoleApplication app,
+ ManagementContextFactory factory) throws ArgumentException,
+ ClientException, CLIException {
// Get the naming argument values.
- List<String> names = getNamingArgValues(namingArgs);
+ List<String> names = getNamingArgValues(app, namingArgs);
- ManagedObject<?> child;
+ // Get the targeted managed object.
+ Message ufn = path.getRelationDefinition().getUserFriendlyName();
+ ManagementContext context = factory.getManagementContext(app);
+ MenuResult<ManagedObject<?>> result;
try {
- child = getManagedObject(path, names);
+ result = getManagedObject(app, context, path, names);
} catch (AuthorizationException e) {
- Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_MODIFY_AUTHZ.get(ufn);
- throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
- msg);
+ throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS, msg);
} catch (DefinitionDecodingException e) {
- Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_CHILD_DDE.get(ufn, ufn, ufn);
throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
} catch (ManagedObjectDecodingException e) {
// FIXME: should not abort here. Instead, display the errors (if
// verbose) and apply the changes to the partial managed object.
- Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_CHILD_MODE.get(ufn);
throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
} catch (CommunicationException e) {
- Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_MODIFY_CE.get(ufn, e.getMessage());
throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
} catch (ConcurrentModificationException e) {
- Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_MODIFY_CME.get(ufn);
- throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
- msg);
+ throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
} catch (ManagedObjectNotFoundException e) {
- Message ufn = path.getManagedObjectDefinition().getUserFriendlyName();
Message msg = ERR_DSCFG_ERROR_GET_CHILD_MONFE.get(ufn);
throw new ClientException(LDAPResultCode.NO_SUCH_OBJECT, msg);
}
+ if (result.isQuit()) {
+ if (!app.isMenuDrivenMode()) {
+ // User chose to quit.
+ Message msg = INFO_DSCFG_CONFIRM_MODIFY_FAIL.get(ufn);
+ app.printVerboseMessage(msg);
+ }
+ return MenuResult.quit();
+ } else if (result.isCancel()) {
+ return MenuResult.cancel();
+ }
+
+ ManagedObject<?> child = result.getValue();
ManagedObjectDefinition<?, ?> d = child.getManagedObjectDefinition();
Map<String, ModificationType> lastModTypes =
new HashMap<String, ModificationType>();
@@ -442,8 +459,8 @@
}
} else {
lastModTypes.put(propertyName, ModificationType.REMOVE);
- modifyPropertyValues(child, pd, changes,
- ModificationType.REMOVE, value);
+ modifyPropertyValues(child, pd, changes, ModificationType.REMOVE,
+ value);
}
}
@@ -495,7 +512,7 @@
}
// Interactively set properties if applicable.
- if (getConsoleApplication().isInteractive()) {
+ if (app.isInteractive()) {
SortedSet<PropertyDefinition<?>> properties =
new TreeSet<PropertyDefinition<?>>();
@@ -504,14 +521,6 @@
continue;
}
- if (pd.hasOption(PropertyOption.READ_ONLY)) {
- continue;
- }
-
- if (pd.hasOption(PropertyOption.MONITORING)) {
- continue;
- }
-
if (!isAdvancedMode() && pd.hasOption(PropertyOption.ADVANCED)) {
continue;
}
@@ -519,54 +528,47 @@
properties.add(pd);
}
- PropertyValueReader reader =
- new PropertyValueReader(getConsoleApplication());
- reader.readAll(child, properties);
+ PropertyValueEditor editor = new PropertyValueEditor(app);
+ MenuResult<Void> result2 = editor.edit(child, properties, true);
+ if (result2.isQuit()) {
+ if (!app.isMenuDrivenMode()) {
+ // User chose to cancel any changes.
+ Message msg = INFO_DSCFG_CONFIRM_MODIFY_FAIL.get(ufn);
+ app.printVerboseMessage(msg);
+ }
+ return MenuResult.quit();
+ } else if (result2.isCancel()) {
+ return MenuResult.cancel();
+ }
}
try {
- // Confirm commit.
- Message prompt = INFO_DSCFG_CONFIRM_MODIFY.get(d.getUserFriendlyName());
- if (!getConsoleApplication().confirmAction(prompt)) {
- // Output failure message.
- Message msg =
- INFO_DSCFG_CONFIRM_MODIFY_FAIL.get(d.getUserFriendlyName());
- getConsoleApplication().printVerboseMessage(msg);
- return 1;
- }
-
child.commit();
// Output success message.
- Message msg =
- INFO_DSCFG_CONFIRM_MODIFY_SUCCESS.get(d.getUserFriendlyName());
- getConsoleApplication().printVerboseMessage(msg);
+ Message msg = INFO_DSCFG_CONFIRM_MODIFY_SUCCESS.get(ufn);
+ app.printVerboseMessage(msg);
} catch (MissingMandatoryPropertiesException e) {
throw ArgumentExceptionFactory.adaptMissingMandatoryPropertiesException(
e, d);
} catch (AuthorizationException e) {
- Message msg = ERR_DSCFG_ERROR_MODIFY_AUTHZ.get(d.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
- msg);
+ Message msg = ERR_DSCFG_ERROR_MODIFY_AUTHZ.get(ufn);
+ throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS, msg);
} catch (ConcurrentModificationException e) {
- Message msg = ERR_DSCFG_ERROR_MODIFY_CME.get(d.getUserFriendlyName());
- throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
- msg);
+ Message msg = ERR_DSCFG_ERROR_MODIFY_CME.get(ufn);
+ throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
} catch (OperationRejectedException e) {
- Message msg = ERR_DSCFG_ERROR_MODIFY_ORE.get(
- d.getUserFriendlyName(), e.getMessage());
- throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION,
- msg);
+ Message msg = ERR_DSCFG_ERROR_MODIFY_ORE.get(ufn, e.getMessage());
+ throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msg);
} catch (CommunicationException e) {
- Message msg = ERR_DSCFG_ERROR_MODIFY_CE.get(
- d.getUserFriendlyName(), e.getMessage());
+ Message msg = ERR_DSCFG_ERROR_MODIFY_CE.get(ufn, e.getMessage());
throw new ClientException(LDAPResultCode.OPERATIONS_ERROR, msg);
} catch (ManagedObjectAlreadyExistsException e) {
// Should never happen.
throw new IllegalStateException(e);
}
- return 0;
+ return MenuResult.success(0);
}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/SubCommandBuilder.java b/opends/src/server/org/opends/server/tools/dsconfig/SubCommandBuilder.java
deleted file mode 100644
index 665d789..0000000
--- a/opends/src/server/org/opends/server/tools/dsconfig/SubCommandBuilder.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * 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.RelationOption;
-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<?, ?>> {
-
- // The application.
- private final ConsoleApplication app;
-
- // 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(ConsoleApplication app, SubCommandArgumentParser parser) {
- this.app = app;
- 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(app, 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(app, parser, p, r));
- handlers.add(DeleteSubCommandHandler.create(app, parser, p, r));
- handlers.add(ListSubCommandHandler.create(app, parser, p, r));
- handlers.add(GetPropSubCommandHandler.create(app, parser, p, r));
- handlers.add(SetPropSubCommandHandler.create(app, 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(app, parser, p, r));
- handlers.add(DeleteSubCommandHandler.create(app, parser, p, r));
- handlers.add(ListSubCommandHandler.create(app, parser, p, r));
- handlers.add(GetPropSubCommandHandler.create(app, parser, p, r));
- handlers.add(SetPropSubCommandHandler.create(app, 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(app, parser, p, r));
- handlers.add(SetPropSubCommandHandler.create(app, 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()) {
- if (!r.hasOption(RelationOption.HIDDEN)) {
- 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 app
- * The console application.
- * @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(
- ConsoleApplication app, SubCommandArgumentParser parser)
- throws ArgumentException {
- Visitor v = new Visitor(app, 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
index 71ebdbd..61aff03 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java
@@ -25,11 +25,10 @@
* Portions Copyright 2007 Sun Microsystems, Inc.
*/
package org.opends.server.tools.dsconfig;
-import org.opends.messages.Message;
-import static org.opends.messages.ToolMessages.*;
+import static org.opends.messages.DSConfigMessages.*;
import java.io.PrintStream;
import java.util.ArrayList;
@@ -42,6 +41,7 @@
import java.util.List;
import java.util.Set;
+import org.opends.messages.Message;
import org.opends.server.admin.AbstractManagedObjectDefinition;
import org.opends.server.admin.Configuration;
import org.opends.server.admin.ConfigurationClient;
@@ -69,6 +69,11 @@
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.cli.CLIException;
+import org.opends.server.util.cli.ConsoleApplication;
+import org.opends.server.util.cli.Menu;
+import org.opends.server.util.cli.MenuBuilder;
+import org.opends.server.util.cli.MenuResult;
import org.opends.server.util.table.TabSeparatedTablePrinter;
import org.opends.server.util.table.TablePrinter;
@@ -77,7 +82,7 @@
/**
* An interface for sub-command implementations.
*/
-abstract class SubCommandHandler {
+abstract class SubCommandHandler implements Comparable<SubCommandHandler> {
/**
* A path serializer which is used to retrieve a managed object
@@ -85,9 +90,8 @@
*/
private class ManagedObjectFinder implements ManagedObjectPathSerializer {
- // Any argument exception that was caught when attempting to find
- // the managed object.
- private ArgumentException ae;
+ // The console application.
+ private ConsoleApplication app;
// The index of the next path argument to be retrieved.
private int argIndex;
@@ -99,23 +103,23 @@
private CommunicationException ce;
+ // Any CLI exception that was caught when attempting to find
+ // the managed object.
+ private CLIException clie;
+
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;
+ // The current result.
+ private MenuResult<ManagedObject<?>> result;
+
/**
@@ -125,7 +129,7 @@
void appendManagedObjectPathElement(
InstantiableRelationDefinition<? super C, ? super S> r,
AbstractManagedObjectDefinition<C, S> d, String name) {
- if (!gotException) {
+ if (result.isSuccess()) {
// We should ignore the "template" name here and use a path
// argument.
String childName = args.get(argIndex++);
@@ -135,50 +139,61 @@
// the user choose.
if (childName == null) {
try {
- childName = readChildName(managedObject, r, d);
- } catch (ArgumentException e) {
- ae = e;
- gotException = true;
+ MenuResult<String> sresult = readChildName(app,
+ result.getValue(), r, d);
+
+ if (sresult.isCancel()) {
+ result = MenuResult.cancel();
+ return;
+ } else if (sresult.isQuit()) {
+ result = MenuResult.quit();
+ return;
+ } else {
+ childName = sresult.getValue();
+ }
+ } catch (CLIException e) {
+ clie = e;
+ result = MenuResult.quit();
return;
}
} else if (childName.trim().length() == 0) {
IllegalManagedObjectNameException e =
new IllegalManagedObjectNameException(childName);
- ae = ArgumentExceptionFactory
+ clie = ArgumentExceptionFactory
.adaptIllegalManagedObjectNameException(e, d);
- gotException = true;
+ result = MenuResult.quit();
return;
}
- ManagedObject<?> child = managedObject.getChild(r, childName);
+ ManagedObject<?> child = result.getValue().getChild(r, childName);
// Check that child is a sub-type of the specified
// definition.
if (!child.getManagedObjectDefinition().isChildOf(d)) {
- ae = ArgumentExceptionFactory.wrongManagedObjectType(r, child
+ clie = ArgumentExceptionFactory.wrongManagedObjectType(r, child
.getManagedObjectDefinition());
- gotException = true;
+ result = MenuResult.quit();
} else {
- managedObject = child;
+ result = MenuResult.<ManagedObject<?>>success(child);
}
} catch (DefinitionDecodingException e) {
dde = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (ManagedObjectDecodingException e) {
mode = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (AuthorizationException e) {
authze = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (ManagedObjectNotFoundException e) {
monfe = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (ConcurrentModificationException e) {
cme = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (CommunicationException e) {
ce = e;
- gotException = true;
+ result = MenuResult.quit();
}
}
}
@@ -192,37 +207,37 @@
void appendManagedObjectPathElement(
OptionalRelationDefinition<? super C, ? super S> r,
AbstractManagedObjectDefinition<C, S> d) {
- if (!gotException) {
+ if (result.isSuccess()) {
try {
- ManagedObject<?> child = managedObject.getChild(r);
+ ManagedObject<?> child = result.getValue().getChild(r);
// Check that child is a sub-type of the specified
// definition.
if (!child.getManagedObjectDefinition().isChildOf(d)) {
- ae = ArgumentExceptionFactory.wrongManagedObjectType(r, child
+ clie = ArgumentExceptionFactory.wrongManagedObjectType(r, child
.getManagedObjectDefinition());
- gotException = true;
+ result = MenuResult.quit();
} else {
- managedObject = child;
+ result = MenuResult.<ManagedObject<?>>success(child);
}
} catch (DefinitionDecodingException e) {
dde = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (ManagedObjectDecodingException e) {
mode = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (AuthorizationException e) {
authze = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (ManagedObjectNotFoundException e) {
monfe = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (ConcurrentModificationException e) {
cme = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (CommunicationException e) {
ce = e;
- gotException = true;
+ result = MenuResult.quit();
}
}
}
@@ -236,37 +251,37 @@
void appendManagedObjectPathElement(
SingletonRelationDefinition<? super C, ? super S> r,
AbstractManagedObjectDefinition<C, S> d) {
- if (!gotException) {
+ if (result.isSuccess()) {
try {
- ManagedObject<?> child = managedObject.getChild(r);
+ ManagedObject<?> child = result.getValue().getChild(r);
// Check that child is a sub-type of the specified
// definition.
if (!child.getManagedObjectDefinition().isChildOf(d)) {
- ae = ArgumentExceptionFactory.wrongManagedObjectType(r, child
+ clie = ArgumentExceptionFactory.wrongManagedObjectType(r, child
.getManagedObjectDefinition());
- gotException = true;
+ result = MenuResult.quit();
} else {
- managedObject = child;
+ result = MenuResult.<ManagedObject<?>>success(child);
}
} catch (DefinitionDecodingException e) {
dde = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (ManagedObjectDecodingException e) {
mode = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (AuthorizationException e) {
authze = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (ManagedObjectNotFoundException e) {
monfe = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (ConcurrentModificationException e) {
cme = e;
- gotException = true;
+ result = MenuResult.quit();
} catch (CommunicationException e) {
ce = e;
- gotException = true;
+ result = MenuResult.quit();
}
}
}
@@ -276,14 +291,20 @@
/**
* Finds the named managed object.
*
+ * @param app
+ * The console application.
* @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
+ * @return Returns a {@link MenuResult#success()} containing the
+ * managed object referenced by the provided managed
+ * object path, or {@link MenuResult#quit()}, or
+ * {@link MenuResult#cancel()}, if the sub-command was
+ * run interactively and the user chose to quit or cancel.
+ * @throws CLIException
* If one of the naming arguments referenced a managed
* object of the wrong type.
* @throws DefinitionDecodingException
@@ -306,18 +327,19 @@
* 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,
+ public MenuResult<ManagedObject<?>> find(ConsoleApplication app,
+ ManagementContext context, ManagedObjectPath<?, ?> path,
+ List<String> args) throws CLIException, CommunicationException,
AuthorizationException, ConcurrentModificationException,
DefinitionDecodingException, ManagedObjectDecodingException,
ManagedObjectNotFoundException {
- this.managedObject = context.getRootConfigurationManagedObject();
+ this.result = MenuResult.<ManagedObject<?>> success(context
+ .getRootConfigurationManagedObject());
+ this.app = app;
this.args = args;
this.argIndex = 0;
- this.gotException = false;
- this.ae = null;
+ this.clie = null;
this.authze = null;
this.ce = null;
this.cme = null;
@@ -327,8 +349,10 @@
path.serialize(this);
- if (ae != null) {
- throw ae;
+ if (result.isSuccess()) {
+ return result;
+ } else if (clie != null) {
+ throw clie;
} else if (authze != null) {
throw authze;
} else if (ce != null) {
@@ -342,7 +366,8 @@
} else if (monfe != null) {
throw monfe;
} else {
- return managedObject;
+ // User requested termination interactively.
+ return result;
}
}
}
@@ -500,6 +525,12 @@
}
/**
+ * The threshold above which choice menus should be displayed in
+ * multiple columns.
+ */
+ public static final int MULTI_COLUMN_THRESHOLD = 8;
+
+ /**
* The value for the long option advanced.
*/
private static final String OPTION_DSCFG_LONG_ADVANCED = "advanced";
@@ -552,9 +583,6 @@
// The argument which should be used to request advanced mode.
private BooleanArgument advancedModeArgument;
- // The application instance.
- private final ConsoleApplication app;
-
// The argument which should be used to specify zero or more
// property names.
private StringArgument propertyArgument;
@@ -575,12 +603,41 @@
/**
* Create a new sub-command handler.
- *
- * @param app
- * The application instance.
*/
- protected SubCommandHandler(ConsoleApplication app) {
- this.app = app;
+ protected SubCommandHandler() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public final int compareTo(SubCommandHandler o) {
+ String s1 = getSubCommand().getName();
+ String s2 = o.getSubCommand().getName();
+
+ return s1.compareTo(s2);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ } else if (obj instanceof SubCommandHandler) {
+ SubCommandHandler other = (SubCommandHandler) obj;
+
+ String s1 = getSubCommand().getName();
+ String s2 = other.getSubCommand().getName();
+ return s1.equals(s2);
+ } else {
+ return false;
+ }
}
@@ -607,17 +664,38 @@
/**
+ * {@inheritDoc}
+ */
+ @Override
+ public final int hashCode() {
+ return getSubCommand().getName().hashCode();
+ }
+
+
+
+ /**
* Run this sub-command handler.
*
- * @return Returns zero if the sub-command completed successfully or
- * non-zero if it did not.
+ * @param app
+ * The console application.
+ * @param factory
+ * The management context factory.
+ * @return Returns a {@link MenuResult#success()} containing zero if
+ * the sub-command completed successfully or non-zero if it
+ * did not, or {@link MenuResult#quit()}, or
+ * {@link MenuResult#cancel()}, if the sub-command was run
+ * interactively and the user chose to quit or cancel.
* @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.
+ * @throws CLIException
+ * If a CLI exception occurred.
*/
- public abstract int run() throws ArgumentException, ClientException;
+ public abstract MenuResult<Integer> run(ConsoleApplication app,
+ ManagementContextFactory factory) throws ArgumentException,
+ ClientException, CLIException;
@@ -702,26 +780,22 @@
/**
- * Gets the console application instance.
- *
- * @return Returns the console application instance.
- */
- protected final ConsoleApplication getConsoleApplication() {
- return app;
- }
-
-
-
- /**
* Get the managed object referenced by the provided managed object
* path.
*
+ * @param app
+ * The console application.
+ * @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.
+ * @return Returns a {@link MenuResult#success()} containing the
+ * managed object referenced by the provided managed object
+ * path, or {@link MenuResult#quit()}, or
+ * {@link MenuResult#cancel()}, if the sub-command was run
+ * interactively and the user chose to quit or cancel.
* @throws DefinitionDecodingException
* If the managed object was found but its type could not
* be determined.
@@ -741,20 +815,21 @@
* @throws CommunicationException
* If the client cannot contact the server due to an
* underlying communication problem.
- * @throws ArgumentException
+ * @throws CLIException
* If one of the naming arguments referenced a managed
* object of the wrong type.
* @throws ClientException
* If the management context could not be created.
*/
- protected final ManagedObject<?> getManagedObject(
- ManagedObjectPath<?, ?> path, List<String> args)
- throws ArgumentException, AuthorizationException,
- DefinitionDecodingException, ManagedObjectDecodingException,
- CommunicationException, ConcurrentModificationException,
- ManagedObjectNotFoundException, ClientException {
+ protected final MenuResult<ManagedObject<?>> getManagedObject(
+ ConsoleApplication app, ManagementContext context,
+ ManagedObjectPath<?, ?> path, List<String> args) throws CLIException,
+ AuthorizationException, DefinitionDecodingException,
+ ManagedObjectDecodingException, CommunicationException,
+ ConcurrentModificationException, ManagedObjectNotFoundException,
+ ClientException {
ManagedObjectFinder finder = new ManagedObjectFinder();
- return finder.find(app.getManagementContext(), path, args);
+ return finder.find(app, context, path, args);
}
@@ -762,6 +837,8 @@
/**
* Gets the values of the naming arguments.
*
+ * @param app
+ * The console application.
* @param namingArgs
* The naming arguments.
* @return Returns the values of the naming arguments.
@@ -769,7 +846,7 @@
* If one of the naming arguments is missing and the
* application is non-interactive.
*/
- protected final List<String> getNamingArgValues(
+ protected final List<String> getNamingArgValues(ConsoleApplication app,
List<StringArgument> namingArgs) throws ArgumentException {
ArrayList<String> values = new ArrayList<String>(namingArgs.size());
for (StringArgument arg : namingArgs) {
@@ -902,14 +979,19 @@
* The type of child client configuration.
* @param <S>
* The type of child server configuration.
+ * @param app
+ * The console application.
* @param parent
* The parent managed object.
* @param r
* The relation between the parent and the children.
* @param d
* The type of child managed object to choose from.
- * @return Returns the name of the managed object that the user
- * selected.
+ * @return Returns a {@link MenuResult#success()} containing the
+ * name of the managed object that the user selected, or
+ * {@link MenuResult#quit()}, or
+ * {@link MenuResult#cancel()}, if the sub-command was run
+ * interactive and the user chose to quit or cancel.
* @throws CommunicationException
* If the server cannot be contacted.
* @throws ConcurrentModificationException
@@ -917,52 +999,62 @@
* @throws AuthorizationException
* If the children cannot be listed due to an
* authorization failure.
- * @throws ArgumentException
+ * @throws CLIException
* If the user input can be read from the console or if
* there are no children.
*/
protected final <C extends ConfigurationClient, S extends Configuration>
- String readChildName(ManagedObject<?> parent,
+ MenuResult<String> readChildName(
+ ConsoleApplication app, ManagedObject<?> parent,
InstantiableRelationDefinition<C, S> r,
AbstractManagedObjectDefinition<? extends C, ? extends S> d)
throws AuthorizationException, ConcurrentModificationException,
- CommunicationException, ArgumentException {
+ CommunicationException, CLIException {
if (d == null) {
d = r.getChildDefinition();
}
+ app.println();
+ app.println();
String[] children = parent.listChildren(r, d);
switch (children.length) {
case 0: {
// No options available - abort.
Message msg =
ERR_DSCFG_ERROR_FINDER_NO_CHILDREN.get(d.getUserFriendlyPluralName());
- throw new ArgumentException(msg);
+ throw new CLIException(msg);
}
case 1: {
// Only one option available so confirm that the user wishes to
// access it.
Message msg = INFO_DSCFG_FINDER_PROMPT_SINGLE.get(
d.getUserFriendlyName(), children[0]);
- if (getConsoleApplication().confirmAction(msg)) {
- return children[0];
+ if (app.confirmAction(msg, true)) {
+ return MenuResult.success(children[0]);
} else {
- msg = ERR_DSCFG_ERROR_FINDER_SINGLE_CHILD_REJECTED.get(
- d.getUserFriendlyName());
- throw new ArgumentException(msg);
+ return MenuResult.cancel();
}
}
default: {
// Display a menu.
+ MenuBuilder<String> builder = new MenuBuilder<String>(app);
+ builder.setMultipleColumnThreshold(MULTI_COLUMN_THRESHOLD);
+ builder.setPrompt(INFO_DSCFG_FINDER_PROMPT_MANY.get(d
+ .getUserFriendlyName()));
+
Arrays.sort(children, String.CASE_INSENSITIVE_ORDER);
- ArrayList<Message> desc = new ArrayList<Message>();
- for (String s : Arrays.asList(children)) {
- desc.add(Message.raw(s));
+ for (String child : children) {
+ Message option = Message.raw("%s", child);
+ builder.addNumberedOption(option, MenuResult.success(child));
}
- Message prompt = INFO_DSCFG_FINDER_PROMPT_MANY.get(
- d.getUserFriendlyName());
- return getConsoleApplication().readChoice(
- prompt, desc, Arrays.asList(children), null);
+
+ if (app.isMenuDrivenMode()) {
+ builder.addCancelOption(true);
+ }
+ builder.addQuitOption();
+
+ Menu<String> menu = builder.toMenu();
+ return menu.run();
}
}
}
@@ -1062,4 +1154,7 @@
subCommand.addArgument(unitTimeArgument);
}
+
+
+
}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandlerFactory.java b/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandlerFactory.java
new file mode 100644
index 0000000..a525d1a
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandlerFactory.java
@@ -0,0 +1,357 @@
+/*
+ * 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.SortedSet;
+import java.util.TreeSet;
+
+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.RelationOption;
+import org.opends.server.admin.SingletonRelationDefinition;
+import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.SubCommandArgumentParser;
+
+
+
+/**
+ * Uses the administration framework introspection API to construct
+ * the dsconfig sub-command handlers.
+ */
+final class SubCommandHandlerFactory {
+
+ /**
+ * A relation definition visitor used to recursively determine the
+ * set of available sub-commands.
+ */
+ private final class Visitor implements
+ RelationDefinitionVisitor<Void, ManagedObjectPath<?, ?>> {
+
+ /**
+ * {@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.
+ createHandlers.add(CreateSubCommandHandler.create(parser, p, r));
+ deleteHandlers.add(DeleteSubCommandHandler.create(parser, p, r));
+ listHandlers.add(ListSubCommandHandler.create(parser, p, r));
+ getPropHandlers.add(GetPropSubCommandHandler.create(parser, p, r));
+ setPropHandlers.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.
+ createHandlers.add(CreateSubCommandHandler.create(parser, p, r));
+ deleteHandlers.add(DeleteSubCommandHandler.create(parser, p, r));
+ listHandlers.add(ListSubCommandHandler.create(parser, p, r));
+ getPropHandlers.add(GetPropSubCommandHandler.create(parser, p, r));
+ setPropHandlers.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.
+ getPropHandlers.add(GetPropSubCommandHandler.create(parser, p, r));
+ setPropHandlers.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;
+ }
+
+ }
+
+ // The set of all available sub-commands.
+ private SortedSet<SubCommandHandler> allHandlers =
+ new TreeSet<SubCommandHandler>();
+
+ // The set of create-xxx available sub-commands.
+ private SortedSet<CreateSubCommandHandler<?, ?>> createHandlers =
+ new TreeSet<CreateSubCommandHandler<?, ?>>();
+
+ // The set of delete-xxx available sub-commands.
+ private SortedSet<DeleteSubCommandHandler> deleteHandlers =
+ new TreeSet<DeleteSubCommandHandler>();
+
+ // Any exception that occurred whilst creating the sub-commands.
+ private ArgumentException exception = null;
+
+ // The set of get-xxx-prop available sub-commands.
+ private SortedSet<GetPropSubCommandHandler> getPropHandlers =
+ new TreeSet<GetPropSubCommandHandler>();
+
+ // The help sub-command handler.
+ private HelpSubCommandHandler helpHandler = null;
+
+ // The set of list-xxx available sub-commands.
+ private SortedSet<ListSubCommandHandler> listHandlers =
+ new TreeSet<ListSubCommandHandler>();
+
+ // The sub-command argument parser.
+ private final SubCommandArgumentParser parser;
+
+ // The set of set-xxx-prop available sub-commands.
+ private SortedSet<SetPropSubCommandHandler> setPropHandlers =
+ new TreeSet<SetPropSubCommandHandler>();
+
+ // The relation visitor.
+ private final Visitor visitor = new Visitor();
+
+
+
+ /**
+ * Create a new sub-command builder.
+ *
+ * @param parser
+ * The sub-command argument parser.
+ * @throws ArgumentException
+ * If a sub-command could not be created successfully.
+ */
+ public SubCommandHandlerFactory(
+ SubCommandArgumentParser parser) throws ArgumentException {
+ this.parser = parser;
+
+ // We always need a help properties sub-command handler.
+ helpHandler = HelpSubCommandHandler.create(parser);
+
+ processPath(ManagedObjectPath.emptyPath());
+
+ allHandlers.add(helpHandler);
+ allHandlers.addAll(createHandlers);
+ allHandlers.addAll(deleteHandlers);
+ allHandlers.addAll(listHandlers);
+ allHandlers.addAll(getPropHandlers);
+ allHandlers.addAll(setPropHandlers);
+
+ if (exception != null) {
+ throw exception;
+ }
+ }
+
+
+
+ /**
+ * Gets all the sub-command handlers.
+ *
+ * @return Returns all the sub-command handlers.
+ */
+ public SortedSet<SubCommandHandler> getAllSubCommandHandlers() {
+ return allHandlers;
+ }
+
+
+
+ /**
+ * Gets all the create-xxx sub-command handlers.
+ *
+ * @return Returns all the create-xxx sub-command handlers.
+ */
+ public SortedSet<CreateSubCommandHandler<?, ?>>
+ getCreateSubCommandHandlers() {
+ return createHandlers;
+ }
+
+
+
+ /**
+ * Gets all the delete-xxx sub-command handlers.
+ *
+ * @return Returns all the delete-xxx sub-command handlers.
+ */
+ public SortedSet<DeleteSubCommandHandler> getDeleteSubCommandHandlers() {
+ return deleteHandlers;
+ }
+
+
+
+ /**
+ * Gets all the get-xxx-prop sub-command handlers.
+ *
+ * @return Returns all the get-xxx-prop sub-command handlers.
+ */
+ public SortedSet<GetPropSubCommandHandler> getGetPropSubCommandHandlers() {
+ return getPropHandlers;
+ }
+
+
+
+ /**
+ * Gets all the list-xxx sub-command handlers.
+ *
+ * @return Returns all the list-xxx sub-command handlers.
+ */
+ public SortedSet<ListSubCommandHandler> getListSubCommandHandlers() {
+ return listHandlers;
+ }
+
+
+
+ /**
+ * Gets all the set-xxx-prop sub-command handlers.
+ *
+ * @return Returns all the set-xxx-prop sub-command handlers.
+ */
+ public SortedSet<SetPropSubCommandHandler> getSetPropSubCommandHandlers() {
+ return setPropHandlers;
+ }
+
+
+
+ // 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()) {
+ if (!r.hasOption(RelationOption.HIDDEN)) {
+ r.accept(visitor, 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));
+ }
+ }
+}
diff --git a/opends/src/server/org/opends/server/util/cli/CLIException.java b/opends/src/server/org/opends/server/util/cli/CLIException.java
new file mode 100644
index 0000000..8483f50
--- /dev/null
+++ b/opends/src/server/org/opends/server/util/cli/CLIException.java
@@ -0,0 +1,92 @@
+/*
+ * 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.util.cli;
+
+
+
+import org.opends.messages.Message;
+import org.opends.messages.UtilityMessages;
+import org.opends.server.types.IdentifiedException;
+
+
+
+/**
+ * Thrown to indicate that a problem occurred when interacting with
+ * the client. For example, if input provided by the client was
+ * invalid.
+ */
+public class CLIException extends IdentifiedException {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -8182075627986981748L;
+
+
+
+ /**
+ * Adapts any exception that may have occurred whilst reading input
+ * from the console.
+ *
+ * @param cause
+ * The exception that occurred whilst reading input from
+ * the console.
+ * @return Returns a new CLI exception describing a problem that
+ * occurred whilst reading input from the console.
+ */
+ public static CLIException adaptInputException(Throwable cause) {
+ return new CLIException(UtilityMessages.ERR_CONSOLE_INPUT_ERROR.get(cause
+ .getMessage()), cause);
+ }
+
+
+
+ /**
+ * Creates a new CLI exception with the provided message.
+ *
+ * @param message
+ * The message explaining the problem that occurred.
+ */
+ public CLIException(Message message) {
+ super(message);
+ }
+
+
+
+ /**
+ * Creates a new CLI exception with the provided message and cause.
+ *
+ * @param message
+ * The message explaining the problem that occurred.
+ * @param cause
+ * The cause of this exception.
+ */
+ public CLIException(Message message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/util/cli/ConsoleApplication.java b/opends/src/server/org/opends/server/util/cli/ConsoleApplication.java
new file mode 100644
index 0000000..7c32dff
--- /dev/null
+++ b/opends/src/server/org/opends/server/util/cli/ConsoleApplication.java
@@ -0,0 +1,453 @@
+/*
+ * 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.util.cli;
+
+
+
+import static org.opends.messages.UtilityMessages.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+
+import java.io.BufferedReader;
+import java.io.EOFException;
+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 org.opends.messages.Message;
+import org.opends.server.types.NullOutputStream;
+import org.opends.server.util.PasswordReader;
+
+
+
+/**
+ * This class provides an abstract base class which can be used as the
+ * basis of a console-based application.
+ */
+public abstract class ConsoleApplication {
+
+ /**
+ * A null reader.
+ */
+ private static final class NullReader extends Reader {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void close() throws IOException {
+ // Do nothing.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int read(char[] cbuf, int off, int len) throws IOException {
+ return -1;
+ }
+ }
+
+ // The error stream which this application should use.
+ private final PrintStream err;
+
+ // The input stream reader which this application should use.
+ private final BufferedReader in;
+
+ // The output stream which this application should use.
+ private final PrintStream out;
+
+
+
+ /**
+ * Creates a new console application instance.
+ *
+ * @param in
+ * The application input stream.
+ * @param out
+ * The application output stream.
+ * @param err
+ * The application error stream.
+ */
+ protected ConsoleApplication(BufferedReader in, PrintStream out,
+ PrintStream err) {
+ if (in != null) {
+ this.in = in;
+ } else {
+ this.in = new BufferedReader(new NullReader());
+ }
+
+ if (out != null) {
+ this.out = out;
+ } else {
+ this.out = NullOutputStream.printStream();
+ }
+
+ if (err != null) {
+ this.err = out;
+ } else {
+ this.err = NullOutputStream.printStream();
+ }
+ }
+
+
+
+ /**
+ * Creates a new console application instance.
+ *
+ * @param in
+ * The application input stream.
+ * @param out
+ * The application output stream.
+ * @param err
+ * The application error stream.
+ */
+ protected ConsoleApplication(InputStream in, OutputStream out,
+ OutputStream err) {
+ if (in != null) {
+ this.in = new BufferedReader(new InputStreamReader(in));
+ } else {
+ this.in = new BufferedReader(new NullReader());
+ }
+
+ 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();
+ }
+ }
+
+
+
+ /**
+ * Interactively confirms whether a user wishes to perform an
+ * action. If the application is non-interactive, then the provided
+ * default is returned automatically.
+ *
+ * @param prompt
+ * The prompt describing the action.
+ * @param defaultValue
+ * The default value for the confirmation message. This
+ * will be returned if the application is non-interactive
+ * or if the user just presses return.
+ * @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.
+ * @throws CLIException
+ * If the user's response could not be read from the
+ * console for some reason.
+ */
+ public final boolean confirmAction(Message prompt, final boolean defaultValue)
+ throws CLIException {
+ if (!isInteractive()) {
+ return defaultValue;
+ }
+
+ final Message yes = INFO_GENERAL_YES.get();
+ final Message no = INFO_GENERAL_NO.get();
+ final Message errMsg = ERR_CONSOLE_APP_CONFIRM.get(yes, no);
+ prompt = INFO_MENU_PROMPT_CONFIRM.get(prompt, yes, no, defaultValue ? yes
+ : no);
+
+ ValidationCallback<Boolean> validator = new ValidationCallback<Boolean>() {
+
+ public Boolean validate(ConsoleApplication app, String input) {
+ String ninput = input.toLowerCase().trim();
+ if (ninput.length() == 0) {
+ return defaultValue;
+ } else if (no.toString().startsWith(ninput)) {
+ return false;
+ } else if (yes.toString().startsWith(ninput)) {
+ return true;
+ } else {
+ // Try again...
+ app.println();
+ app.println(errMsg);
+ app.println();
+ }
+
+ return null;
+ }
+ };
+
+ try {
+ return readValidatedInput(prompt, validator);
+ } catch (CLIException e) {
+ // Should never happen.
+ throw new RuntimeException(e);
+ }
+ }
+
+
+
+ /**
+ * Gets the application error stream.
+ *
+ * @return Returns the application error stream.
+ */
+ public final PrintStream getErrorStream() {
+ return err;
+ }
+
+
+
+ /**
+ * Gets the application input stream.
+ *
+ * @return Returns the application input stream.
+ */
+ public final BufferedReader getInputStream() {
+ return in;
+ }
+
+
+
+ /**
+ * Gets the application output stream.
+ *
+ * @return Returns the application output stream.
+ */
+ public final PrintStream getOutputStream() {
+ return out;
+ }
+
+
+
+ /**
+ * Indicates whether or not the user has requested interactive
+ * behavior.
+ *
+ * @return Returns <code>true</code> if the user has requested
+ * interactive behavior.
+ */
+ public abstract boolean isInteractive();
+
+
+
+ /**
+ * Indicates whether or not this console application is running in
+ * its menu-driven mode. This can be used to dictate whether output
+ * should go to the error stream or not. In addition, it may also
+ * dictate whether or not sub-menus should display a cancel option
+ * as well as a quit option.
+ *
+ * @return Returns <code>true</code> if this console application
+ * is running in its menu-driven mode.
+ */
+ public abstract boolean isMenuDrivenMode();
+
+
+
+ /**
+ * Indicates whether or not the user has requested quiet output.
+ *
+ * @return Returns <code>true</code> if the user has requested
+ * quiet output.
+ */
+ public abstract boolean isQuiet();
+
+
+
+ /**
+ * 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 abstract boolean isScriptFriendly();
+
+
+
+ /**
+ * Indicates whether or not the user has requested verbose output.
+ *
+ * @return Returns <code>true</code> if the user has requested
+ * verbose output.
+ */
+ public abstract boolean isVerbose();
+
+
+
+ /**
+ * Interactively prompts the user to press return to continue. This
+ * method should be called in situations where a user needs to be
+ * given a chance to read some documentation before continuing
+ * (continuing may cause the documentation to be scrolled out of
+ * view).
+ */
+ public final void pressReturnToContinue() {
+ Message msg = INFO_MENU_PROMPT_RETURN_TO_CONTINUE.get();
+ try {
+ readLineOfInput(msg);
+ } catch (CLIException e) {
+ // Ignore the exception - applications don't care.
+ }
+ }
+
+
+
+ /**
+ * Displays a blank line to the error stream.
+ */
+ public final void println() {
+ err.println();
+ }
+
+
+
+ /**
+ * Displays a message to the error stream.
+ *
+ * @param msg
+ * The message.
+ */
+ public final void println(Message msg) {
+ err.println(wrapText(msg, MAX_LINE_WIDTH));
+ }
+
+
+
+ /**
+ * Displays a message to the error stream indented by the specified
+ * number of columns.
+ *
+ * @param msg
+ * The message.
+ * @param indent
+ * The number of columns to indent.
+ */
+ public final void println(Message msg, int indent) {
+ err.println(wrapText(msg, MAX_LINE_WIDTH, indent));
+ }
+
+
+
+ /**
+ * Displays a message to the error stream if verbose mode is
+ * enabled.
+ *
+ * @param msg
+ * The verbose message.
+ */
+ public final void printVerboseMessage(Message msg) {
+ if (isVerbose() || isInteractive()) {
+ err.println(wrapText(msg, MAX_LINE_WIDTH));
+ }
+ }
+
+
+
+ /**
+ * 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 CLIException
+ * If the line of input could not be retrieved for some
+ * reason.
+ */
+ public final String readLineOfInput(Message prompt) throws CLIException {
+ err.print(wrapText(prompt + " ", MAX_LINE_WIDTH));
+ try {
+ String s = in.readLine();
+ if (s == null) {
+ throw CLIException
+ .adaptInputException(new EOFException("End of input"));
+ } else {
+ return s;
+ }
+ } catch (IOException e) {
+ throw CLIException.adaptInputException(e);
+ }
+ }
+
+
+
+ /**
+ * Interactively retrieves a password from the console.
+ *
+ * @param prompt
+ * The password prompt.
+ * @return Returns the password.
+ * @throws CLIException
+ * If the password could not be retrieved for some reason.
+ */
+ public final String readPassword(Message prompt) throws CLIException {
+ err.print(wrapText(prompt + " ", MAX_LINE_WIDTH));
+ char[] pwChars;
+ try {
+ pwChars = PasswordReader.readPassword();
+ } catch (Exception e) {
+ throw CLIException.adaptInputException(e);
+ }
+ return new String(pwChars);
+ }
+
+
+
+ /**
+ * Interactively prompts for user input and continues until valid
+ * input is provided.
+ *
+ * @param <T>
+ * The type of decoded user input.
+ * @param prompt
+ * The interactive prompt which should be displayed on each
+ * input attempt.
+ * @param validator
+ * An input validator responsible for validating and
+ * decoding the user's response.
+ * @return Returns the decoded user's response.
+ * @throws CLIException
+ * If an unexpected error occurred which prevented
+ * validation.
+ */
+ public final <T> T readValidatedInput(Message prompt,
+ ValidationCallback<T> validator) throws CLIException {
+ while (true) {
+ String response = readLineOfInput(prompt);
+ T value = validator.validate(this, response);
+ if (value != null) {
+ return value;
+ }
+ }
+ }
+}
diff --git a/opends/src/server/org/opends/server/util/cli/ErrorStreamConsoleApplication.java b/opends/src/server/org/opends/server/util/cli/ErrorStreamConsoleApplication.java
new file mode 100644
index 0000000..0d16256
--- /dev/null
+++ b/opends/src/server/org/opends/server/util/cli/ErrorStreamConsoleApplication.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.util.cli;
+
+
+
+/**
+ * A console application decorator which redirects all output to the
+ * underlying application's error stream.
+ */
+public class ErrorStreamConsoleApplication extends ConsoleApplication {
+
+ // The underlying console application.
+ private final ConsoleApplication app;
+
+
+
+ /**
+ * Creates a new console application instance which redirects all
+ * output to the underlying application's error stream.
+ *
+ * @param app
+ * The underlying application console.
+ */
+ public ErrorStreamConsoleApplication(ConsoleApplication app) {
+ super(app.getInputStream(), app.getErrorStream(), app.getErrorStream());
+
+ this.app = app;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isInteractive() {
+ return app.isInteractive();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isMenuDrivenMode() {
+ return app.isMenuDrivenMode();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isQuiet() {
+ return app.isQuiet();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isScriptFriendly() {
+ return app.isScriptFriendly();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isVerbose() {
+ return app.isVerbose();
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/HelpCallback.java b/opends/src/server/org/opends/server/util/cli/HelpCallback.java
similarity index 94%
rename from opends/src/server/org/opends/server/tools/dsconfig/HelpCallback.java
rename to opends/src/server/org/opends/server/util/cli/HelpCallback.java
index 8412933..fb5af43 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/HelpCallback.java
+++ b/opends/src/server/org/opends/server/util/cli/HelpCallback.java
@@ -24,14 +24,14 @@
*
* Portions Copyright 2007 Sun Microsystems, Inc.
*/
-package org.opends.server.tools.dsconfig;
+package org.opends.server.util.cli;
/**
* An interface for displaying help interactively.
*/
-interface HelpCallback {
+public interface HelpCallback {
/**
* Displays help to the provided application console.
diff --git a/opends/src/server/org/opends/server/util/cli/Menu.java b/opends/src/server/org/opends/server/util/cli/Menu.java
new file mode 100644
index 0000000..abeb384
--- /dev/null
+++ b/opends/src/server/org/opends/server/util/cli/Menu.java
@@ -0,0 +1,52 @@
+/*
+ * 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.util.cli;
+
+
+
+/**
+ * An interactive console-based menu.
+ *
+ * @param <T>
+ * The type of success result value(s) returned by the
+ * call-back. Use <code>Void</code> if the call-backs do
+ * not return any values.
+ */
+public interface Menu<T> {
+
+ /**
+ * Displays the menu and waits for the user to select a valid
+ * option. When the user selects an option, the call-back associated
+ * with the option will be invoked and its result returned.
+ *
+ * @return Returns the result of invoking the chosen menu call-back.
+ * @throws CLIException
+ * If an I/O exception occurred or if one of the menu
+ * option call-backs failed for some reason.
+ */
+ MenuResult<T> run() throws CLIException;
+}
diff --git a/opends/src/server/org/opends/server/util/cli/MenuBuilder.java b/opends/src/server/org/opends/server/util/cli/MenuBuilder.java
new file mode 100644
index 0000000..a69d9a0
--- /dev/null
+++ b/opends/src/server/org/opends/server/util/cli/MenuBuilder.java
@@ -0,0 +1,818 @@
+/*
+ * 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.util.cli;
+
+
+
+import static org.opends.messages.UtilityMessages.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opends.messages.Message;
+import org.opends.server.util.table.TableBuilder;
+import org.opends.server.util.table.TablePrinter;
+import org.opends.server.util.table.TextTablePrinter;
+
+
+
+/**
+ * An interface for incrementally building a command-line menu.
+ *
+ * @param <T>
+ * The type of value returned by the call-backs. Use
+ * <code>Void</code> if the call-backs do not return a
+ * value.
+ */
+public final class MenuBuilder<T> {
+
+ /**
+ * A simple menu option call-back which is a composite of zero or
+ * more underlying call-backs.
+ *
+ * @param <T>
+ * The type of value returned by the call-back.
+ */
+ private static final class CompositeCallback<T> implements MenuCallback<T> {
+
+ // The list of underlying call-backs.
+ private final Collection<MenuCallback<T>> callbacks;
+
+
+
+ /**
+ * Creates a new composite call-back with the specified set of
+ * call-backs.
+ *
+ * @param callbacks
+ * The set of call-backs.
+ */
+ public CompositeCallback(Collection<MenuCallback<T>> callbacks) {
+ this.callbacks = callbacks;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public MenuResult<T> invoke(ConsoleApplication app) throws CLIException {
+ List<T> values = new ArrayList<T>();
+ for (MenuCallback<T> callback : callbacks) {
+ MenuResult<T> result = callback.invoke(app);
+
+ if (!result.isSuccess()) {
+ // Throw away all the other results.
+ return result;
+ } else {
+ values.addAll(result.getValues());
+ }
+ }
+ return MenuResult.success(values);
+ }
+ }
+
+
+
+ /**
+ * Underlying menu implementation generated by this menu builder.
+ *
+ * @param <T>
+ * The type of value returned by the call-backs. Use
+ * <code>Void</code> if the call-backs do not return a
+ * value.
+ */
+ private static final class MenuImpl<T> implements Menu<T> {
+
+ // Indicates whether the menu will allow selection of multiple
+ // numeric options.
+ private final boolean allowMultiSelect;
+
+ // The application console.
+ private final ConsoleApplication app;
+
+ // The call-back lookup table.
+ private final Map<String, MenuCallback<T>> callbacks;
+
+ // The char options table builder.
+ private final TableBuilder cbuilder;
+
+ // The call-back for the optional default action.
+ private final MenuCallback<T> defaultCallback;
+
+ // The description of the optional default action.
+ private final Message defaultDescription;
+
+ // The numeric options table builder.
+ private final TableBuilder nbuilder;
+
+ // The table printer.
+ private final TablePrinter printer;
+
+ // The menu prompt.
+ private final Message prompt;
+
+ // The menu title.
+ private final Message title;
+
+
+
+ // Private constructor.
+ private MenuImpl(ConsoleApplication app, Message title, Message prompt,
+ TableBuilder ntable, TableBuilder ctable, TablePrinter printer,
+ Map<String, MenuCallback<T>> callbacks, boolean allowMultiSelect,
+ MenuCallback<T> defaultCallback, Message defaultDescription) {
+ this.app = app;
+ this.title = title;
+ this.prompt = prompt;
+ this.nbuilder = ntable;
+ this.cbuilder = ctable;
+ this.printer = printer;
+ this.callbacks = callbacks;
+ this.allowMultiSelect = allowMultiSelect;
+ this.defaultCallback = defaultCallback;
+ this.defaultDescription = defaultDescription;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public MenuResult<T> run() throws CLIException {
+ // The validation call-back which will be used to determine the
+ // action call-back.
+ ValidationCallback<MenuCallback<T>> validator =
+ new ValidationCallback<MenuCallback<T>>() {
+
+ public MenuCallback<T> validate(ConsoleApplication app, String input) {
+ String ninput = input.trim();
+
+ if (ninput.length() == 0) {
+ if (defaultCallback != null) {
+ return defaultCallback;
+ } else if (allowMultiSelect) {
+ app.println();
+ app.println(ERR_MENU_BAD_CHOICE_MULTI.get());
+ app.println();
+ return null;
+ } else {
+ app.println();
+ app.println(ERR_MENU_BAD_CHOICE_SINGLE.get());
+ app.println();
+ return null;
+ }
+ } else if (allowMultiSelect) {
+ // Use a composite call-back to collect all the results.
+ List<MenuCallback<T>> cl = new ArrayList<MenuCallback<T>>();
+ for (String value : ninput.split(",")) {
+ // Make sure that there are no duplicates.
+ String nvalue = value.trim();
+ Set<String> choices = new HashSet<String>();
+
+ if (choices.contains(nvalue)) {
+ app.println();
+ app.println(ERR_MENU_BAD_CHOICE_MULTI_DUPE.get(value));
+ app.println();
+ return null;
+ } else if (!callbacks.containsKey(nvalue)) {
+ app.println();
+ app.println(ERR_MENU_BAD_CHOICE_MULTI.get());
+ app.println();
+ return null;
+ } else {
+ cl.add(callbacks.get(nvalue));
+ choices.add(nvalue);
+ }
+ }
+
+ return new CompositeCallback<T>(cl);
+ } else if (!callbacks.containsKey(ninput)) {
+ app.println();
+ app.println(ERR_MENU_BAD_CHOICE_SINGLE.get());
+ app.println();
+ return null;
+ } else {
+ return callbacks.get(ninput);
+ }
+ }
+ };
+
+ // Determine the correct choice prompt.
+ Message promptMsg;
+ if (allowMultiSelect) {
+ if (defaultDescription != null) {
+ promptMsg = INFO_MENU_PROMPT_MULTI_DEFAULT.get(defaultDescription);
+ } else {
+ promptMsg = INFO_MENU_PROMPT_MULTI.get();
+ }
+ } else {
+ if (defaultDescription != null) {
+ promptMsg = INFO_MENU_PROMPT_SINGLE_DEFAULT.get(defaultDescription);
+ } else {
+ promptMsg = INFO_MENU_PROMPT_SINGLE.get();
+ }
+ }
+
+ // If the user selects help then we need to loop around and
+ // display the menu again.
+ while (true) {
+ // Display the menu.
+ if (title != null) {
+ app.println(title);
+ app.println();
+ }
+
+ if (prompt != null) {
+ app.println(prompt);
+ app.println();
+ }
+
+ if (nbuilder.getTableHeight() > 0) {
+ nbuilder.print(printer);
+ app.println();
+ }
+
+ if (cbuilder.getTableHeight() > 0) {
+ TextTablePrinter cprinter =
+ new TextTablePrinter(app.getErrorStream());
+ cprinter.setDisplayHeadings(false);
+ int sz = String.valueOf(nbuilder.getTableHeight()).length() + 1;
+ cprinter.setColumnWidth(0, 2);
+ cprinter.setColumnWidth(1, sz);
+ cprinter.setColumnWidth(2, 0);
+ cbuilder.print(cprinter);
+ app.println();
+ }
+
+ // Get the user's choice.
+ MenuCallback<T> choice;
+ try {
+ choice = app.readValidatedInput(promptMsg, validator);
+ } catch (CLIException e) {
+ // Should never happen.
+ throw new RuntimeException(e);
+ }
+
+ // Invoke the user's selected choice.
+ MenuResult<T> result = choice.invoke(app);
+
+ // Determine if the help needs to be displayed, display it and
+ // start again.
+ if (!result.isAgain()) {
+ return result;
+ } else {
+ app.println();
+ app.println();
+ }
+ }
+ }
+ }
+
+
+
+ /**
+ * A simple menu option call-back which does nothing but return the
+ * provided menu result.
+ *
+ * @param <T>
+ * The type of result returned by the call-back.
+ */
+ private static final class ResultCallback<T> implements MenuCallback<T> {
+
+ // The result to be returned by this call-back.
+ private final MenuResult<T> result;
+
+
+
+ // Private constructor.
+ private ResultCallback(MenuResult<T> result) {
+ this.result = result;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public MenuResult<T> invoke(ConsoleApplication app) throws CLIException {
+ return result;
+ }
+
+ }
+
+ // The multiple column display threshold.
+ private int threshold = -1;
+
+ // Indicates whether the menu will allow selection of multiple
+ // numeric options.
+ private boolean allowMultiSelect = false;
+
+ // The application console.
+ private final ConsoleApplication app;
+
+ // The char option call-backs.
+ private final List<MenuCallback<T>> charCallbacks =
+ new ArrayList<MenuCallback<T>>();
+
+ // The char option keys (must be single-character messages).
+ private final List<Message> charKeys = new ArrayList<Message>();
+
+ // The synopsis of char options.
+ private final List<Message> charSynopsis = new ArrayList<Message>();
+
+ // Optional column headings.
+ private final List<Message> columnHeadings = new ArrayList<Message>();
+
+ // Optional column widths.
+ private final List<Integer> columnWidths = new ArrayList<Integer>();
+
+ // The call-back for the optional default action.
+ private MenuCallback<T> defaultCallback = null;
+
+ // The description of the optional default action.
+ private Message defaultDescription = null;
+
+ // The numeric option call-backs.
+ private final List<MenuCallback<T>> numericCallbacks =
+ new ArrayList<MenuCallback<T>>();
+
+ // The numeric option fields.
+ private final List<List<Message>> numericFields =
+ new ArrayList<List<Message>>();
+
+ // The menu title.
+ private Message title = null;
+
+ // The menu prompt.
+ private Message prompt = null;
+
+
+
+ /**
+ * Creates a new menu.
+ *
+ * @param app
+ * The application console.
+ */
+ public MenuBuilder(ConsoleApplication app) {
+ this.app = app;
+ }
+
+
+
+ /**
+ * Creates a "back" menu option. When invoked, this option will
+ * return a {@link MenuResult#cancel()} result.
+ *
+ * @param isDefault
+ * Indicates whether this option should be made the menu
+ * default.
+ */
+ public void addBackOption(boolean isDefault) {
+ addCharOption(INFO_MENU_OPTION_BACK_KEY.get(), INFO_MENU_OPTION_BACK.get(),
+ MenuResult.<T> cancel());
+
+ if (isDefault) {
+ setDefault(INFO_MENU_OPTION_BACK_KEY.get(), MenuResult.<T> cancel());
+ }
+ }
+
+
+
+ /**
+ * Creates a "cancel" menu option. When invoked, this option will
+ * return a {@link MenuResult#cancel()} result.
+ *
+ * @param isDefault
+ * Indicates whether this option should be made the menu
+ * default.
+ */
+ public void addCancelOption(boolean isDefault) {
+ addCharOption(INFO_MENU_OPTION_CANCEL_KEY.get(), INFO_MENU_OPTION_CANCEL
+ .get(), MenuResult.<T> cancel());
+
+ if (isDefault) {
+ setDefault(INFO_MENU_OPTION_CANCEL_KEY.get(), MenuResult.<T> cancel());
+ }
+ }
+
+
+
+ /**
+ * Adds a menu choice to the menu which will have a single letter as
+ * its key.
+ *
+ * @param c
+ * The single-letter message which will be used as the key
+ * for this option.
+ * @param description
+ * The menu option description.
+ * @param callback
+ * The call-back associated with this option.
+ */
+ public void addCharOption(Message c, Message description,
+ MenuCallback<T> callback) {
+ charKeys.add(c);
+ charSynopsis.add(description);
+ charCallbacks.add(callback);
+ }
+
+
+
+ /**
+ * Adds a menu choice to the menu which will have a single letter as
+ * its key and which returns the provided result.
+ *
+ * @param c
+ * The single-letter message which will be used as the key
+ * for this option.
+ * @param description
+ * The menu option description.
+ * @param result
+ * The menu result which should be returned by this menu
+ * choice.
+ */
+ public void addCharOption(Message c, Message description,
+ MenuResult<T> result) {
+ addCharOption(c, description, new ResultCallback<T>(result));
+ }
+
+
+
+ /**
+ * Creates a "help" menu option which will use the provided help
+ * call-back to display help relating to the other menu options.
+ * When the help menu option is selected help will be displayed and
+ * then the user will be shown the menu again and prompted to enter
+ * a choice.
+ *
+ * @param callback
+ * The help call-back.
+ */
+ public void addHelpOption(final HelpCallback callback) {
+ MenuCallback<T> wrapper = new MenuCallback<T>() {
+
+ public MenuResult<T> invoke(ConsoleApplication app) throws CLIException {
+ app.println();
+ callback.display(app);
+ return MenuResult.again();
+ }
+
+ };
+
+ addCharOption(INFO_MENU_OPTION_HELP_KEY.get(), INFO_MENU_OPTION_HELP.get(),
+ wrapper);
+ }
+
+
+
+ /**
+ * Adds a menu choice to the menu which will have a numeric key.
+ *
+ * @param description
+ * The menu option description.
+ * @param callback
+ * The call-back associated with this option.
+ * @param extraFields
+ * Any additional fields associated with this menu option.
+ * @return Returns the number associated with menu choice.
+ */
+ public int addNumberedOption(Message description, MenuCallback<T> callback,
+ Message... extraFields) {
+ List<Message> fields = new ArrayList<Message>();
+ fields.add(description);
+ if (extraFields != null) {
+ fields.addAll(Arrays.asList(extraFields));
+ }
+
+ numericFields.add(fields);
+ numericCallbacks.add(callback);
+
+ return numericCallbacks.size();
+ }
+
+
+
+ /**
+ * Adds a menu choice to the menu which will have a numeric key and
+ * which returns the provided result.
+ *
+ * @param description
+ * The menu option description.
+ * @param result
+ * The menu result which should be returned by this menu
+ * choice.
+ * @param extraFields
+ * Any additional fields associated with this menu option.
+ * @return Returns the number associated with menu choice.
+ */
+ public int addNumberedOption(Message description, MenuResult<T> result,
+ Message... extraFields) {
+ return addNumberedOption(description, new ResultCallback<T>(result),
+ extraFields);
+ }
+
+
+
+ /**
+ * Creates a "quit" menu option. When invoked, this option will
+ * return a {@link MenuResult#quit()} result.
+ */
+ public void addQuitOption() {
+ addCharOption(INFO_MENU_OPTION_QUIT_KEY.get(), INFO_MENU_OPTION_QUIT.get(),
+ MenuResult.<T> quit());
+ }
+
+
+
+ /**
+ * Sets the flag which indicates whether or not the menu will permit
+ * multiple numeric options to be selected at once. Users specify
+ * multiple choices by separating them with a comma. The default is
+ * <code>false</code>.
+ *
+ * @param allowMultiSelect
+ * Indicates whether or not the menu will permit multiple
+ * numeric options to be selected at once.
+ */
+ public void setAllowMultiSelect(boolean allowMultiSelect) {
+ this.allowMultiSelect = allowMultiSelect;
+ }
+
+
+
+ /**
+ * Sets the optional column headings. The column headings will be
+ * displayed above the menu options.
+ *
+ * @param headings
+ * The optional column headings.
+ */
+ public void setColumnHeadings(Message... headings) {
+ this.columnHeadings.clear();
+ if (headings != null) {
+ this.columnHeadings.addAll(Arrays.asList(headings));
+ }
+ }
+
+
+
+ /**
+ * Sets the optional column widths. A value of zero indicates that
+ * the column should be expandable, a value of <code>null</code>
+ * indicates that the column should use its default width.
+ *
+ * @param widths
+ * The optional column widths.
+ */
+ public void setColumnWidths(Integer... widths) {
+ this.columnWidths.clear();
+ if (widths != null) {
+ this.columnWidths.addAll(Arrays.asList(widths));
+ }
+ }
+
+
+
+ /**
+ * Sets the optional default action for this menu. The default
+ * action call-back will be invoked if the user does not specify an
+ * option and just presses enter.
+ *
+ * @param description
+ * A short description of the default action.
+ * @param callback
+ * The call-back associated with the default action.
+ */
+ public void setDefault(Message description, MenuCallback<T> callback) {
+ defaultCallback = callback;
+ defaultDescription = description;
+ }
+
+
+
+ /**
+ * Sets the optional default action for this menu. The default
+ * action call-back will be invoked if the user does not specify an
+ * option and just presses enter.
+ *
+ * @param description
+ * A short description of the default action.
+ * @param result
+ * The menu result which should be returned by default.
+ */
+ public void setDefault(Message description, MenuResult<T> result) {
+ setDefault(description, new ResultCallback<T>(result));
+ }
+
+
+
+ /**
+ * Sets the number of numeric options required to trigger
+ * multiple-column display. A negative value (the default) indicates
+ * that the numeric options will always be displayed in a single
+ * column. A value of 0 indicates that numeric options will always
+ * be displayed in multiple columns.
+ *
+ * @param threshold
+ * The number of numeric options required to trigger
+ * multiple-column display.
+ */
+ public void setMultipleColumnThreshold(int threshold) {
+ this.threshold = threshold;
+ }
+
+
+
+ /**
+ * Sets the optional menu prompt. The prompt will be displayed above
+ * the menu. Menus do not have a prompt by default.
+ *
+ * @param prompt
+ * The menu prompt, or <code>null</code> if there is not
+ * prompt.
+ */
+ public void setPrompt(Message prompt) {
+ this.prompt = prompt;
+ }
+
+
+
+ /**
+ * Sets the optional menu title. The title will be displayed above
+ * the menu prompt. Menus do not have a title by default.
+ *
+ * @param title
+ * The menu title, or <code>null</code> if there is not
+ * title.
+ */
+ public void setTitle(Message title) {
+ this.title = title;
+ }
+
+
+
+ /**
+ * Creates a menu from this menu builder.
+ *
+ * @return Returns the new menu.
+ */
+ public Menu<T> toMenu() {
+ TableBuilder nbuilder = new TableBuilder();
+ Map<String, MenuCallback<T>> callbacks =
+ new HashMap<String, MenuCallback<T>>();
+
+ // Determine whether multiple columns should be used for numeric
+ // options.
+ boolean useMultipleColumns = false;
+ if (threshold >= 0 && numericCallbacks.size() >= threshold) {
+ useMultipleColumns = true;
+ }
+
+ // Create optional column headers.
+ if (!columnHeadings.isEmpty()) {
+ nbuilder.appendHeading();
+ nbuilder.appendHeading();
+ for (Message heading : columnHeadings) {
+ if (heading != null) {
+ nbuilder.appendHeading(heading);
+ } else {
+ nbuilder.appendHeading();
+ }
+ }
+
+ if (useMultipleColumns) {
+ nbuilder.appendHeading();
+ for (Message heading : columnHeadings) {
+ if (heading != null) {
+ nbuilder.appendHeading(heading);
+ } else {
+ nbuilder.appendHeading();
+ }
+ }
+ }
+ }
+
+ // Add the numeric options first.
+ int sz = numericCallbacks.size();
+ int rows = sz;
+
+ if (useMultipleColumns) {
+ // Display in two columns the first column should contain half
+ // the options. If there are an odd number of columns then the
+ // first column should contain an additional option (e.g. if
+ // there are 23 options, the first column should contain 12
+ // options and the second column 11 options).
+ rows /= 2;
+ rows += sz % 2;
+ }
+
+ for (int i = 0, j = rows; i < rows; i++, j++) {
+ nbuilder.startRow();
+ nbuilder.appendCell();
+ nbuilder.appendCell(INFO_MENU_NUMERIC_OPTION.get(i + 1));
+
+ for (Message field : numericFields.get(i)) {
+ if (field != null) {
+ nbuilder.appendCell(field);
+ } else {
+ nbuilder.appendCell();
+ }
+ }
+
+ callbacks.put(String.valueOf(i + 1), numericCallbacks.get(i));
+
+ // Second column.
+ if (useMultipleColumns && (j < sz)) {
+ nbuilder.appendCell(INFO_MENU_NUMERIC_OPTION.get(j + 1));
+
+ for (Message field : numericFields.get(j)) {
+ if (field != null) {
+ nbuilder.appendCell(field);
+ } else {
+ nbuilder.appendCell();
+ }
+ }
+
+ callbacks.put(String.valueOf(j + 1), numericCallbacks.get(j));
+ }
+ }
+
+ // Add the char options last.
+ TableBuilder cbuilder = new TableBuilder();
+ for (int i = 0; i < charCallbacks.size(); i++) {
+ char c = charKeys.get(i).charAt(0);
+ Message option = INFO_MENU_CHAR_OPTION.get(c);
+
+ cbuilder.startRow();
+ cbuilder.appendCell();
+ cbuilder.appendCell(option);
+ cbuilder.appendCell(charSynopsis.get(i));
+
+ callbacks.put(String.valueOf(c), charCallbacks.get(i));
+ }
+
+ // Configure the table printer.
+ TextTablePrinter printer = new TextTablePrinter(app.getErrorStream());
+
+ if (columnHeadings.isEmpty()) {
+ printer.setDisplayHeadings(false);
+ } else {
+ printer.setDisplayHeadings(true);
+ }
+
+ printer.setColumnWidth(0, 2);
+ if (columnWidths.isEmpty()) {
+ printer.setColumnWidth(2, 0);
+ if (useMultipleColumns) {
+ printer.setColumnWidth(4, 0);
+ }
+ } else {
+ for (int i = 0; i < columnWidths.size(); i++) {
+ Integer j = columnWidths.get(i);
+ if (j != null) {
+ // Skip the option key column.
+ printer.setColumnWidth(i + 2, j);
+
+ if (useMultipleColumns) {
+ printer.setColumnWidth(i + 3 + columnWidths.size(), j);
+ }
+ }
+ }
+ }
+
+ return new MenuImpl<T>(app, title, prompt, nbuilder, cbuilder, printer,
+ callbacks, allowMultiSelect, defaultCallback, defaultDescription);
+ }
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/HelpCallback.java b/opends/src/server/org/opends/server/util/cli/MenuCallback.java
similarity index 60%
copy from opends/src/server/org/opends/server/tools/dsconfig/HelpCallback.java
copy to opends/src/server/org/opends/server/util/cli/MenuCallback.java
index 8412933..d26ed45 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/HelpCallback.java
+++ b/opends/src/server/org/opends/server/util/cli/MenuCallback.java
@@ -24,20 +24,29 @@
*
* Portions Copyright 2007 Sun Microsystems, Inc.
*/
-package org.opends.server.tools.dsconfig;
+package org.opends.server.util.cli;
/**
- * An interface for displaying help interactively.
+ * A menu call-back which should be associated with each menu option.
+ * When an option is selected the call-back is invoked.
+ *
+ * @param <T>
+ * The type of success result value(s) returned by the
+ * call-back. Use <code>Void</code> if the call-backs do
+ * not return any values.
*/
-interface HelpCallback {
+public interface MenuCallback<T> {
/**
- * Displays help to the provided application console.
+ * Invoke the menu call-back.
*
* @param app
- * The console application.
+ * The application console.
+ * @return Returns the result of invoking the menu call-back.
+ * @throws CLIException
+ * If the menu call-back fails for some reason.
*/
- void display(ConsoleApplication app);
+ MenuResult<T> invoke(ConsoleApplication app) throws CLIException;
}
diff --git a/opends/src/server/org/opends/server/util/cli/MenuResult.java b/opends/src/server/org/opends/server/util/cli/MenuResult.java
new file mode 100644
index 0000000..a5c7ca5
--- /dev/null
+++ b/opends/src/server/org/opends/server/util/cli/MenuResult.java
@@ -0,0 +1,324 @@
+/*
+ * 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.util.cli;
+
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+
+
+/**
+ * The result of running a {@link Menu}. The result indicates to the
+ * application how it should proceed:
+ * <ul>
+ * <li>{@link #again()} - the menu should be displayed again. A good
+ * example of this is when a user chooses to view some help. Normally,
+ * after the help is displayed, the user is allowed to select another
+ * option
+ * <li>{@link #cancel()} - the user chose to cancel any task
+ * currently in progress and go back to the previous main menu if
+ * applicable
+ * <li>{@link #success()} - the user chose to apply any task
+ * currently in progress and go back to the previous menu if
+ * applicable. Any result values applicable to the chosen option can
+ * be retrieved using {@link #getValue()} or {@link #getValues()}
+ * <li>{@link #quit()} - the user chose to quit the application and
+ * cancel all outstanding tasks.
+ * </ul>
+ *
+ * @param <T>
+ * The type of result value(s) contained in success results.
+ * Use <code>Void</code> if success results should not
+ * contain values.
+ */
+public final class MenuResult<T> {
+
+ /**
+ * The type of result returned from the menu.
+ */
+ private static enum Type {
+ /**
+ * The user selected an option which did not return a result, so
+ * the menu should be displayed again.
+ */
+ AGAIN,
+
+ /**
+ * The user did not select an option and instead chose to cancel
+ * the current task.
+ */
+ CANCEL,
+
+ /**
+ * The user did not select an option and instead chose to quit the
+ * entire application.
+ */
+ QUIT,
+
+ /**
+ * The user selected an option which succeeded and returned one or
+ * more result values.
+ */
+ SUCCESS
+ }
+
+
+
+ /**
+ * Creates a new menu result indicating that the menu should be
+ * displayed again. A good example of this is when a user chooses to
+ * view some help. Normally, after the help is displayed, the user
+ * is allowed to select another option.
+ *
+ * @param <T>
+ * The type of result value(s) contained in success
+ * results. Use <code>Void</code> if success results
+ * should not contain values.
+ * @return Returns a new menu result indicating that the menu should
+ * be displayed again.
+ */
+ public static <T> MenuResult<T> again() {
+ return new MenuResult<T>(Type.AGAIN, Collections.<T> emptyList());
+ }
+
+
+
+ /**
+ * Creates a new menu result indicating that the user chose to
+ * cancel any task currently in progress and go back to the previous
+ * main menu if applicable.
+ *
+ * @param <T>
+ * The type of result value(s) contained in success
+ * results. Use <code>Void</code> if success results
+ * should not contain values.
+ * @return Returns a new menu result indicating that the user chose
+ * to cancel any task currently in progress and go back to
+ * the previous main menu if applicable.
+ */
+ public static <T> MenuResult<T> cancel() {
+ return new MenuResult<T>(Type.CANCEL, Collections.<T> emptyList());
+ }
+
+
+
+ /**
+ * Creates a new menu result indicating that the user chose to quit
+ * the application and cancel all outstanding tasks.
+ *
+ * @param <T>
+ * The type of result value(s) contained in success
+ * results. Use <code>Void</code> if success results
+ * should not contain values.
+ * @return Returns a new menu result indicating that the user chose
+ * to quit the application and cancel all outstanding tasks.
+ */
+ public static <T> MenuResult<T> quit() {
+ return new MenuResult<T>(Type.QUIT, Collections.<T> emptyList());
+ }
+
+
+
+ /**
+ * Creates a new menu result indicating that the user chose to apply
+ * any task currently in progress and go back to the previous menu
+ * if applicable. The menu result will not contain any result
+ * values.
+ *
+ * @param <T>
+ * The type of result value(s) contained in success
+ * results. Use <code>Void</code> if success results
+ * should not contain values.
+ * @return Returns a new menu result indicating that the user chose
+ * to apply any task currently in progress and go back to
+ * the previous menu if applicable.The menu result will not
+ * contain any result values.
+ */
+ public static <T> MenuResult<T> success() {
+ return success(Collections.<T> emptySet());
+ }
+
+
+
+ /**
+ * Creates a new menu result indicating that the user chose to apply
+ * any task currently in progress and go back to the previous menu
+ * if applicable. The menu result will contain the provided values,
+ * which can be retrieved using {@link #getValue()} or
+ * {@link #getValues()}.
+ *
+ * @param <T>
+ * The type of the result values.
+ * @param values
+ * The result values.
+ * @return Returns a new menu result indicating that the user chose
+ * to apply any task currently in progress and go back to
+ * the previous menu if applicable. The menu result will
+ * contain the provided values, which can be retrieved using
+ * {@link #getValue()} or {@link #getValues()}.
+ */
+ public static <T> MenuResult<T> success(Collection<T> values) {
+ return new MenuResult<T>(Type.SUCCESS, new ArrayList<T>(values));
+ }
+
+
+
+ /**
+ * Creates a new menu result indicating that the user chose to apply
+ * any task currently in progress and go back to the previous menu
+ * if applicable. The menu result will contain the provided value,
+ * which can be retrieved using {@link #getValue()} or
+ * {@link #getValues()}.
+ *
+ * @param <T>
+ * The type of the result value.
+ * @param value
+ * The result value.
+ * @return Returns a new menu result indicating that the user chose
+ * to apply any task currently in progress and go back to
+ * the previous menu if applicable. The menu result will
+ * contain the provided value, which can be retrieved using
+ * {@link #getValue()} or {@link #getValues()}.
+ */
+ public static <T> MenuResult<T> success(T value) {
+ return success(Collections.singleton(value));
+ }
+
+ // The type of result returned from the menu.
+ private final Type type;
+
+ // The menu result value(s).
+ private final Collection<T> values;
+
+
+
+ // Private constructor.
+ private MenuResult(Type type, Collection<T> values) {
+ this.type = type;
+ this.values = values;
+ }
+
+
+
+ /**
+ * Gets the menu result value if this is a menu result indicating
+ * success.
+ *
+ * @return Returns the menu result value, or <code>null</code> if
+ * there was no result value or if this is not a success
+ * menu result.
+ * @see #isSuccess()
+ */
+ public T getValue() {
+ if (values.isEmpty()) {
+ return null;
+ } else {
+ return values.iterator().next();
+ }
+ }
+
+
+
+ /**
+ * Gets the menu result values if this is a menu result indicating
+ * success.
+ *
+ * @return Returns the menu result values, which may be empty if
+ * there were no result values or if this is not a success
+ * menu result.
+ * @see #isSuccess()
+ */
+ public Collection<T> getValues() {
+ return new ArrayList<T>(values);
+ }
+
+
+
+ /**
+ * Determines if this menu result indicates that the menu should be
+ * displayed again. A good example of this is when a user chooses to
+ * view some help. Normally, after the help is displayed, the user
+ * is allowed to select another option.
+ *
+ * @return Returns <code>true</code> if this menu result indicates
+ * that the menu should be displayed again.
+ */
+ public boolean isAgain() {
+ return type == Type.AGAIN;
+ }
+
+
+
+ /**
+ * Determines if this menu result indicates that the user chose to
+ * cancel any task currently in progress and go back to the previous
+ * main menu if applicable.
+ *
+ * @return Returns <code>true</code> if this menu result indicates
+ * that the user chose to cancel any task currently in
+ * progress and go back to the previous main menu if
+ * applicable.
+ */
+ public boolean isCancel() {
+ return type == Type.CANCEL;
+ }
+
+
+
+ /**
+ * Determines if this menu result indicates that the user chose to
+ * quit the application and cancel all outstanding tasks.
+ *
+ * @return Returns <code>true</code> if this menu result indicates
+ * that the user chose to quit the application and cancel
+ * all outstanding tasks.
+ */
+ public boolean isQuit() {
+ return type == Type.QUIT;
+ }
+
+
+
+ /**
+ * Determines if this menu result indicates that the user chose to
+ * apply any task currently in progress and go back to the previous
+ * menu if applicable. Any result values can be retrieved using the
+ * {@link #getValue()} or {@link #getValues()} methods.
+ *
+ * @return Returns <code>true</code> if this menu result indicates
+ * that the user chose to apply any task currently in
+ * progress and go back to the previous menu if applicable.
+ * @see #getValue()
+ * @see #getValues()
+ */
+ public boolean isSuccess() {
+ return type == Type.SUCCESS;
+ }
+}
diff --git a/opends/src/server/org/opends/server/util/cli/OutputStreamConsoleApplication.java b/opends/src/server/org/opends/server/util/cli/OutputStreamConsoleApplication.java
new file mode 100644
index 0000000..e0aa77a
--- /dev/null
+++ b/opends/src/server/org/opends/server/util/cli/OutputStreamConsoleApplication.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.util.cli;
+
+
+
+/**
+ * A console application decorator which redirects all output to the
+ * underlying application's output stream.
+ */
+public class OutputStreamConsoleApplication extends ConsoleApplication {
+
+ // The underlying console application.
+ private final ConsoleApplication app;
+
+
+
+ /**
+ * Creates a new console application instance which redirects all
+ * output to the underlying application's output stream.
+ *
+ * @param app
+ * The underlying application console.
+ */
+ public OutputStreamConsoleApplication(ConsoleApplication app) {
+ super(app.getInputStream(), app.getOutputStream(), app.getOutputStream());
+
+ this.app = app;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isInteractive() {
+ return app.isInteractive();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isMenuDrivenMode() {
+ return app.isMenuDrivenMode();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isQuiet() {
+ return app.isQuiet();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isScriptFriendly() {
+ return app.isScriptFriendly();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isVerbose() {
+ return app.isVerbose();
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/ValidationCallback.java b/opends/src/server/org/opends/server/util/cli/ValidationCallback.java
similarity index 88%
rename from opends/src/server/org/opends/server/tools/dsconfig/ValidationCallback.java
rename to opends/src/server/org/opends/server/util/cli/ValidationCallback.java
index a8f7750..cefe601 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/ValidationCallback.java
+++ b/opends/src/server/org/opends/server/util/cli/ValidationCallback.java
@@ -24,9 +24,7 @@
*
* Portions Copyright 2007 Sun Microsystems, Inc.
*/
-package org.opends.server.tools.dsconfig;
-
-import org.opends.server.tools.ClientException;
+package org.opends.server.util.cli;
@@ -36,7 +34,7 @@
* @param <T>
* The type of the decoded input.
*/
-interface ValidationCallback<T> {
+public interface ValidationCallback<T> {
/**
* Validates and decodes the user-provided input. Implementations
@@ -51,9 +49,9 @@
* The user input to be validated.
* @return Returns the decoded input if the input is valid, or
* <code>null</code> if it is not.
- * @throws ClientException
+ * @throws CLIException
* If an unexpected error occurred which prevented
* validation.
*/
- T validate(ConsoleApplication app, String input) throws ClientException;
+ T validate(ConsoleApplication app, String input) throws CLIException;
}
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/HelpCallback.java b/opends/src/server/org/opends/server/util/cli/package-info.java
similarity index 60%
copy from opends/src/server/org/opends/server/tools/dsconfig/HelpCallback.java
copy to opends/src/server/org/opends/server/util/cli/package-info.java
index 8412933..0d8f7ac 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/HelpCallback.java
+++ b/opends/src/server/org/opends/server/util/cli/package-info.java
@@ -22,22 +22,23 @@
* CDDL HEADER END
*
*
- * Portions Copyright 2007 Sun Microsystems, Inc.
+ * Portions Copyright 2006-2007 Sun Microsystems, Inc.
*/
-package org.opends.server.tools.dsconfig;
-
-
/**
- * An interface for displaying help interactively.
+ * Provides a high-level framework for implementing command-line
+ * tools.
+ * <p>
+ * The {@link ConsoleApplication} interface can be used as a basis for
+ * console based applications. It includes common utility methods for
+ * interacting with the console.
+ * <p>
+ * The {@link MenuBuilder} and associated classes and interfaces can
+ * be used to implement text based menu driven applications.
*/
-interface HelpCallback {
+@org.opends.server.types.PublicAPI(
+ stability = org.opends.server.types.StabilityLevel.PRIVATE)
+package org.opends.server.util.cli;
- /**
- * Displays help to the provided application console.
- *
- * @param app
- * The console application.
- */
- void display(ConsoleApplication app);
-}
+
+
--
Gitblit v1.10.0