From 13a63611d24de8c5727e62a215b26354c1a22278 Mon Sep 17 00:00:00 2001
From: jvergara <jvergara@localhost>
Date: Wed, 19 Mar 2008 18:09:56 +0000
Subject: [PATCH] Fix for issue 2197 (dsconfig: interactive mode should display the effective dsconfig command)

---
 opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java |  249 +++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 228 insertions(+), 21 deletions(-)

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 d0bcc6d..57e8843 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java
@@ -35,6 +35,9 @@
 import static org.opends.server.tools.dsconfig.ArgumentExceptionFactory.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.Comparator;
@@ -46,6 +49,7 @@
 import java.util.TreeSet;
 
 import org.opends.messages.Message;
+import org.opends.quicksetup.util.Utils;
 import org.opends.server.admin.AttributeTypePropertyDefinition;
 import org.opends.server.admin.ClassLoaderProvider;
 import org.opends.server.admin.ClassPropertyDefinition;
@@ -60,6 +64,7 @@
 import org.opends.server.types.DebugLogLevel;
 import org.opends.server.types.InitializationException;
 import org.opends.server.util.EmbeddedUtils;
+import org.opends.server.util.ServerConstants;
 import org.opends.server.util.StaticUtils;
 import org.opends.server.util.args.ArgumentException;
 import org.opends.server.util.args.BooleanArgument;
@@ -68,6 +73,7 @@
 import org.opends.server.util.args.SubCommandArgumentParser;
 import org.opends.server.util.args.ArgumentGroup;
 import org.opends.server.util.cli.CLIException;
+import org.opends.server.util.cli.CommandBuilder;
 import org.opends.server.util.cli.ConsoleApplication;
 import org.opends.server.util.cli.Menu;
 import org.opends.server.util.cli.MenuBuilder;
