From edb7b32eaa2db4a171496d30ed3293bfa06b30c8 Mon Sep 17 00:00:00 2001
From: Violette Roche-Montane <violette.roche-montane@forgerock.com>
Date: Tue, 11 Feb 2014 13:36:41 +0000
Subject: [PATCH] Checkpoint commit for OPENDJ-1303 - added DEFAULT_LDAP_CONNECT_TIMEOUT to constants. - added ClientException, merge it with CLIException. Replaced CLIException calls. (CLIException will disappear soon) - Console application : errors,warnings should be displayed in stdout if interactive mode is enabled. 	- added unit tests. 	- removed closeIfNotNull / replaced it by Utils.closeSilently

---
 opendj-cli/src/main/java/com/forgerock/opendj/cli/Utils.java                      |    7 
 opendj-cli/src/main/java/com/forgerock/opendj/cli/ClientException.java            |  108 ++++++++++++++++++
 opendj-cli/src/test/java/com/forgerock/opendj/cli/UtilsTestCase.java              |    6 
 opendj-cli/src/main/java/com/forgerock/opendj/cli/ConsoleApplication.java         |  131 ++++++++++-----------
 opendj-cli/src/test/java/com/forgerock/opendj/cli/ConsoleApplicationTestCase.java |   58 +++++++++
 opendj-cli/src/main/java/com/forgerock/opendj/cli/CliConstants.java               |    3 
 6 files changed, 236 insertions(+), 77 deletions(-)

diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/CliConstants.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/CliConstants.java
index 4dc1a78..c32484b 100755
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/CliConstants.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/CliConstants.java
@@ -31,6 +31,9 @@
  */
 public final class CliConstants {
 
+    /** Default value for LDAP connection timeout. */
+    public static final int DEFAULT_LDAP_CONNECT_TIMEOUT = 30000;
+
     /** Default value for incrementing port number. */
     public static final int PORT_INCREMENT = 1000;
 
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ClientException.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ClientException.java
new file mode 100644
index 0000000..4848ad5
--- /dev/null
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ClientException.java
@@ -0,0 +1,108 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Portions Copyright 2014 ForgeRock AS
+ */
+package com.forgerock.opendj.cli;
+
+import static com.forgerock.opendj.cli.CliMessages.ERR_CONSOLE_INPUT_ERROR;
+import org.forgerock.i18n.LocalizableException;
+import org.forgerock.i18n.LocalizableMessage;
+
+/**
+ * This class defines an exception that may be thrown if a local problem occurs in a Directory Server client.
+ */
+public class ClientException extends Exception implements LocalizableException {
+    /**
+     * The serial version identifier required to satisfy the compiler because this class extends
+     * <CODE>java.lang.Exception</CODE>, which implements the <CODE>java.io.Serializable</CODE> interface. This value
+     * was generated using the <CODE>serialver</CODE> command-line utility included with the Java SDK.
+     */
+    private static final long serialVersionUID = 1384120263337669664L;
+
+    /** The return code. */
+    private ReturnCode returnCode;
+
+    /** The message linked to that exception. */
+    private final LocalizableMessage message;
+
+    /**
+     * Adapts any exception that may have occurred whilst reading input from the
+     * console.
+     *
+     * @param cause
+     *            The exception that occurred whilst reading input from the
+     *            console.
+     * @return Returns a new CLI exception describing a problem that occurred
+     *         whilst reading input from the console.
+     */
+    public static ClientException adaptInputException(final Throwable cause) {
+        return new ClientException(ReturnCode.ERROR_USER_DATA, ERR_CONSOLE_INPUT_ERROR.get(cause.getMessage()), cause);
+    }
+
+    /**
+     * Creates a new client exception with the provided message.
+     *
+     * @param exitCode
+     *            The exit code that may be used if the client considers this to be a fatal problem.
+     * @param message
+     *            The message that explains the problem that occurred.
+     */
+    public ClientException(ReturnCode exitCode, LocalizableMessage message) {
+        super(message.toString());
+        this.returnCode = exitCode;
+        this.message = message;
+    }
+
+    /**
+     * Creates a new client exception with the provided message and root cause.
+     *
+     * @param exitCode
+     *            The exit code that may be used if the client considers this to be a fatal problem.
+     * @param message
+     *            The message that explains the problem that occurred.
+     * @param cause
+     *            The exception that was caught to trigger this exception.
+     */
+    public ClientException(ReturnCode exitCode, LocalizableMessage message, Throwable cause) {
+        super(message.toString(), cause);
+        this.returnCode = exitCode;
+        this.message = message;
+    }
+
+    /**
+     * Retrieves the exit code that the client may use if it considers this to be a fatal problem.
+     *
+     * @return The exit code that the client may use if it considers this to be a fatal problem.
+     */
+    public int getReturnCode() {
+        return returnCode.get();
+    }
+
+    @Override
+    public LocalizableMessage getMessageObject() {
+        return message;
+    }
+
+}
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConsoleApplication.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConsoleApplication.java
index 883923e..3811989 100755
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConsoleApplication.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConsoleApplication.java
@@ -34,7 +34,6 @@
 import static com.forgerock.opendj.cli.Utils.wrapText;
 
 import java.io.BufferedReader;
-import java.io.Closeable;
 import java.io.Console;
 import java.io.EOFException;
 import java.io.IOException;
@@ -45,11 +44,9 @@
 import org.forgerock.i18n.LocalizableMessage;
 
 /**
- * This class provides an abstract base class which can be used as the basis of
- * a console-based application.
+ * This class provides an abstract base class which can be used as the basis of a console-based application.
  */
 public abstract class ConsoleApplication {
-    private final PrintStream err;
 
     private final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
 
@@ -57,6 +54,8 @@
 
     private final PrintStream out;
 
+    private final PrintStream err;
+
     private final Console console = System.console();
 
     /**
@@ -80,27 +79,6 @@
     }
 
     /**
-     * Closes the provided {@code Closeable}s if they are not {@code null}.
-     *
-     * @param closeables
-     *          The closeables to be closed.
-     */
-    public final void closeIfNotNull(Closeable... closeables) {
-        if (closeables == null) {
-            return;
-        }
-        for (Closeable closeable : closeables) {
-            if (closeable != null) {
-                try {
-                    closeable.close();
-                } catch (Exception ignored) {
-                    // Do nothing.
-                }
-            }
-        }
-    }
-
-    /**
      * Returns the application error stream.
      *
      * @return The application error stream.
@@ -128,8 +106,8 @@
     }
 
     /**
-     * Indicates whether or not the user has requested interactive behavior. The
-     * default implementation returns {@code true}.
+     * Indicates whether or not the user has requested interactive behavior. The default implementation returns
+     * {@code true}.
      *
      * @return {@code true} if the user has requested interactive behavior.
      */
@@ -138,8 +116,7 @@
     }
 
     /**
-     * Indicates whether or not the user has requested quiet output. The default
-     * implementation returns {@code false}.
+     * Indicates whether or not the user has requested quiet output. The default implementation returns {@code false}.
      *
      * @return {@code true} if the user has requested quiet output.
      */
@@ -148,8 +125,8 @@
     }
 
     /**
-     * Indicates whether or not the user has requested script-friendly output.
-     * The default implementation returns {@code false}.
+     * Indicates whether or not the user has requested script-friendly output. The default implementation returns
+     * {@code false}.
      *
      * @return {@code true} if the user has requested script-friendly output.
      */
@@ -158,8 +135,7 @@
     }
 
     /**
-     * Indicates whether or not the user has requested verbose output. The
-     * default implementation returns {@code false}.
+     * Indicates whether or not the user has requested verbose output. The default implementation returns {@code false}.
      *
      * @return {@code true} if the user has requested verbose output.
      */
@@ -168,16 +144,15 @@
     }
 
     /**
-     * Interactively prompts the user to press return to continue. This method
-     * should be called in situations where a user needs to be given a chance to
-     * read some documentation before continuing (continuing may cause the
+     * Interactively prompts the user to press return to continue. This method should be called in situations where a
+     * user needs to be given a chance to read some documentation before continuing (continuing may cause the
      * documentation to be scrolled out of view).
      */
     public final void pressReturnToContinue() {
         final LocalizableMessage msg = INFO_MENU_PROMPT_RETURN_TO_CONTINUE.get();
         try {
             readLineOfInput(msg);
-        } catch (final CLIException e) {
+        } catch (final ClientException e) {
             // Ignore the exception - applications don't care.
         }
     }
