From 54c2799f45256fef4a981fa2a6a7c97a9708ac8b Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Thu, 26 Jul 2007 12:01:44 +0000
Subject: [PATCH] Partial fix for issue 1831 - dsconfig interactive mode.
---
opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java | 278 +++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 228 insertions(+), 50 deletions(-)
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 f5944e3..3c3034c 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
@@ -31,7 +31,7 @@
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.messages.ToolMessages.*;
-import java.io.PrintStream;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -43,6 +43,7 @@
import java.util.TreeMap;
import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.Configuration;
import org.opends.server.admin.ConfigurationClient;
import org.opends.server.admin.DefaultBehaviorException;
import org.opends.server.admin.DefinitionDecodingException;
@@ -65,7 +66,6 @@
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;
@@ -74,6 +74,8 @@
import org.opends.server.util.args.StringArgument;
import org.opends.server.util.args.SubCommand;
import org.opends.server.util.args.SubCommandArgumentParser;
+import org.opends.server.util.table.TableBuilder;
+import org.opends.server.util.table.TextTablePrinter;
@@ -84,9 +86,12 @@
*
* @param <C>
* The type of managed object which can be created.
+ * @param <S>
+ * The type of server managed object which can be created.
*/
-final class CreateSubCommandHandler<C extends ConfigurationClient> extends
- SubCommandHandler {
+final class CreateSubCommandHandler<C extends ConfigurationClient,
+ S extends Configuration> extends SubCommandHandler {
+
/**
* A property provider which uses the command-line arguments to
@@ -95,8 +100,8 @@
private static class MyPropertyProvider implements PropertyProvider {
// Decoded set of properties.
- private final Map<PropertyDefinition, Collection> properties =
- new HashMap<PropertyDefinition, Collection>();
+ private final Map<PropertyDefinition<?>, Collection<?>> properties =
+ new HashMap<PropertyDefinition<?>, Collection<?>>();
@@ -162,7 +167,7 @@
* @return Returns the set of parsed property definitions that
* have values specified.
*/
- public Set<PropertyDefinition> getProperties() {
+ public Set<PropertyDefinition<?>> getProperties() {
return properties.keySet();
}
@@ -174,7 +179,7 @@
@SuppressWarnings("unchecked")
public <T> Collection<T> getPropertyValues(PropertyDefinition<T> d)
throws IllegalArgumentException {
- Collection<T> values = properties.get(d);
+ Collection<T> values = (Collection<T>) properties.get(d);
if (values == null) {
return Collections.emptySet();
} else {
@@ -195,7 +200,7 @@
throw ArgumentExceptionFactory.adaptPropertyException(e, d);
}
- Collection<T> values = properties.get(pd);
+ Collection<T> values = (Collection<T>) properties.get(pd);
if (values == null) {
values = new LinkedList<T>();
}
@@ -210,6 +215,53 @@
}
}
+
+
+ /**
+ * A help call-back which displays help about available component types.
+ */
+ private final class TypeHelpCallback implements HelpCallback {
+
+ /**
+ * {@inheritDoc}
+ */
+ public void display(ConsoleApplication app) {
+ // Create a table containing a description of each component type.
+ TableBuilder builder = new TableBuilder();
+
+ int msgID = MSGID_DSCFG_DESCRIPTION_CREATE_HELP_HEADING_TYPE;
+ builder.appendHeading(getMessage(msgID));
+
+ msgID = MSGID_DSCFG_DESCRIPTION_CREATE_HELP_HEADING_DESCR;
+ builder.appendHeading(getMessage(msgID));
+
+ boolean isFirst = true;
+ for (ManagedObjectDefinition<?, ?> d : types.values()) {
+ if (!isFirst) {
+ builder.startRow();
+ builder.startRow();
+ } else {
+ isFirst = false;
+ }
+
+ builder.startRow();
+ builder.appendCell(d.getUserFriendlyName());
+ builder.appendCell(d.getSynopsis());
+ if (d.getDescription() != null) {
+ builder.startRow();
+ builder.startRow();
+ builder.appendCell();
+ builder.appendCell(d.getDescription());
+ }
+ }
+
+ TextTablePrinter printer = new TextTablePrinter(app.getErrorStream());
+ printer.setColumnWidth(1, 0);
+ printer.setColumnSeparator(":");
+ builder.print(printer);
+ }
+ }
+
/**
* The value for the -t argument which will be used for the most
* generic managed object when it is instantiable.
@@ -244,6 +296,10 @@
*
* @param <C>
* 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
@@ -254,10 +310,12 @@
* @throws ArgumentException
* If the sub-command could not be created successfully.
*/
- public static <C extends ConfigurationClient> CreateSubCommandHandler create(
- SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
- InstantiableRelationDefinition<C, ?> r) throws ArgumentException {
- return new CreateSubCommandHandler<C>(parser, p, r, r
+ 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
.getNamingPropertyDefinition(), p.child(r, "DUMMY"));
}
@@ -268,6 +326,10 @@
*
* @param <C>
* 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
@@ -278,10 +340,13 @@
* @throws ArgumentException
* If the sub-command could not be created successfully.
*/
- public static <C extends ConfigurationClient> CreateSubCommandHandler create(
- SubCommandArgumentParser parser, ManagedObjectPath<?, ?> p,
- OptionalRelationDefinition<C, ?> r) throws ArgumentException {
- return new CreateSubCommandHandler<C>(parser, p, r, null, p.child(r));
+ 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));
}
// The sub-commands naming arguments.
@@ -298,7 +363,7 @@
private final StringArgument propertySetArgument;
// The relation which should be used for creating children.
- private final RelationDefinition<C, ?> relation;
+ private final RelationDefinition<C, S> relation;
// The sub-command associated with this handler.
private final SubCommand subCommand;
@@ -310,7 +375,7 @@
// The set of instantiable managed object definitions and their
// associated type option value.
private final SortedMap<String,
- ManagedObjectDefinition<? extends C, ?>> types;
+ ManagedObjectDefinition<? extends C, ? extends S>> types;
// The syntax of the type argument.
private final String typeUsage;
@@ -318,10 +383,13 @@
// Common constructor.
- private CreateSubCommandHandler(SubCommandArgumentParser parser,
- ManagedObjectPath<?, ?> p, RelationDefinition<C, ?> r,
+ private CreateSubCommandHandler(ConsoleApplication app,
+ SubCommandArgumentParser parser,
+ ManagedObjectPath<?, ?> p, RelationDefinition<C, S> r,
PropertyDefinition<?> pd, ManagedObjectPath<?, ?> c)
throws ArgumentException {
+ super(app);
+
this.path = p;
this.relation = r;
this.namingPropertyDefinition = pd;
@@ -359,9 +427,9 @@
this.typeUsage = builder.toString();
if (!types.containsKey(GENERIC_TYPE)) {
- // The option is mandatory.
+ // The option is mandatory when non-interactive.
this.typeArgument = new StringArgument("type", OPTION_DSCFG_SHORT_TYPE,
- OPTION_DSCFG_LONG_TYPE, true, false, true, "{TYPE}", null, null,
+ OPTION_DSCFG_LONG_TYPE, false, false, true, "{TYPE}", null, null,
MSGID_DSCFG_DESCRIPTION_TYPE, r.getChildDefinition()
.getUserFriendlyName(), typeUsage);
} else {
@@ -399,11 +467,40 @@
* {@inheritDoc}
*/
@Override
- public int run(DSConfig app, PrintStream out, PrintStream err)
- throws ArgumentException, ClientException {
+ public int run() throws ArgumentException, ClientException {
// Determine the type of managed object to be created.
- String typeName = typeArgument.getValue();
- ManagedObjectDefinition<? extends C, ?> d = types.get(typeName);
+ String typeName;
+
+ if (!typeArgument.isPresent()) {
+ if (getConsoleApplication().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<String> descriptions = new ArrayList<String>(values.size());
+ for (ManagedObjectDefinition<?, ?> d : types.values()) {
+ descriptions.add(d.getUserFriendlyName());
+ }
+ int msgID = MSGID_DSCFG_CREATE_TYPE_PROMPT;
+ String msg = getMessage(msgID, relation.getChildDefinition()
+ .getUserFriendlyName());
+ typeName = getConsoleApplication().readChoice(msg, descriptions,
+ values, new TypeHelpCallback());
+ }
+ } else if (typeArgument.getDefaultValue() != null) {
+ typeName = typeArgument.getDefaultValue();
+ } else {
+ throw ArgumentExceptionFactory
+ .missingMandatoryNonInteractiveArgument(typeArgument);
+ }
+ } else {
+ typeName = typeArgument.getValue();
+ }
+
+ ManagedObjectDefinition<? extends C, ? extends S> d = types.get(typeName);
if (d == null) {
throw ArgumentExceptionFactory.unknownSubType(relation, typeName,
typeUsage);
@@ -418,10 +515,9 @@
namingPropertyDefinition, propertyArgs);
// Add the child managed object.
- ManagementContext context = app.getManagementContext();
ManagedObject<?> parent;
try {
- parent = getManagedObject(context, path, names);
+ parent = getManagedObject(path, names);
} catch (AuthorizationException e) {
int msgID = MSGID_DSCFG_ERROR_CREATE_AUTHZ;
String msg = getMessage(msgID, d.getUserFriendlyName());
@@ -459,18 +555,28 @@
List<DefaultBehaviorException> exceptions =
new LinkedList<DefaultBehaviorException>();
if (relation instanceof InstantiableRelationDefinition) {
- InstantiableRelationDefinition<C, ?> irelation =
- (InstantiableRelationDefinition<C, ?>) relation;
+ InstantiableRelationDefinition<C, S> irelation =
+ (InstantiableRelationDefinition<C, S>) relation;
String name = names.get(names.size() - 1);
- try {
- child = parent.createChild(irelation, d, name, exceptions);
- } catch (IllegalManagedObjectNameException e) {
- throw ArgumentExceptionFactory
- .adaptIllegalManagedObjectNameException(e, d);
+ if (name == null) {
+ if (getConsoleApplication().isInteractive()) {
+ child = createChildInteractively(parent, irelation, d, exceptions);
+ } else {
+ throw ArgumentExceptionFactory
+ .missingMandatoryNonInteractiveArgument(namingArgs.get(names
+ .size() - 1));
+ }
+ } else {
+ try {
+ child = parent.createChild(irelation, d, name, exceptions);
+ } catch (IllegalManagedObjectNameException e) {
+ throw ArgumentExceptionFactory
+ .adaptIllegalManagedObjectNameException(e, d);
+ }
}
} else {
- OptionalRelationDefinition<C, ?> orelation =
- (OptionalRelationDefinition<C, ?>) relation;
+ OptionalRelationDefinition<C, S> orelation =
+ (OptionalRelationDefinition<C, S>) relation;
child = parent.createChild(orelation, d, exceptions);
}
@@ -485,11 +591,11 @@
// Confirm commit.
String prompt = String.format(Messages.getString("create.confirm"), d
.getUserFriendlyName());
- if (!app.confirmAction(prompt)) {
+ if (!getConsoleApplication().confirmAction(prompt)) {
// Output failure message.
String msg = String.format(Messages.getString("create.failed"), d
.getUserFriendlyName());
- app.displayVerboseMessage(msg);
+ getConsoleApplication().printVerboseMessage(msg);
return 1;
}
@@ -499,7 +605,7 @@
// Output success message.
String msg = String.format(Messages.getString("create.done"), d
.getUserFriendlyName());
- app.displayVerboseMessage(msg);
+ getConsoleApplication().printVerboseMessage(msg);
} catch (MissingMandatoryPropertiesException e) {
throw ArgumentExceptionFactory.adaptMissingMandatoryPropertiesException(
e, d);
@@ -535,28 +641,100 @@
+ // Interactively create the child by prompting for the name.
+ private ManagedObject<? extends C> createChildInteractively(
+ final ManagedObject<?> parent,
+ final InstantiableRelationDefinition<C, S> irelation,
+ final ManagedObjectDefinition<? extends C, ? extends S> d,
+ final List<DefaultBehaviorException> exceptions)
+ throws ArgumentException, ClientException {
+ int msgID = MSGID_DSCFG_CREATE_NAME_PROMPT;
+ String msg = getMessage(msgID, relation.getUserFriendlyName());
+ ValidationCallback<ManagedObject<? extends C>> validator =
+ new ValidationCallback<ManagedObject<? extends C>>() {
+
+ public ManagedObject<? extends C> validate(ConsoleApplication app,
+ String input) throws ClientException {
+ ManagedObject<? extends C> child;
+
+ // First attempt to create the child, this will guarantee that
+ // the name is acceptable.
+ try {
+ child = parent.createChild(irelation, d, input, exceptions);
+ } catch (IllegalManagedObjectNameException e) {
+ ArgumentException ae = ArgumentExceptionFactory
+ .adaptIllegalManagedObjectNameException(e, d);
+ app.printMessage(ae.getMessage());
+ return null;
+ }
+
+ // Make sure that there are not any other children with the
+ // same name.
+ try {
+ // Attempt to retrieve a child using this name.
+ parent.getChild(irelation, input);
+ } catch (AuthorizationException e) {
+ int msgID = MSGID_DSCFG_ERROR_CREATE_AUTHZ;
+ String msg = getMessage(msgID, irelation.getUserFriendlyName());
+ throw new ClientException(LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ msgID, msg);
+ } catch (ConcurrentModificationException e) {
+ int msgID = MSGID_DSCFG_ERROR_CREATE_CME;
+ String msg = getMessage(msgID, irelation.getUserFriendlyName());
+ throw new ClientException(LDAPResultCode.CONSTRAINT_VIOLATION, msgID,
+ msg);
+ } catch (CommunicationException e) {
+ int msgID = MSGID_DSCFG_ERROR_CREATE_CE;
+ String msg = getMessage(msgID, irelation.getUserFriendlyName(), e
+ .getMessage());
+ throw new ClientException(LDAPResultCode.CLIENT_SIDE_SERVER_DOWN,
+ msgID, msg);
+ } catch (DefinitionDecodingException e) {
+ // Do nothing.
+ } catch (ManagedObjectDecodingException e) {
+ // Do nothing.
+ } catch (ManagedObjectNotFoundException e) {
+ // The child does not already exist so this name is ok.
+ return child;
+ }
+
+ // A child with the specified name must already exist.
+ int msgID = MSGID_DSCFG_ERROR_CREATE_NAME_ALREADY_EXISTS;
+ String msg = getMessage(msgID, relation.getUserFriendlyName(), input);
+ app.printMessage(msg);
+ return null;
+ }
+
+ };
+
+ return getConsoleApplication().readValidatedInput(msg, validator);
+ }
+
+
+
// Generate the type name - definition mapping table.
@SuppressWarnings("unchecked")
- private SortedMap<String, ManagedObjectDefinition<? extends C, ?>>
- getSubTypes(AbstractManagedObjectDefinition<C, ?> d) {
- SortedMap<String, ManagedObjectDefinition<? extends C, ?>> map;
- map = new TreeMap<String, ManagedObjectDefinition<? extends C, ?>>();
+ private SortedMap<String, ManagedObjectDefinition<? extends C, ? extends S>>
+ getSubTypes(AbstractManagedObjectDefinition<C, S> d) {
+ SortedMap<String, ManagedObjectDefinition<? extends C, ? extends S>> map;
+ map =
+ new TreeMap<String, ManagedObjectDefinition<? extends C, ? extends S>>();
// If the top-level definition is instantiable, we use the value
// "generic".
if (d instanceof ManagedObjectDefinition) {
- ManagedObjectDefinition<? extends C, ?> mod =
- (ManagedObjectDefinition<? extends C, ?>) d;
+ ManagedObjectDefinition<? extends C, ? extends S> mod =
+ (ManagedObjectDefinition<? extends C, ? extends S>) d;
map.put(GENERIC_TYPE, mod);
}
// Process its sub-definitions.
String suffix = "-" + d.getName();
- for (AbstractManagedObjectDefinition<? extends C, ?> c :
+ for (AbstractManagedObjectDefinition<? extends C, ? extends S> c :
d.getAllChildren()) {
if (c instanceof ManagedObjectDefinition) {
- ManagedObjectDefinition<? extends C, ?> mod =
- (ManagedObjectDefinition<? extends C, ?>) c;
+ ManagedObjectDefinition<? extends C, ? extends S> mod =
+ (ManagedObjectDefinition<? extends C, ? extends S>) c;
// For the type name we shorten it, if possible, by stripping
// off the trailing part of the name which matches the
--
Gitblit v1.10.0