@@ -116,6 +122,11 @@
         if (result.isQuit()) {
           return result;
         } else {
+          if (result.isSuccess() && isInteractive() &&
+              handler.isCommandBuilderUseful())
+          {
+            printCommandBuilder(getCommandBuilder(handler));
+          }
           // Success or cancel.
           app.println();
           app.pressReturnToContinue();
@@ -364,6 +375,14 @@
   // behavior.
   private BooleanArgument noPromptArgument;
 
+  // The argument that the user must set to display the equivalent
+  // non-interactive mode argument
+  private BooleanArgument displayEquivalentArgument;
+
+  // The argument that allows the user to dump the equivalent non-interactive
+  // command to a file.
+  private StringArgument equivalentCommandFileArgument;
+
   // The command-line argument parser.
   private final SubCommandArgumentParser parser;
 
@@ -387,6 +406,10 @@
   // properties file.
   private BooleanArgument noPropertiesFileArgument;
 
+  // The boolean that is used to know if data must be appended to the file
+  // containing equivalent non-interactive commands.
+  private boolean alreadyWroteEquivalentCommand;
+
   /**
    * Creates a new dsconfig application instance.
    *
@@ -540,6 +563,19 @@
           OPTION_LONG_HELP, INFO_DSCFG_DESCRIPTION_SHOW_GROUP_USAGE_SUMMARY
               .get());
 
+      displayEquivalentArgument = new BooleanArgument(
+          OPTION_DSCFG_LONG_DISPLAY_EQUIVALENT,
+          null, OPTION_DSCFG_LONG_DISPLAY_EQUIVALENT,
+          INFO_DSCFG_DESCRIPTION_DISPLAY_EQUIVALENT.get());
+      advancedModeArgument.setPropertyName(
+          OPTION_DSCFG_LONG_DISPLAY_EQUIVALENT);
+
+      equivalentCommandFileArgument = new StringArgument(
+          OPTION_LONG_EQUIVALENT_COMMAND_FILE_PATH, null,
+          OPTION_LONG_EQUIVALENT_COMMAND_FILE_PATH, false, false, true,
+          INFO_PATH_PLACEHOLDER.get(), null, null,
+          INFO_DSCFG_DESCRIPTION_EQUIVALENT_COMMAND_FILE_PATH.get());
+
       propertiesFileArgument = new StringArgument("propertiesFilePath",
           null, OPTION_LONG_PROP_FILE_PATH,
           false, false, true, INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
@@ -561,6 +597,8 @@
       parser.addGlobalArgument(quietArgument);
       parser.addGlobalArgument(scriptFriendlyArgument);
       parser.addGlobalArgument(noPromptArgument);
+      parser.addGlobalArgument(displayEquivalentArgument);
+      parser.addGlobalArgument(equivalentCommandFileArgument);
       parser.addGlobalArgument(propertiesFileArgument);
       parser.setFilePropertiesArgument(propertiesFileArgument);
       parser.addGlobalArgument(noPropertiesFileArgument);
@@ -711,6 +749,18 @@
       return 1;
     }
 
+    // Check that we can write on the provided path where we write the
+    // equivalent non-interactive commands.
+    if (equivalentCommandFileArgument.isPresent())
+    {
+      String file = equivalentCommandFileArgument.getValue();
+      if (!Utils.canWrite(file))
+      {
+        println(ERR_DSCFG_CANNOT_WRITE_EQUIVALENT_COMMAND_LINE_FILE.get(file));
+        return 1;
+      }
+    }
+
     // Make sure that management context's arguments are valid.
     try {
       factory.validateGlobalArguments();
@@ -724,32 +774,32 @@
       hasSubCommand = false;
 
       if (isInteractive()) {
-          // Top-level interactive mode.
-          retCode = runInteractiveMode();
-        } else {
-          Message message = ERR_ERROR_PARSING_ARGS
-              .get(ERR_DSCFG_ERROR_MISSING_SUBCOMMAND.get());
-          displayMessageAndUsageReference(message);
-          retCode = 1;
-        }
+        // Top-level interactive mode.
+        retCode = runInteractiveMode();
       } else {
-        hasSubCommand = true;
-
-        // Retrieve the sub-command implementation and run it.
-        SubCommandHandler handler = handlers.get(parser.getSubCommand());
-        retCode = runSubCommand(handler);
+        Message message = ERR_ERROR_PARSING_ARGS
+        .get(ERR_DSCFG_ERROR_MISSING_SUBCOMMAND.get());
+        displayMessageAndUsageReference(message);
+        retCode = 1;
       }
+    } else {
+      hasSubCommand = true;
 
-      try {
-        // Close the Management context ==> an LDAP UNBIND is sent
-        factory.close();
-      } catch (Exception e) {
-      // Nothing to report in this case
-      }
-
-      return retCode;
+      // Retrieve the sub-command implementation and run it.
+      SubCommandHandler handler = handlers.get(parser.getSubCommand());
+      retCode = runSubCommand(handler);
     }
 
+    try {
+      // Close the Management context ==> an LDAP UNBIND is sent
+      factory.close();
+    } catch (Exception e) {
+      // Nothing to report in this case
+    }
+
+    return retCode;
+  }
+
 
 
   // Run the top-level interactive console.
@@ -874,6 +924,13 @@
       MenuResult<Integer> result = handler.run(this, factory);
 
       if (result.isSuccess()) {
+        if (isInteractive())
+        {
+          println();
+          println(INFO_DSCFG_NON_INTERACTIVE.get(
+              getCommandBuilder(handler).toString()));
+        }
+
         return result.getValue();
       } else {
         // User must have quit.
@@ -918,4 +975,154 @@
       return 1;
     }
   }
+
+  /**
+   * Updates the command builder with the global options: script friendly,
+   * verbose, etc. for a given subcommand.  It also adds systematically the
+   * no-prompt option.
+   * @param handler the subcommand handler.
+   */
+  private CommandBuilder getCommandBuilder(SubCommandHandler handler)
+  {
+    String commandName =
+      System.getProperty(ServerConstants.PROPERTY_SCRIPT_NAME);
+    if (commandName == null)
+    {
+      commandName = "dsconfig";
+    }
+
+    CommandBuilder commandBuilder =
+      new CommandBuilder(commandName, handler.getSubCommand().getName());
+
+    if (advancedModeArgument.isPresent())
+    {
+      commandBuilder.addArgument(advancedModeArgument);
+    }
+
+    commandBuilder.append(handler.getCommandBuilder());
+
+    if ((factory != null) && (factory.getContextCommandBuilder() != null))
+    {
+      commandBuilder.append(factory.getContextCommandBuilder());
+    }
+
+    if (verboseArgument.isPresent())
+    {
+      commandBuilder.addArgument(verboseArgument);
+    }
+
+    if (scriptFriendlyArgument.isPresent())
+    {
+      commandBuilder.addArgument(scriptFriendlyArgument);
+    }
+
+    commandBuilder.addArgument(noPromptArgument);
+
+    if (propertiesFileArgument.isPresent())
+    {
+      commandBuilder.addArgument(propertiesFileArgument);
+    }
+
+    if (noPropertiesFileArgument.isPresent())
+    {
+      commandBuilder.addArgument(noPropertiesFileArgument);
+    }
+
+    return commandBuilder;
+  }
+
+  /**
+   * Creates a command builder with the global options: script friendly,
+   * verbose, etc. for a given subcommand name.  It also adds systematically the
+   * no-prompt option.
+   * @param subcommandName the subcommand name.
+   * @return the command builder that has been created with the specified
+   * subcommandName.
+   */
+  CommandBuilder getCommandBuilder(String subcommandName)
+  {
+    String commandName =
+      System.getProperty(ServerConstants.PROPERTY_SCRIPT_NAME);
+    if (commandName == null)
+    {
+      commandName = "dsconfig";
+    }
+
+    CommandBuilder commandBuilder =
+      new CommandBuilder(commandName, subcommandName);
+
+    if (advancedModeArgument.isPresent())
+    {
+      commandBuilder.addArgument(advancedModeArgument);
+    }
+
+    if ((factory != null) && (factory.getContextCommandBuilder() != null))
+    {
+      commandBuilder.append(factory.getContextCommandBuilder());
+    }
+
+    if (verboseArgument.isPresent())
+    {
+      commandBuilder.addArgument(verboseArgument);
+    }
+
+    if (scriptFriendlyArgument.isPresent())
+    {
+      commandBuilder.addArgument(scriptFriendlyArgument);
+    }
+
+    commandBuilder.addArgument(noPromptArgument);
+
+    if (propertiesFileArgument.isPresent())
+    {
+      commandBuilder.addArgument(propertiesFileArgument);
+    }
+
+    if (noPropertiesFileArgument.isPresent())
+    {
+      commandBuilder.addArgument(noPropertiesFileArgument);
+    }
+
+    return commandBuilder;
+  }
+
+  /**
+   * Prints the contents of a command builder.  This method has been created
+   * since SetPropSubCommandHandler calls it.  All the logic of DSConfig is on
+   * this method.  Currently it simply writes the content of the CommandBuilder
+   * to the standard output, but if we provide an option to write the content
+   * to a file only the implementation of this method must be changed.
+   * @param commandBuilder the command builder to be printed.
+   */
+  void printCommandBuilder(CommandBuilder commandBuilder)
+  {
+    if (displayEquivalentArgument.isPresent())
+    {
+      println();
+      // We assume that the app we are running is this one.
+      println(INFO_DSCFG_NON_INTERACTIVE.get(commandBuilder.toString()));
+    }
+    if (equivalentCommandFileArgument.isPresent())
+    {
+      // Write to the file.
+      boolean append = alreadyWroteEquivalentCommand;
+      String file = equivalentCommandFileArgument.getValue();
+      try
+      {
+        BufferedWriter writer =
+          new BufferedWriter(new FileWriter(file, append));
+        writer.write(commandBuilder.toString());
+        writer.newLine();
+
+        writer.flush();
+        writer.close();
+      }
+      catch (IOException ioe)
+      {
+        println(ERR_DSCFG_ERROR_WRITING_EQUIVALENT_COMMAND_LINE.get(file,
+            ioe.toString()));
+      }
+      alreadyWroteEquivalentCommand = true;
+    }
+  }
 }

--
Gitblit v1.10.0