From 9e4f312fe9c0820638503b40b5fcbb6571e23354 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Fri, 27 Jul 2007 17:29:33 +0000
Subject: [PATCH] Partial 95% fix for issue 1831 - dsconfig interactive mode.
---
opends/src/server/org/opends/server/messages/ToolMessages.java | 101 +++++++
opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java | 35 ++
opends/src/server/org/opends/server/tools/dsconfig/PropertyValueReader.java | 623 ++++++++++++++++++++++++++++++++++++++++++++
opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java | 34 ++
4 files changed, 789 insertions(+), 4 deletions(-)
diff --git a/opends/src/server/org/opends/server/messages/ToolMessages.java b/opends/src/server/org/opends/server/messages/ToolMessages.java
index aa7f8c1..eb08e12 100644
--- a/opends/src/server/org/opends/server/messages/ToolMessages.java
+++ b/opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -9379,11 +9379,88 @@
CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1239;
/**
+ * The message ID for the message that will be used in the property
+ * editing menu for resetting.
+ */
+ public static final int MSGID_DSCFG_VALUE_READER_MENU_RESET =
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1240;
+
+ /**
+ * The message ID for the message that will be used in the property
+ * editing menu for setting a value.
+ */
+ public static final int MSGID_DSCFG_VALUE_READER_MENU_SET =
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1241;
+
+ /**
+ * The message ID for the message that will be used in the property
+ * editing menu for adding a value.
+ */
+ public static final int MSGID_DSCFG_VALUE_READER_MENU_ADD =
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1242;
+
+ /**
+ * The message ID for the message that will be used in the property
+ * editing menu for removing a value.
+ */
+ public static final int MSGID_DSCFG_VALUE_READER_MENU_REMOVE =
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1243;
+
+ /**
+ * The message ID for the message that will be used in the property
+ * editing menu for the continue option.
+ */
+ public static final int MSGID_DSCFG_VALUE_READER_MENU_CONTINUE =
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1244;
+
+ /**
+ * The message ID for the message that will be used in the property
+ * editor as the prompt for removing a value.
+ */
+ public static final int MSGID_DSCFG_VALUE_READER_PROMPT_REMOVE =
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1245;
+
+ /**
+ * The message ID for the message that will be used in the property
+ * editor as the prompt for selecting a value.
+ */
+ public static final int MSGID_DSCFG_VALUE_READER_PROMPT_SELECT_VALUE =
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1246;
+
+ /**
+ * The message ID for the message that will be used in the property
+ * editor as the prompt for entering a value.
+ */
+ public static final int MSGID_DSCFG_VALUE_READER_PROMPT_ENTER_VALUE =
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1247;
+
+ /**
+ * The message ID for the message that will be used in the property
+ * editor as the title prompt for the property selection menu.
+ */
+ public static final int MSGID_DSCFG_VALUE_READER_MENU_TITLE =
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1248;
+
+ /**
+ * The message ID for the message that will be used in the property
+ * editor as the prompt for mandatory properties.
+ */
+ public static final int MSGID_DSCFG_VALUE_READER_PROMPT_MANDATORY =
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1249;
+
+ /**
+ * The message ID for the message that will be used in the property
+ * editor as the prompt for property modification menu.
+ */
+ public static final int MSGID_DSCFG_VALUE_READER_PROMPT_MODIFY_MENU =
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1250;
+
+ /**
* The message ID for the message that will be used as the description of the
* clearBackend argument. This does not take any arguments.
*/
public static final int MSGID_LDIFIMPORT_DESCRIPTION_CLEAR_BACKEND =
- CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1240;
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1251;
/**
* The message ID for the message that will be used if neither the
@@ -9392,7 +9469,7 @@
* includeBranchStrings and backendID options.
*/
public static final int MSGID_LDIFIMPORT_MISSING_BACKEND_ARGUMENT =
- CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1241;
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1252;
/**
@@ -9402,7 +9479,7 @@
* option as an argument.
*/
public static final int MSGID_LDIFIMPORT_MISSING_CLEAR_BACKEND =
- CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1242;
+ CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1253;
/**
* Associates a set of generic messages with the message IDs defined in this
@@ -12432,6 +12509,24 @@
"Invalid response. Please enter a value between 1 and %s");
registerMessage(MSGID_DSCFG_ERROR_GENERAL_CONFIRM,
"Invalid response. Please enter \"%s\" or \"%s\"");
+ registerMessage(MSGID_DSCFG_VALUE_READER_MENU_ADD, "add a value");
+ registerMessage(MSGID_DSCFG_VALUE_READER_MENU_REMOVE, "remove a value");
+ registerMessage(MSGID_DSCFG_VALUE_READER_MENU_SET, "modify the value");
+ registerMessage(MSGID_DSCFG_VALUE_READER_MENU_RESET,
+ "reset the value back to its default");
+ registerMessage(MSGID_DSCFG_VALUE_READER_MENU_CONTINUE, "continue");
+ registerMessage(MSGID_DSCFG_VALUE_READER_PROMPT_REMOVE,
+ "Select the value to be removed from the \"%s\" property:");
+ registerMessage(MSGID_DSCFG_VALUE_READER_PROMPT_SELECT_VALUE,
+ "Select a value for the \"%s\" property:");
+ registerMessage(MSGID_DSCFG_VALUE_READER_PROMPT_ENTER_VALUE,
+ "Enter a value for the \"%s\" property:");
+ registerMessage(MSGID_DSCFG_VALUE_READER_MENU_TITLE,
+ "Select a property to be edited, or enter \"%d\" to continue:");
+ registerMessage(MSGID_DSCFG_VALUE_READER_PROMPT_MANDATORY,
+ "The property \"%s\" is mandatory and must have a value specified");
+ registerMessage(MSGID_DSCFG_VALUE_READER_PROMPT_MODIFY_MENU,
+ "Do you want to modify the \"%s\" property?");
registerMessage(MSGID_LDIFIMPORT_DESCRIPTION_CLEAR_BACKEND,
"Remove all entries for all base DNs in the backend " +
"before importing");
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 da46c18..489d4fc 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
@@ -40,7 +40,9 @@
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
+import java.util.SortedSet;
import java.util.TreeMap;
+import java.util.TreeSet;
import org.opends.server.admin.AbstractManagedObjectDefinition;
import org.opends.server.admin.Configuration;
@@ -407,6 +409,10 @@
// Create the naming arguments.
this.namingArgs = createNamingArgs(subCommand, c, true);
+ // Register common arguments.
+ registerAdvancedModeArgument(this.subCommand,
+ MSGID_DSCFG_DESCRIPTION_ADVANCED_SET, r.getUserFriendlyName());
+
// Create the --property argument which is used to specify
// property values.
this.propertySetArgument = new StringArgument(OPTION_DSCFG_LONG_SET,
@@ -588,6 +594,32 @@
setProperty(child, provider, pd);
}
+ // Interactively set properties if applicable.
+ if (getConsoleApplication().isInteractive()) {
+ SortedSet<PropertyDefinition<?>> properties =
+ new TreeSet<PropertyDefinition<?>>();
+
+ for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
+ if (pd.hasOption(PropertyOption.HIDDEN)) {
+ continue;
+ }
+
+ if (pd.hasOption(PropertyOption.MONITORING)) {
+ continue;
+ }
+
+ if (!isAdvancedMode() && pd.hasOption(PropertyOption.ADVANCED)) {
+ continue;
+ }
+
+ properties.add(pd);
+ }
+
+ PropertyValueReader reader =
+ new PropertyValueReader(getConsoleApplication());
+ reader.readAll(child, properties);
+ }
+
// Confirm commit.
String prompt = String.format(Messages.getString("create.confirm"), d
.getUserFriendlyName());
@@ -649,7 +681,7 @@
final List<DefaultBehaviorException> exceptions)
throws ArgumentException, ClientException {
int msgID = MSGID_DSCFG_CREATE_NAME_PROMPT;
- String msg = getMessage(msgID, relation.getUserFriendlyName());
+ String msg = getMessage(msgID, d.getUserFriendlyName());
ValidationCallback<ManagedObject<? extends C>> validator =
new ValidationCallback<ManagedObject<? extends C>>() {
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/PropertyValueReader.java b/opends/src/server/org/opends/server/tools/dsconfig/PropertyValueReader.java
new file mode 100644
index 0000000..7881af0
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/dsconfig/PropertyValueReader.java
@@ -0,0 +1,623 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.tools.dsconfig;
+
+
+
+import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.ToolMessages.*;
+
+import java.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) {
+ HelpSubCommandHandler help = HelpSubCommandHandler.getInstance();
+ app.println();
+ help.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<String> descriptions = new ArrayList<String>(values.size());
+ List<T> lvalues = new ArrayList<T>(values.size());
+
+ for (T value : values) {
+ descriptions.add(printer.print(pd, value));
+ lvalues.add(value);
+ }
+
+ String promptMsg =
+ getMessage(MSGID_DSCFG_VALUE_READER_PROMPT_REMOVE, 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"
+ });
+ try {
+ String promptMsg = getMessage(
+ MSGID_DSCFG_VALUE_READER_PROMPT_SELECT_VALUE, d.getName());
+ return app.readChoice(promptMsg, values, 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> descriptions = new ArrayList<String>(map.values());
+ List<String> values = new ArrayList<String>(map.keySet());
+ try {
+ String promptMsg = getMessage(
+ MSGID_DSCFG_VALUE_READER_PROMPT_SELECT_VALUE, 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 {
+ String promptMsg = getMessage(
+ MSGID_DSCFG_VALUE_READER_PROMPT_ENTER_VALUE, 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(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(getMessage(MSGID_DSCFG_HEADING_PROPERTY_NAME));
+ builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_PROPERTY_VALUE));
+
+ int i = 0;
+ List<PropertyDefinition<?>> pl = new ArrayList<PropertyDefinition<?>>(c);
+ for (PropertyDefinition<?> pd : pl) {
+ builder.startRow();
+ builder.appendCell("[" + i + "]");
+ builder.appendCell(pd.getName());
+
+ String values = getPropertyValuesAsString(mo, pd, valuePrinter);
+ builder.appendCell(values);
+ i++;
+ }
+
+ builder.startRow();
+ builder.startRow();
+ builder.appendCell("[" + i + "]");
+ builder.appendCell(getMessage(MSGID_DSCFG_VALUE_READER_MENU_CONTINUE));
+
+ // Display the menu.
+ app.println();
+ app.printMessage(getMessage(MSGID_DSCFG_VALUE_READER_MENU_TITLE, i));
+ app.println();
+
+ TextTablePrinter printer = new TextTablePrinter(app.getErrorStream());
+ printer.setColumnWidth(2, 0);
+ builder.print(printer);
+
+ // Get the user input.
+ final int size = i;
+ String promptMsg =
+ getMessage(MSGID_DSCFG_GENERAL_CHOICE_PROMPT_NOHELP, 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();
+ String errMsg = getMessage(MSGID_DSCFG_ERROR_GENERAL_CHOICE, 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();
+ String promptMsg = getMessage(
+ MSGID_DSCFG_VALUE_READER_PROMPT_MANDATORY, 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<String> descriptions = new ArrayList<String>();
+ List<MenuCallback> callbacks = new ArrayList<MenuCallback>();
+
+ if (pd.hasOption(PropertyOption.MULTI_VALUED)) {
+ descriptions.add(getMessage(MSGID_DSCFG_VALUE_READER_MENU_ADD));
+ callbacks.add(new AddValueMenuCallback());
+
+ if (!mo.getPropertyValues(pd).isEmpty()) {
+ descriptions.add(getMessage(MSGID_DSCFG_VALUE_READER_MENU_REMOVE));
+ callbacks.add(new RemoveValueMenuCallback());
+ }
+ } else {
+ descriptions.add(getMessage(MSGID_DSCFG_VALUE_READER_MENU_SET));
+ callbacks.add(new SetValueMenuCallback());
+ }
+
+ if (!pd.hasOption(PropertyOption.MANDATORY)
+ || !(pd.getDefaultBehaviorProvider()
+ instanceof UndefinedDefaultBehaviorProvider)) {
+ descriptions.add(getMessage(MSGID_DSCFG_VALUE_READER_MENU_RESET));
+ callbacks.add(new ResetValueMenuCallback());
+ }
+
+ descriptions.add(getMessage(MSGID_DSCFG_VALUE_READER_MENU_CONTINUE));
+ callbacks.add(null);
+
+ // FIXME: display current values of the property.
+ String promptMsg = getMessage(
+ MSGID_DSCFG_VALUE_READER_PROMPT_MODIFY_MENU, 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> String 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, String, Void> visitor =
+ new DefaultBehaviorProviderVisitor<T, String, Void>() {
+
+ public String visitAbsoluteInherited(
+ AbsoluteInheritedDefaultBehaviorProvider<T> d, Void p) {
+ // Should not happen - inherited default values are
+ // displayed as normal values.
+ throw new IllegalStateException();
+ }
+
+
+
+ public String visitAlias(AliasDefaultBehaviorProvider<T> d, Void p) {
+ if (app.isVerbose()) {
+ return d.getSynopsis();
+ } else {
+ return null;
+ }
+ }
+
+
+
+ public String visitDefined(
+ DefinedDefaultBehaviorProvider<T> d, Void p) {
+ // Should not happen - real default values are displayed as
+ // normal values.
+ throw new IllegalStateException();
+ }
+
+
+
+ public String visitRelativeInherited(
+ RelativeInheritedDefaultBehaviorProvider<T> d, Void p) {
+ // Should not happen - inherited default values are
+ // displayed as normal values.
+ throw new IllegalStateException();
+ }
+
+
+
+ public String visitUndefined(UndefinedDefaultBehaviorProvider<T> d,
+ Void p) {
+ return null;
+ }
+ };
+
+ String content = pd.getDefaultBehaviorProvider().accept(visitor, null);
+ if (content == null) {
+ return "-";
+ } else {
+ return content;
+ }
+ } else {
+ StringBuilder sb = new StringBuilder();
+ boolean isFirst = true;
+ for (T value : values) {
+ if (!isFirst) {
+ sb.append(", ");
+ }
+ sb.append(valuePrinter.print(pd, value));
+ isFirst = false;
+ }
+
+ return sb.toString();
+ }
+ }
+}
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 7a99ff4..46ceafa 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/SetPropSubCommandHandler.java
@@ -35,6 +35,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.SortedSet;
import java.util.TreeSet;
import org.opends.server.admin.DefinitionDecodingException;
@@ -250,6 +251,10 @@
// Create the naming arguments.
this.namingArgs = createNamingArgs(subCommand, path, false);
+ // Register common arguments.
+ registerAdvancedModeArgument(this.subCommand,
+ MSGID_DSCFG_DESCRIPTION_ADVANCED_SET, r.getUserFriendlyName());
+
// Create the --set argument.
this.propertySetArgument = new StringArgument(OPTION_DSCFG_LONG_SET,
OPTION_DSCFG_SHORT_SET, OPTION_DSCFG_LONG_SET, false, true, true,
@@ -494,6 +499,36 @@
}
}
+ // Interactively set properties if applicable.
+ if (getConsoleApplication().isInteractive()) {
+ SortedSet<PropertyDefinition<?>> properties =
+ new TreeSet<PropertyDefinition<?>>();
+
+ for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
+ if (pd.hasOption(PropertyOption.HIDDEN)) {
+ continue;
+ }
+
+ if (pd.hasOption(PropertyOption.READ_ONLY)) {
+ continue;
+ }
+
+ if (pd.hasOption(PropertyOption.MONITORING)) {
+ continue;
+ }
+
+ if (!isAdvancedMode() && pd.hasOption(PropertyOption.ADVANCED)) {
+ continue;
+ }
+
+ properties.add(pd);
+ }
+
+ PropertyValueReader reader =
+ new PropertyValueReader(getConsoleApplication());
+ reader.readAll(child, properties);
+ }
+
try {
// Confirm commit.
String prompt = String.format(Messages.getString("modify.confirm"), d
--
Gitblit v1.10.0