From ee021bead4d9a72f6f2e6b52222ff4013cbc8b71 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Tue, 20 Jan 2015 09:26:46 +0000
Subject: [PATCH] OPENDJ-1734 (CR-5811) V/-version option does not work for some tools

---
 opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java |  178 +++++++++++------------------------------------------------
 1 files changed, 33 insertions(+), 145 deletions(-)

diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
index a09b968..3d3e9bd 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
@@ -31,7 +31,6 @@
 import static com.forgerock.opendj.cli.Utils.*;
 import static com.forgerock.opendj.util.StaticUtils.*;
 
-import java.io.IOException;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -61,17 +60,11 @@
     private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
     private static final String INDENT = "    ";
 
-    /** The argument that will be used to trigger the display of usage information. */
-    private Argument usageArgument;
     /** The arguments that will be used to trigger the display of usage information for groups of sub-commands. */
     private final Map<Argument, Collection<SubCommand>> usageGroupArguments =
         new HashMap<Argument, Collection<SubCommand>>();
     /** The set of unnamed trailing arguments that were provided for this parser. */
     private final ArrayList<String> trailingArguments = new ArrayList<String>();
-    /** Indicates whether subcommand and long argument names should be treated in a case-sensitive manner. */
-    private final boolean longArgumentsCaseSensitive;
-    /** Indicates whether the usage information has been displayed. */
-    private boolean usageOrVersionDisplayed;
 
     /** The set of global arguments defined for this parser, referenced by short ID. */
     private final Map<Character, Argument> globalShortIDMap = new HashMap<Character, Argument>();
@@ -84,26 +77,11 @@
     /** The set of subcommands defined for this parser, referenced by subcommand name. */
     private final SortedMap<String, SubCommand> subCommands = new TreeMap<String, SubCommand>();
 
-    /** The output stream to which usage information should be printed. */
-    private OutputStream usageOutputStream;
-
-    /**
-     * The fully-qualified name of the Java class that should be invoked to launch the program with which this argument
-     * parser is associated.
-     */
-    private final String mainClassName;
-
-    /**A human-readable description for the tool, which will be included when displaying usage information.     */
-    private final LocalizableMessage toolDescription;
-
     /** The raw set of command-line arguments that were provided. */
     private String[] rawArguments;
     /**The subcommand requested by the user as part of the command-line arguments.     */
     private SubCommand subCommand;
 
-    /** Indicates whether the version argument was provided. */
-    private boolean versionPresent;
-
     /**
      * Creates a new instance of this subcommand argument parser with no arguments.
      *
@@ -118,42 +96,6 @@
     public SubCommandArgumentParser(String mainClassName, LocalizableMessage toolDescription,
             boolean longArgumentsCaseSensitive) {
         super(mainClassName, toolDescription, longArgumentsCaseSensitive);
-        this.mainClassName = mainClassName;
-        this.toolDescription = toolDescription;
-        this.longArgumentsCaseSensitive = longArgumentsCaseSensitive;
-    }
-
-    /**
-     * Retrieves the fully-qualified name of the Java class that should be invoked to launch the program with which this
-     * argument parser is associated.
-     *
-     * @return The fully-qualified name of the Java class that should be invoked to launch the program with which this
-     *         argument parser is associated.
-     */
-    @Override
-    public String getMainClassName() {
-        return mainClassName;
-    }
-
-    /**
-     * Retrieves a human-readable description for this tool, which should be included at the top of the command-line
-     * usage information.
-     *
-     * @return A human-readable description for this tool, or {@code null} if none is available.
-     */
-    @Override
-    public LocalizableMessage getToolDescription() {
-        return toolDescription;
-    }
-
-    /**
-     * Indicates whether subcommand names and long argument strings should be treated in a case-sensitive manner.
-     *
-     * @return <CODE>true</CODE> if subcommand names and long argument strings should be treated in a case-sensitive
-     *         manner, or <CODE>false</CODE> if they should not.
-     */
-    public boolean longArgumentsCaseSensitive() {
-        return longArgumentsCaseSensitive;
     }
 
     /**
@@ -380,7 +322,7 @@
 
         String longID = argument.getLongIdentifier();
         if (longID != null) {
-            if (!longArgumentsCaseSensitive) {
+            if (!longArgumentsCaseSensitive()) {
                 longID = toLowerCase(longID);
             }
 
@@ -436,7 +378,7 @@
 
         String longID = argument.getLongIdentifier();
         if (longID != null) {
-            if (!longArgumentsCaseSensitive) {
+            if (!longArgumentsCaseSensitive()) {
                 longID = toLowerCase(longID);
             }
 
@@ -466,9 +408,7 @@
      */
     @Override
     public void setUsageArgument(Argument argument, OutputStream outputStream) {
-        usageArgument = argument;
-        usageOutputStream = outputStream;
-
+        super.setUsageArgument(argument, outputStream);
         usageGroupArguments.put(argument, Collections.<SubCommand> emptySet());
     }
 