@@ -189,14 +164,14 @@
      *            The message.
      */
     public final void errPrint(final LocalizableMessage msg) {
-        err.print(wrapText(msg, MAX_LINE_WIDTH));
+        getErrStream().print(wrap(msg));
     }
 
     /**
      * Displays a blank line to the error stream.
      */
     public final void errPrintln() {
-        err.println();
+        getErrStream().println();
     }
 
     /**
@@ -206,12 +181,11 @@
      *            The message.
      */
     public final void errPrintln(final LocalizableMessage msg) {
-        err.println(wrapText(msg, MAX_LINE_WIDTH));
+        getErrStream().println(wrap(msg));
     }
 
     /**
-     * Displays a message to the error stream indented by the specified number
-     * of columns.
+     * Displays a message to the error stream indented by the specified number of columns.
      *
      * @param msg
      *            The message.
@@ -219,7 +193,7 @@
      *            The number of columns to indent.
      */
     public final void errPrintln(final LocalizableMessage msg, final int indent) {
-        err.println(wrapText(msg, MAX_LINE_WIDTH, indent));
+        getErrStream().println(wrapText(msg, MAX_LINE_WIDTH, indent));
     }
 
     /**
@@ -229,8 +203,8 @@
      *            The verbose message.
      */
     public final void errPrintVerboseMessage(final LocalizableMessage msg) {
-        if (isVerbose() || isInteractive()) {
-            err.println(wrapText(msg, MAX_LINE_WIDTH));
+        if (isVerbose()) {
+            getErrStream().println(wrap(msg));
         }
     }
 
@@ -241,7 +215,7 @@
      *            The message.
      */
     public final void print(final LocalizableMessage msg) {
-        out.print(wrapText(msg, MAX_LINE_WIDTH));
+        out.print(wrap(msg));
     }
 
     /**
@@ -258,12 +232,11 @@
      *            The message.
      */
     public final void println(final LocalizableMessage msg) {
-        out.println(wrapText(msg, MAX_LINE_WIDTH));
+        out.println(wrap(msg));
     }
 
     /**
-     * Displays a message to the output stream indented by the specified number
-     * of columns.
+     * Displays a message to the output stream indented by the specified number of columns.
      *
      * @param msg
      *            The message.
@@ -282,27 +255,24 @@
      */
     public final void printVerboseMessage(final LocalizableMessage msg) {
         if (isVerbose() || isInteractive()) {
-            out.println(wrapText(msg, MAX_LINE_WIDTH));
+            out.println(wrap(msg));
         }
     }
 
     /**
-     * Interactively prompts (on error output) the user to provide a string
-     * value. Any non-empty string will be allowed (the empty string will
-     * indicate that the default should be used, if there is one).
+     * Interactively prompts (on error output) the user to provide a string value. Any non-empty string will be allowed
+     * (the empty string will indicate that the default should be used, if there is one).
      *
      * @param prompt
      *            The prompt to present to the user.
      * @param defaultValue
-     *            The default value to assume if the user presses ENTER without
-     *            typing anything, or {@code null} if there should not be a
-     *            default and the user must explicitly provide a value.
-     * @throws CLIException
+     *            The default value to assume if the user presses ENTER without typing anything, or {@code null} if
+     *            there should not be a default and the user must explicitly provide a value.
+     * @throws ClientException
      *             If the line of input could not be retrieved for some reason.
      * @return The string value read from the user.
      */
-    public final String readInput(LocalizableMessage prompt, final String defaultValue)
-            throws CLIException {
+    public final String readInput(LocalizableMessage prompt, final String defaultValue) throws ClientException {
         while (true) {
             if (defaultValue != null) {
                 prompt = INFO_PROMPT_SINGLE_DEFAULT.get(prompt.toString(), defaultValue);
@@ -327,13 +297,13 @@
      * @param prompt
      *            The password prompt.
      * @return The password.
-     * @throws CLIException
+     * @throws ClientException
      *             If the password could not be retrieved for some reason.
      */
-    public final char[] readPassword(final LocalizableMessage prompt) throws CLIException {
+    public final char[] readPassword(final LocalizableMessage prompt) throws ClientException {
         if (console != null) {
             if (prompt != null) {
-                err.print(wrapText(prompt, MAX_LINE_WIDTH));
+                err.print(wrap(prompt));
                 err.print(" ");
             }
             try {
@@ -343,7 +313,7 @@
                 }
                 return password;
             } catch (final Throwable e) {
-                throw CLIException.adaptInputException(e);
+                throw ClientException.adaptInputException(e);
             }
         } else {
             // FIXME: should go direct to char[] and avoid the String.
@@ -357,23 +327,48 @@
      * @param prompt
      *            The prompt.
      * @return The line of input.
-     * @throws CLIException
+     * @throws ClientException
      *             If the line of input could not be retrieved for some reason.
      */
-    private final String readLineOfInput(final LocalizableMessage prompt) throws CLIException {
+    private final String readLineOfInput(final LocalizableMessage prompt) throws ClientException {
         if (prompt != null) {
-            err.print(wrapText(prompt, MAX_LINE_WIDTH));
+            err.print(wrap(prompt));
             err.print(" ");
         }
         try {
             final String s = reader.readLine();
             if (s == null) {
-                throw CLIException.adaptInputException(new EOFException("End of input"));
+                throw ClientException.adaptInputException(new EOFException("End of input"));
             } else {
                 return s;
             }
         } catch (final IOException e) {
-            throw CLIException.adaptInputException(e);
+            throw ClientException.adaptInputException(e);
+        }
+    }
+
+    /**
+     * Inserts line breaks into the provided buffer to wrap text at no more than the specified column width (80).
+     *
+     * @param msg
+     *            The message to wrap.
+     * @return The wrapped message.
+     */
+    private String wrap(final LocalizableMessage msg) {
+        return wrapText(msg, MAX_LINE_WIDTH);
+    }
+
+    /**
+     * Returns the error stream. Effectively, when an application is in "interactive mode" all the informations should
+     * be written in the stdout.
+     *
+     * @return The error stream that should be used with this application.
+     */
+    private PrintStream getErrStream() {
+        if (isInteractive()) {
+            return out;
+        } else {
+            return err;
         }
     }
 
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/Utils.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/Utils.java
index c1cbd2e..0c48ba0 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/Utils.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/Utils.java
@@ -332,14 +332,15 @@
     /**
      * Checks that the java version.
      *
-     * @throws CLIException
+     * @throws ClientException
      *             If the java version we are running on is not compatible.
      */
-    public static void checkJavaVersion() throws CLIException {
+    public static void checkJavaVersion() throws ClientException {
         final String version = System.getProperty("java.specification.version");
         if (!(Float.valueOf(version) >= 1.6)) {
             final String javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
-            throw new CLIException(ERR_INCOMPATIBLE_JAVA_VERSION.get("1.6", version, javaBin), null);
+            throw new ClientException(ReturnCode.JAVA_VERSION_INCOMPATIBLE, ERR_INCOMPATIBLE_JAVA_VERSION.get("1.6",
+                    version, javaBin), null);
         }
     }
 
diff --git a/opendj-cli/src/test/java/com/forgerock/opendj/cli/ConsoleApplicationTestCase.java b/opendj-cli/src/test/java/com/forgerock/opendj/cli/ConsoleApplicationTestCase.java
index f22ad43..f0aa277 100644
--- a/opendj-cli/src/test/java/com/forgerock/opendj/cli/ConsoleApplicationTestCase.java
+++ b/opendj-cli/src/test/java/com/forgerock/opendj/cli/ConsoleApplicationTestCase.java
@@ -33,6 +33,8 @@
 import org.testng.annotations.Test;
 
 import static org.fest.assertions.Assertions.assertThat;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
 
 /**
  * Unit tests for the console application class.
@@ -80,8 +82,12 @@
             return interactive;
         }
 
-        public void setVerbose(boolean verbose) {
-            this.verbose = verbose;
+        public void setVerbose(boolean v) {
+            verbose = v;
+        }
+
+        public void setInteractive(boolean inter) {
+            interactive = inter;
         }
     }
 
@@ -99,7 +105,7 @@
     public void testWriteLineInErrorStream() throws UnsupportedEncodingException {
         final LocalizableMessage msg = LocalizableMessage.raw("Language is the source of misunderstandings.");
         final MockConsoleApplication ca = MockConsoleApplication.getDefault();
-        ca.errPrint(msg);
+        ca.errPrintln(msg);
         assertThat(ca.getOut()).isEmpty();
         assertThat(ca.getErr()).contains(msg.toString());
     }
@@ -134,4 +140,50 @@
         assertThat(ca.getOut()).isEmpty();
         assertThat(ca.getErr()).contains(msg.toString());
     }
+
+    /**
+     * In non interactive applications, standard messages should be displayed in the stdout(info) and errors to the
+     * stderr (warnings, errors).
+     *
+     * @throws UnsupportedEncodingException
+     */
+    @Test()
+    public void testNonInteractiveApplicationShouldNotStdoutErrors() throws UnsupportedEncodingException {
+        final LocalizableMessage msg = LocalizableMessage.raw("Language is the source of misunderstandings.");
+        final LocalizableMessage msg2 = LocalizableMessage
+                .raw("If somebody wants a sheep, that is a proof that one exists.");
+        final MockConsoleApplication ca = MockConsoleApplication.getDefault();
+
+        assertFalse(ca.isInteractive());
+        ca.errPrintln(msg);
+        assertThat(ca.getOut()).isEmpty();
+        assertThat(ca.getErr()).contains(msg.toString());
+        ca.println(msg2);
+        assertThat(ca.getOut()).contains(msg2.toString());
+        assertThat(ca.getErr()).doesNotContain(msg2.toString());
+    }
+
+    /**
+     * If an application is interactive, all messages should be redirect to the stdout. (info, warnings, errors).
+     *
+     * @throws UnsupportedEncodingException
+     */
+    @Test()
+    public void testInteractiveApplicationShouldStdoutErrors() throws UnsupportedEncodingException {
+        final LocalizableMessage msg = LocalizableMessage.raw("Language is the source of misunderstandings.");
+        final LocalizableMessage msg2 = LocalizableMessage
+                .raw("If somebody wants a sheep, that is a proof that one exists.");
+
+        final MockConsoleApplication ca = MockConsoleApplication.getDefault();
+
+        assertFalse(ca.isInteractive());
+        ca.setInteractive(true);
+        assertTrue(ca.isInteractive());
+        ca.errPrintln(msg);
+        assertThat(ca.getOut()).contains(msg.toString());
+        assertThat(ca.getErr()).isEmpty();
+        ca.println(msg2);
+        assertThat(ca.getOut()).contains(msg2.toString());
+        assertThat(ca.getErr()).isEmpty();
+    }
 }
diff --git a/opendj-cli/src/test/java/com/forgerock/opendj/cli/UtilsTestCase.java b/opendj-cli/src/test/java/com/forgerock/opendj/cli/UtilsTestCase.java
index a1e679e..8df648b 100644
--- a/opendj-cli/src/test/java/com/forgerock/opendj/cli/UtilsTestCase.java
+++ b/opendj-cli/src/test/java/com/forgerock/opendj/cli/UtilsTestCase.java
@@ -29,8 +29,8 @@
 
 public class UtilsTestCase extends CliTestCase {
 
-    @Test(expectedExceptions = CLIException.class)
-    public void testInvalidJavaVersion() throws CLIException {
+    @Test(expectedExceptions = ClientException.class)
+    public void testInvalidJavaVersion() throws ClientException {
         final String original = System.getProperty("java.specification.version");
         System.setProperty("java.specification.version", "1.5");
         try {
@@ -41,7 +41,7 @@
     }
 
     @Test()
-    public void testValidJavaVersion() throws CLIException {
+    public void testValidJavaVersion() throws ClientException {
         Utils.checkJavaVersion();
     }
 }

--
Gitblit v1.10.0