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/SubCommandHandler.java |  164 ++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 134 insertions(+), 30 deletions(-)

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 a82d0d6..ac32ec1 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java
@@ -82,12 +82,10 @@
    * A path serializer which is used to retrieve a managed object
    * based on a path and a list of path arguments.
    */
-  private static class ManagedObjectFinder implements
-      ManagedObjectPathSerializer {
+  private class ManagedObjectFinder implements ManagedObjectPathSerializer {
 
     // Any argument exception that was caught when attempting to find
-    // the
-    // managed object.
+    // the managed object.
     private ArgumentException ae;
 
     // The index of the next path argument to be retrieved.
@@ -103,8 +101,7 @@
     private ConcurrentModificationException cme;
 
     // Any operation exception that was caught when attempting to find
-    // the
-    // managed object.
+    // the managed object.
     private DefinitionDecodingException dde;
 
     // Flag indicating whether or not an exception occurred during
@@ -133,6 +130,18 @@
         String childName = args.get(argIndex++);
 
         try {
+          // If the name is null then we must be interactive - so let
+          // the user choose.
+          if (childName == null) {
+            try {
+              childName = readChildName(managedObject, r, d);
+            } catch (ArgumentException e) {
+              ae = e;
+              gotException = true;
+              return;
+            }
+          }
+
           ManagedObject<?> child = managedObject.getChild(r, childName);
 
           // Check that child is a sub-type of the specified
@@ -377,14 +386,14 @@
     // arguments.
     private ArgumentException e = null;
 
-    // The sub-command.
-    private final SubCommand subCommand;
-
     // Indicates whether the sub-command is a create-xxx
     // sub-command, in which case the final path element will
     // have different usage information.
     private final boolean isCreate;
 
+    // The sub-command.
+    private final SubCommand subCommand;
+
     // The number of path elements to expect.
     private int sz;
 
@@ -435,17 +444,17 @@
             PropertyDefinitionUsageBuilder b =
               new PropertyDefinitionUsageBuilder(false);
             String usage = "{" + b.getUsage(pd) + "}";
-            arg = new StringArgument(argName, null, argName, true, true, usage,
-                MSGID_DSCFG_DESCRIPTION_NAME_CREATE_EXT, d
+            arg = new StringArgument(argName, null, argName, false, true,
+                usage, MSGID_DSCFG_DESCRIPTION_NAME_CREATE_EXT, d
                     .getUserFriendlyName(), pd.getName(), pd.getSynopsis());
           } else {
-            arg = new StringArgument(argName, null, argName, true, true,
+            arg = new StringArgument(argName, null, argName, false, true,
                 "{NAME}", MSGID_DSCFG_DESCRIPTION_NAME_CREATE, d
                     .getUserFriendlyName());
           }
         } else {
           // A normal naming argument.
-          arg = new StringArgument(argName, null, argName, true, true,
+          arg = new StringArgument(argName, null, argName, false, true,
               "{NAME}", MSGID_DSCFG_DESCRIPTION_NAME, d.getUserFriendlyName());
         }
         subCommand.addArgument(arg);
@@ -534,6 +543,9 @@
   // 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;
@@ -554,9 +566,12 @@
 
   /**
    * Create a new sub-command handler.
+   *
+   * @param app
+   *          The application instance.
    */
-  protected SubCommandHandler() {
-    // No implementation required.
+  protected SubCommandHandler(ConsoleApplication app) {
+    this.app = app;
   }
 
 
@@ -585,12 +600,6 @@
   /**
    * Run this sub-command handler.
    *
-   * @param app
-   *          The application.
-   * @param out
-   *          The application output stream.
-   * @param err
-   *          The application error stream.
    * @return Returns zero if the sub-command completed successfully or
    *         non-zero if it did not.
    * @throws ArgumentException
@@ -599,8 +608,7 @@
    * @throws ClientException
    *           If the management context could not be created.
    */
-  public abstract int run(DSConfig app, PrintStream out, PrintStream err)
-      throws ArgumentException, ClientException;
+  public abstract int run() throws ArgumentException, ClientException;
 
 
 
@@ -685,11 +693,20 @@
 
 
   /**
+   * 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 context
-   *          The management context.
    * @param path
    *          The managed object path.
    * @param args
@@ -718,15 +735,17 @@
    * @throws ArgumentException
    *           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(ManagementContext context,
+  protected final ManagedObject<?> getManagedObject(
       ManagedObjectPath<?, ?> path, List<String> args)
       throws ArgumentException, AuthorizationException,
       DefinitionDecodingException, ManagedObjectDecodingException,
       CommunicationException, ConcurrentModificationException,
-      ManagedObjectNotFoundException {
+      ManagedObjectNotFoundException, ClientException {
     ManagedObjectFinder finder = new ManagedObjectFinder();
-    return finder.find(context, path, args);
+    return finder.find(app.getManagementContext(), path, args);
   }
 
 
@@ -737,12 +756,22 @@
    * @param namingArgs
    *          The naming arguments.
    * @return Returns the values of the naming arguments.
+   * @throws ArgumentException
+   *           If one of the naming arguments is missing and the
+   *           application is non-interactive.
    */
   protected final List<String> getNamingArgValues(
-      List<StringArgument> namingArgs) {
+      List<StringArgument> namingArgs) throws ArgumentException {
     ArrayList<String> values = new ArrayList<String>(namingArgs.size());
     for (StringArgument arg : namingArgs) {
-      values.add(arg.getValue());
+      String value = arg.getValue();
+
+      if (value == null && !app.isInteractive()) {
+        throw ArgumentExceptionFactory
+            .missingMandatoryNonInteractiveArgument(arg);
+      } else {
+        values.add(value);
+      }
     }
     return values;
   }
@@ -854,6 +883,81 @@
 
 
   /**
+   * Interactively prompts the user to select from a choice of child
+   * managed objects.
+   * <p>
+   * This method will adapt according to the available choice. For
+   * example, if there is only one choice, then a question will be
+   * asked. If there are no children then an
+   * <code>ArgumentException</code> will be thrown.
+   *
+   * @param <C>
+   *          The type of child client configuration.
+   * @param <S>
+   *          The type of child server configuration.
+   * @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.
+   * @throws CommunicationException
+   *           If the server cannot be contacted.
+   * @throws ConcurrentModificationException
+   *           If the parent managed object has been deleted.
+   * @throws AuthorizationException
+   *           If the children cannot be listed due to an
+   *           authorization failure.
+   * @throws ArgumentException
+   *           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,
+      InstantiableRelationDefinition<C, S> r,
+      AbstractManagedObjectDefinition<? extends C, ? extends S> d)
+      throws AuthorizationException, ConcurrentModificationException,
+      CommunicationException, ArgumentException {
+    if (d == null) {
+      d = r.getChildDefinition();
+    }
+
+    String[] children = parent.listChildren(r, d);
+    switch (children.length) {
+    case 0: {
+      // No options available - abort.
+      int msgID = MSGID_DSCFG_ERROR_FINDER_NO_CHILDREN;
+      String msg = getMessage(msgID, d.getUserFriendlyPluralName());
+      throw new ArgumentException(msgID, msg);
+    }
+    case 1: {
+      // Only one option available so confirm that the user wishes to
+      // access it.
+      int msgID = MSGID_DSCFG_FINDER_PROMPT_SINGLE;
+      String msg = getMessage(msgID, d.getUserFriendlyName(), children[0]);
+      if (getConsoleApplication().confirmAction(msg)) {
+        return children[0];
+      } else {
+        msgID = MSGID_DSCFG_ERROR_FINDER_SINGLE_CHILD_REJECTED;
+        msg = getMessage(msgID, d.getUserFriendlyName());
+        throw new ArgumentException(msgID, msg);
+      }
+    }
+    default: {
+      // Display a menu.
+      List<String> choices = Arrays.asList(children);
+      int msgID = MSGID_DSCFG_FINDER_PROMPT_MANY;
+      String msg = getMessage(msgID, d.getUserFriendlyName());
+      return getConsoleApplication().readChoice(msg, choices, choices, null);
+    }
+    }
+  }
+
+
+
+  /**
    * Registers the advanced mode argument with the sub-command.
    *
    * @param subCommand

--
Gitblit v1.10.0