@@ -523,7 +463,7 @@
         this.rawArguments = rawArguments;
         this.subCommand = null;
         this.trailingArguments.clear();
-        this.usageOrVersionDisplayed = false;
+        setUsageOrVersionDisplayed(false);
 
         boolean inTrailingArgs = false;
 
@@ -572,7 +512,7 @@
 
                 // If we're not case-sensitive, then convert the name to lowercase.
                 String origArgName = argName;
-                if (!longArgumentsCaseSensitive) {
+                if (!longArgumentsCaseSensitive()) {
                     argName = toLowerCase(argName);
                 }
 
@@ -587,13 +527,11 @@
                         if (OPTION_LONG_HELP.equals(argName)) {
                             // "--help" will always be interpreted as requesting usage
                             // information.
-                            getUsage(usageOutputStream);
+                            writeToUsageOutputStream(getUsage());
                             return;
-                        } else if (OPTION_LONG_PRODUCT_VERSION.equals(argName)) {
+                        } else if (OPTION_LONG_PRODUCT_VERSION.equals(argName) && getVersionHandler() != null) {
                             // "--version" will always be interpreted as requesting usage
                             // information.
-                            versionPresent = true;
-                            usageOrVersionDisplayed = true;
                             printVersion();
                             return;
                         } else if (subCommand != null) {
@@ -612,7 +550,7 @@
                 // If this is a usage argument, then immediately stop and print
                 // usage information.
                 if (usageGroupArguments.containsKey(a)) {
-                    getUsage(a, usageOutputStream);
+                    getUsage(a);
                     return;
                 }
 
@@ -670,17 +608,15 @@
                     if (subCommand == null) {
                         if (argCharacter == '?') {
                             // "-?" will always be interpreted as requesting usage.
-                            getUsage(usageOutputStream);
-                            if (usageArgument != null) {
-                                usageArgument.setPresent(true);
+                            writeToUsageOutputStream(getUsage());
+                            if (getUsageArgument() != null) {
+                                getUsageArgument().setPresent(true);
                             }
                             return;
-                        } else if (argCharacter == OPTION_SHORT_PRODUCT_VERSION) {
+                        } else if (argCharacter == OPTION_SHORT_PRODUCT_VERSION && getVersionHandler() != null) {
                             // "-V" will always be interpreted as requesting
                             // version information except if it's already defined.
                             if (dashVAccepted()) {
-                                usageOrVersionDisplayed = true;
-                                versionPresent = true;
                                 printVersion();
                                 return;
                             } else {
@@ -699,12 +635,10 @@
                         if (a == null) {
                             if (argCharacter == '?') {
                                 // "-?" will always be interpreted as requesting usage.
-                                getUsage(usageOutputStream);
+                                writeToUsageOutputStream(getUsage());
                                 return;
-                            } else if (argCharacter == OPTION_SHORT_PRODUCT_VERSION) {
+                            } else if (argCharacter == OPTION_SHORT_PRODUCT_VERSION && getVersionHandler() != null) {
                                 if (dashVAccepted()) {
-                                    usageOrVersionDisplayed = true;
-                                    versionPresent = true;
                                     printVersion();
                                     return;
                                 }
@@ -722,7 +656,7 @@
                 // If this is the usage argument, then immediately stop and print
                 // usage information.
                 if (usageGroupArguments.containsKey(a)) {
-                    getUsage(a, usageOutputStream);
+                    getUsage(a);
                     return;
                 }
 
@@ -784,7 +718,7 @@
                         // If this is the usage argument, then immediately stop and
                         // print usage information.
                         if (usageGroupArguments.containsKey(b)) {
-                            getUsage(b, usageOutputStream);
+                            getUsage(b);
                             return;
                         }
                     }
@@ -802,7 +736,7 @@
             } else {
                 // It must be the sub-command.
                 String nameToCheck = arg;
-                if (!longArgumentsCaseSensitive) {
+                if (!longArgumentsCaseSensitive()) {
                     nameToCheck = toLowerCase(arg);
                 }
 
@@ -861,10 +795,10 @@
      *            The subcommand for which to display the usage information.
      */
     public void getSubCommandUsage(LocalizableMessageBuilder buffer, SubCommand subCommand) {
-        usageOrVersionDisplayed = true;
+        setUsageOrVersionDisplayed(true);
         String scriptName = System.getProperty(PROPERTY_SCRIPT_NAME);
         if (scriptName == null || scriptName.length() == 0) {
-            scriptName = "java " + mainClassName;
+            scriptName = "java " + getMainClassName();
         }
         buffer.append(INFO_ARGPARSER_USAGE_JAVA_SCRIPTNAME.get(scriptName));
         buffer.append("  ");
@@ -895,6 +829,8 @@
             buffer.append(INFO_SUBCMD_OPTIONS.get());
             buffer.append(EOL);
         }
+
+        final Argument usageArgument = getUsageArgument();
         for (Argument a : subCommand.getArguments()) {
             // If this argument is hidden, then skip it.
             if (a.isHidden()) {
@@ -1007,10 +943,10 @@
      * @return A string describing how the user can get more help.
      */
     public LocalizableMessage getHelpUsageReference() {
-        usageOrVersionDisplayed = true;
+        setUsageOrVersionDisplayed(true);
         String scriptName = System.getProperty(PROPERTY_SCRIPT_NAME);
         if (scriptName == null || scriptName.length() == 0) {
-            scriptName = "java " + mainClassName;
+            scriptName = "java " + getMainClassName();
         }
 
         LocalizableMessageBuilder buffer = new LocalizableMessageBuilder();
@@ -1030,17 +966,6 @@
     }
 
     /**
-     * Indicates whether the usage information has been displayed to the end user either by an explicit argument like
-     * "-H" or "--help", or by a built-in argument like "-?".
-     *
-     * @return {@code true} if the usage information has been displayed, or {@code false} if not.
-     */
-    @Override
-    public boolean usageOrVersionDisplayed() {
-        return usageOrVersionDisplayed;
-    }
-
-    /**
      * Adds the provided subcommand to this argument parser. This is only intended for use by the
      * <CODE>SubCommand</CODE> constructor and does not do any validation of its own to ensure that there are no
      * conflicts with the subcommand or any of its arguments.
@@ -1053,9 +978,10 @@
     }
 
     /** Get usage for a specific usage argument. */
-    private void getUsage(Argument a, OutputStream outputStream) {
+    private void getUsage(Argument a) {
         LocalizableMessageBuilder buffer = new LocalizableMessageBuilder();
 
+        final Argument usageArgument = getUsageArgument();
         if (a.equals(usageArgument) && subCommand != null) {
             getSubCommandUsage(buffer, subCommand);
         } else if (a.equals(usageArgument) && usageGroupArguments.size() <= 1) {
@@ -1065,33 +991,20 @@
             // Using groups - so display all sub-commands group help.
             getFullUsage(Collections.<SubCommand> emptySet(), true, buffer);
         } else {
-            // Requested help on specific group - don't display global
-            // options.
+            // Requested help on specific group - don't display global options.
             getFullUsage(usageGroupArguments.get(a), false, buffer);
         }
 
-        try {
-            outputStream.write(buffer.toString().getBytes());
-        } catch (Exception e) {
-            logger.traceException(e);
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void getUsage(OutputStream outputStream) {
-        try {
-            outputStream.write(getUsage().getBytes());
-        } catch (IOException e) {
-            logger.traceException(e);
-        }
+        writeToUsageOutputStream(buffer);
     }
 
     /**
      * Appends complete usage information for the specified set of sub-commands.
      */
     private void getFullUsage(Collection<SubCommand> c, boolean showGlobalOptions, LocalizableMessageBuilder buffer) {
-        usageOrVersionDisplayed = true;
+        setUsageOrVersionDisplayed(true);
+
+        final LocalizableMessage toolDescription = getToolDescription();
         if (toolDescription != null && toolDescription.length() > 0) {
             buffer.append(wrapText(toolDescription, MAX_LINE_WIDTH - 1));
             buffer.append(EOL).append(EOL);
@@ -1099,7 +1012,7 @@
 
         String scriptName = System.getProperty(PROPERTY_SCRIPT_NAME);
         if (scriptName == null || scriptName.length() == 0) {
-            scriptName = "java " + mainClassName;
+            scriptName = "java " + getMainClassName();
         }
         buffer.append(INFO_ARGPARSER_USAGE.get());
         buffer.append("  ");
@@ -1122,6 +1035,7 @@
             buffer.append(EOL);
         }
 
+        final Argument usageArgument = getUsageArgument();
         if (c.isEmpty()) {
             // Display usage arguments (except the default one).
             for (Argument a : globalArgumentList) {
@@ -1216,6 +1130,7 @@
             value = "";
         }
 
+        final Argument usageArgument = getUsageArgument();
         Character shortIDChar = a.getShortIdentifier();
         if (shortIDChar != null) {
             if (a.equals(usageArgument)) {
@@ -1292,28 +1207,6 @@
     }
 
     /**
-     * Returns whether the usage argument was provided or not. This method should be called after a call to
-     * parseArguments.
-     *
-     * @return <CODE>true</CODE> if the usage argument was provided and <CODE>false</CODE> otherwise.
-     */
-    @Override
-    public boolean isUsageArgumentPresent() {
-        return usageArgument != null && usageArgument.isPresent();
-    }
-
-    /**
-     * Returns whether the version argument was provided or not. This method should be called after a call to
-     * parseArguments.
-     *
-     * @return <CODE>true</CODE> if the version argument was provided and <CODE>false</CODE> otherwise.
-     */
-    @Override
-    public boolean isVersionArgumentPresent() {
-        return super.isVersionArgumentPresent() && !versionPresent;
-    }
-
-    /**
      * Generate reference documentation for dsconfig subcommands in DocBook 5 XML format. As the number of categories is
      * large, the subcommand entries are sorted here by name for inclusion in a &lt;refsect1&gt; covering all dsconfig
      * Subcommands as part of the &lt;refentry&gt; for dsconfig (in man-dsconfig.xml).
@@ -1401,9 +1294,4 @@
         return "<refsect2 xml:id=\"dsconfig-" + sc.getName() + "\">" + EOL + " <title>dsconfig " + sc.getName()
                 + "</title>" + EOL + " <para>" + sc.getDescription() + "</para>" + EOL + options + "</refsect2>" + EOL;
     }
-
-    void printVersion() {
-        // TODO
-        // DirectoryServer.printVersion(usageOutputStream);
-    }
 }

--
Gitblit v1.10.0