From 707c42dc201fef98865f2c2db666df801378e69e Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Tue, 19 Nov 2013 13:50:58 +0000
Subject: [PATCH] OPENDJ-1075 Port server make-ldif tool to the SDK CR-2603

---
 opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools.properties   |   29 +++
 opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConsoleApplication.java |   15 +
 opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/MakeLDIF.java           |  256 ++++++++++++++++++++++++++++++++
 opendj-sdk/opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/MakeLDIFTestCase.java   |  130 ++++++++++++++++
 4 files changed, 426 insertions(+), 4 deletions(-)

diff --git a/opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConsoleApplication.java b/opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConsoleApplication.java
index 98e0b0b..a1d38f6 100755
--- a/opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConsoleApplication.java
+++ b/opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConsoleApplication.java
@@ -49,13 +49,13 @@
  * a console-based application.
  */
 abstract class ConsoleApplication {
-    private final PrintStream err = new PrintStream(System.err);
+    private final PrintStream err;
 
     private final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
 
     private final InputStream in = System.in;
 
-    private final PrintStream out = new PrintStream(System.out);
+    private final PrintStream out;
 
     private final Console console = System.console();
 
@@ -63,7 +63,16 @@
      * Creates a new console application instance.
      */
     ConsoleApplication() {
-        // Nothing to do.
+        this(System.out, System.err);
+    }
+
+    /**
+     * Creates a new console application instance with
+     * provided standard and error out streams.
+     */
+    ConsoleApplication(PrintStream out, PrintStream err) {
+        this.out = out;
+        this.err = err;
     }
 
     /**
diff --git a/opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/MakeLDIF.java b/opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/MakeLDIF.java
new file mode 100644
index 0000000..9f64f90
--- /dev/null
+++ b/opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/MakeLDIF.java
@@ -0,0 +1,256 @@
+/*
+ * 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-2010 Sun Microsystems, Inc.
+ *      Portions Copyright 2013 ForgeRock AS
+ */
+package com.forgerock.opendj.ldap.tools;
+
+import static com.forgerock.opendj.ldap.tools.ToolConstants.*;
+import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
+import static com.forgerock.opendj.ldap.tools.Utils.*;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.ldap.Entry;
+import org.forgerock.opendj.ldif.EntryGenerator;
+import org.forgerock.opendj.ldif.LDIFEntryWriter;
+
+/**
+ * Program that generate LDIF content based on a template.
+ */
+public final class MakeLDIF extends ConsoleApplication {
+
+    private static final int EXIT_CODE_SUCCESS = 0;
+    private static final int EXIT_CODE_FAILURE = 1;
+
+    /** The total number of entries that have been written. */
+    private long numberOfEntriesWritten;
+
+    /**
+     * Main method for MakeLDIF tool.
+     *
+     * @param args
+     *            The command-line arguments provided to this program.
+     */
+    public static void main(final String[] args) {
+        final int retCode = new MakeLDIF().run(args);
+        System.exit(filterExitCode(retCode));
+    }
+
+    /** Run Make LDIF with provided command-line arguments. */
+    int run(final String[] args) {
+        final LocalizableMessage toolDescription = INFO_MAKELDIF_TOOL_DESCRIPTION.get();
+        final ArgumentParser argParser = new ArgumentParser(MakeLDIF.class.getName(), toolDescription,
+                false, true, 1, 1, "template-file-path");
+
+        BooleanArgument showUsage;
+        IntegerArgument randomSeed;
+        StringArgument ldifFile;
+        StringArgument resourcePath;
+        StringArgument constants;
+        try {
+            resourcePath = new StringArgument("resourcepath", 'r', "resourcePath", false, false, true,
+                    INFO_PATH_PLACEHOLDER.get(), null, null, INFO_MAKELDIF_DESCRIPTION_RESOURCE_PATH.get());
+            resourcePath.setHidden(true);
+            argParser.addArgument(resourcePath);
+
+            ldifFile = new StringArgument("ldiffile", OPTION_SHORT_OUTPUT_LDIF_FILENAME,
+                    OPTION_LONG_OUTPUT_LDIF_FILENAME, false, false, true, INFO_FILE_PLACEHOLDER.get(),
+                    null, null, INFO_MAKELDIF_DESCRIPTION_LDIF.get());
+            argParser.addArgument(ldifFile);
+
+            randomSeed = new IntegerArgument("randomseed", OPTION_SHORT_RANDOM_SEED, OPTION_LONG_RANDOM_SEED, false,
+                    false, true, INFO_SEED_PLACEHOLDER.get(), 0, null, INFO_MAKELDIF_DESCRIPTION_SEED.get());
+            argParser.addArgument(randomSeed);
+
+            constants = new StringArgument("constant", 'c', "constant", false, true, true, INFO_FILE_PLACEHOLDER.get(),
+                    null, null, INFO_MAKELDIF_DESCRIPTION_LDIF.get());
+            argParser.addArgument(constants);
+
+            showUsage = new BooleanArgument("help", OPTION_SHORT_HELP, OPTION_LONG_HELP,
+                    INFO_MAKELDIF_DESCRIPTION_HELP.get());
+            argParser.addArgument(showUsage);
+            argParser.setUsageArgument(showUsage, getOutputStream());
+        } catch (ArgumentException ae) {
+            println(ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage()));
+            return EXIT_CODE_FAILURE;
+        }
+
+        // Parse the command-line arguments provided to the program.
+        try {
+            argParser.parseArguments(args);
+        } catch (ArgumentException ae) {
+            println(ERR_ERROR_PARSING_ARGS.get(ae.getMessage()));
+            println(argParser.getUsageMessage());
+            return EXIT_CODE_FAILURE;
+        }
+
+        if (argParser.usageOrVersionDisplayed()) {
+            return 0;
+        }
+        final String templatePath = argParser.getTrailingArguments().get(0);
+        return run(templatePath, resourcePath, ldifFile, randomSeed, constants);
+    }
+
+    /** Run Make LDIF with provided arguments. */
+    private int run(final String templatePath, final StringArgument resourcePath,
+            final StringArgument ldifFile, final IntegerArgument randomSeedArg, final StringArgument constants) {
+        EntryGenerator generator = null;
+        LDIFEntryWriter writer = null;
+        try {
+            generator = createGenerator(templatePath, resourcePath, randomSeedArg, constants);
+            if (generator == null) {
+                return EXIT_CODE_FAILURE;
+            }
+
+            if (generator.hasWarning()) {
+                for (LocalizableMessage warn : generator.getWarnings()) {
+                    println(warn);
+                }
+            }
+
+            if (ldifFile.isPresent()) {
+                try {
+                    writer = new LDIFEntryWriter(new BufferedWriter(new FileWriter(new File(ldifFile.getValue()))));
+                } catch (IOException e) {
+                    println(ERR_MAKELDIF_UNABLE_TO_CREATE_LDIF.get(ldifFile.getValue(), e.getMessage()));
+                    return EXIT_CODE_FAILURE;
+                }
+            } else {
+                writer = new LDIFEntryWriter(getOutputStream());
+            }
+
+            if (!generateEntries(generator, writer, ldifFile)) {
+                return EXIT_CODE_FAILURE;
+            }
+
+            println(INFO_MAKELDIF_PROCESSING_COMPLETE.get(numberOfEntriesWritten));
+
+        } finally {
+            closeIfNotNull(generator, writer);
+        }
+
+        return EXIT_CODE_SUCCESS;
+    }
+
+    /**
+     * Returns the initialized generator, or null if a problem occurs.
+     */
+    private EntryGenerator createGenerator(final String templatePath, final StringArgument resourcePath,
+            final IntegerArgument randomSeedArg, final StringArgument constants) {
+        final EntryGenerator generator = new EntryGenerator(templatePath);
+
+        if (resourcePath.isPresent()) {
+            final File resourceDir = new File(resourcePath.getValue());
+            if (!resourceDir.exists()) {
+                println(ERR_MAKELDIF_NO_SUCH_RESOURCE_DIRECTORY.get(resourcePath.getValue()));
+                generator.close();
+                return null;
+            }
+            generator.setResourcePath(resourcePath.getValue());
+        }
+
+        if (randomSeedArg.isPresent()) {
+            try {
+                generator.setRandomSeed(randomSeedArg.getIntValue());
+            } catch (ArgumentException ae) {
+                println(ERR_ERROR_PARSING_ARGS.get(ae.getMessage()));
+                generator.close();
+                return null;
+            }
+        }
+
+        if (constants.isPresent()) {
+            if (!addConstantsToGenerator(constants, generator)) {
+                generator.close();
+                return null;
+            }
+        }
+
+        // Force initialization of generator
+        try {
+            generator.hasNext();
+        } catch (IOException e) {
+            println(ERR_MAKELDIF_EXCEPTION_DURING_PARSE.get(e.getMessage()));
+            generator.close();
+            return null;
+        }
+
+        return generator;
+    }
+
+    /**
+     * Returns true if all constants are added to generator, false otherwise.
+     */
+    private boolean addConstantsToGenerator(StringArgument constants, EntryGenerator generator) {
+        for (final String constant : constants.getValues()) {
+            final String[] chunks = constant.split("=");
+            if (chunks.length != 2) {
+                println(ERR_CONSTANT_ARG_CANNOT_DECODE.get(constant));
+                return false;
+            }
+            generator.setConstant(chunks[0], chunks[1]);
+        }
+        return true;
+    }
+
+    /**
+     * Returns true if generation is successfull, false otherwise.
+     */
+    private boolean generateEntries(final EntryGenerator generator, final LDIFEntryWriter writer,
+            final StringArgument ldifFile) {
+        try {
+            while (generator.hasNext()) {
+                final Entry entry = generator.readEntry();
+                try {
+                    writer.writeEntry(entry);
+                } catch (IOException e) {
+                    println(ERR_MAKELDIF_ERROR_WRITING_LDIF.get(ldifFile.getValue(), e.getMessage()));
+                    return false;
+                }
+                if ((++numberOfEntriesWritten % 1000) == 0) {
+                    println(INFO_MAKELDIF_PROCESSED_N_ENTRIES.get(numberOfEntriesWritten));
+                }
+            }
+        } catch (Exception e) {
+            println(ERR_MAKELDIF_EXCEPTION_DURING_PROCESSING.get(e.getMessage()));
+            return false;
+        }
+        return true;
+    }
+
+    private MakeLDIF() {
+        // nothing to do
+    }
+
+    // To allow tests
+    MakeLDIF(PrintStream out, PrintStream err) {
+        super(out, err);
+    }
+
+}
diff --git a/opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools.properties b/opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools.properties
index 8f7902e..d630efb 100755
--- a/opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools.properties
+++ b/opendj-sdk/opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools.properties
@@ -117,7 +117,6 @@
 INFO_TIME_IN_HOURS_MINUTES_SECONDS=%d hours, %d minutes, %d seconds
 INFO_TIME_IN_DAYS_HOURS_MINUTES_SECONDS=%d days, %d hours, %d minutes, %d \
  seconds
-INFO_ARGPARSER_USAGE=Usage:
 INFO_SUBCMDPARSER_WHERE_OPTIONS_INCLUDE=Command options:
 ERR_MENU_BAD_CHOICE_SINGLE=Invalid response. Please enter a valid \
 menu option
@@ -472,3 +471,31 @@
  files and report the differences in LDIF format
 INFO_LDIFSEARCH_TOOL_DESCRIPTION=This utility can be used to perform search \
  operations against entries contained in an LDIF file
+ #
+ # MakeLDIF tool
+ #
+INFO_MAKELDIF_TOOL_DESCRIPTION=This utility can be used to generate LDIF \
+ data based on a definition in a template file
+INFO_SEED_PLACEHOLDER={seed}
+INFO_PATH_PLACEHOLDER={path}
+INFO_MAKELDIF_DESCRIPTION_LDIF=The path to the LDIF file to be written
+INFO_MAKELDIF_DESCRIPTION_SEED=The seed to use to initialize the random \
+ number generator
+INFO_MAKELDIF_DESCRIPTION_HELP=Show this usage information
+INFO_MAKELDIF_DESCRIPTION_RESOURCE_PATH=Path to look for \
+ MakeLDIF resources (e.g., data files)
+ERR_MAKELDIF_NO_SUCH_RESOURCE_DIRECTORY=The specified resource \
+ directory %s could not be found
+INFO_MAKELDIF_PROCESSED_N_ENTRIES=Processed %d entries
+INFO_MAKELDIF_PROCESSING_COMPLETE=LDIF processing complete. %d entries \
+ written
+ERR_MAKELDIF_EXCEPTION_DURING_PARSE=An error occurred while \
+ parsing template file :  %s
+ERR_MAKELDIF_UNABLE_TO_CREATE_LDIF=An error occurred while \
+ attempting to open LDIF file %s for writing:  %s
+ERR_MAKELDIF_ERROR_WRITING_LDIF=An error occurred while writing data \
+ to LDIF file %s:  %s
+ERR_MAKELDIF_EXCEPTION_DURING_PROCESSING=An error occurred while \
+ processing :  %s
+ERR_CONSTANT_ARG_CANNOT_DECODE=Unable to parse a constant argument, \
+ expecting name=value but got %s
diff --git a/opendj-sdk/opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/MakeLDIFTestCase.java b/opendj-sdk/opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/MakeLDIFTestCase.java
new file mode 100644
index 0000000..d5b84fc
--- /dev/null
+++ b/opendj-sdk/opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/MakeLDIFTestCase.java
@@ -0,0 +1,130 @@
+/*
+ * 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 2013 ForgeRock AS.
+ */
+package com.forgerock.opendj.ldap.tools;
+
+import static org.fest.assertions.Assertions.*;
+
+import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+
+import org.forgerock.i18n.LocalizableMessage;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import com.forgerock.opendj.util.StaticUtils;
+
+@SuppressWarnings("javadoc")
+public class MakeLDIFTestCase extends ToolsTestCase {
+
+    @DataProvider(name = "validArguments")
+    Object[][] createValidArguments() throws Exception {
+        Object[][] data = new Object[][] {
+            { args("-c", "numusers=1", "example.template"),
+              // 2 base entries + users
+              expectedErrOutput(INFO_MAKELDIF_PROCESSING_COMPLETE.get(3)) },
+
+            { args("-c", "numusers=5", "example.template"),
+              // 2 base entries + users
+              expectedErrOutput(INFO_MAKELDIF_PROCESSING_COMPLETE.get(7)) },
+        };
+        return data;
+    }
+
+    @DataProvider(name = "invalidArguments")
+    Object[][] createInValidArguments() throws Exception {
+        Object[][] data = new Object[][] {
+            { // check that usage is written to output when arguments are invalid
+              args(),
+              expectedErrOutput(INFO_MAKELDIF_TOOL_DESCRIPTION.get()) },
+
+            { // check that there is an argument error when no arg provided
+              args(),
+              expectedErrOutput(ERR_ERROR_PARSING_ARGS.get("")) },
+
+            { args("-r", "unknown/path" , "example.template"),
+              expectedErrOutput(ERR_MAKELDIF_NO_SUCH_RESOURCE_DIRECTORY.get("unknown/path")) },
+
+            { args("-o", "unknown/path" , "example.template"),
+              expectedErrOutput(ERR_MAKELDIF_UNABLE_TO_CREATE_LDIF.get("unknown/path", "")) },
+
+            { args("-s", "non-numeric" , "example.template"),
+              expectedErrOutput(ERR_ERROR_PARSING_ARGS.get("")) },
+        };
+        return data;
+    }
+
+    @Test(dataProvider = "validArguments")
+    public void testRunValidArguments(String[] arguments, LocalizableMessage expectedErrOutput)
+            throws Exception {
+        run(arguments, true, expectedErrOutput);
+    }
+
+    @Test(dataProvider = "invalidArguments")
+    public void testRunInvalidArguments(String[] arguments, LocalizableMessage expectedErrOutput)
+            throws Exception {
+        run(arguments, false, expectedErrOutput);
+    }
+
+    private void run(String[] arguments, boolean expectsResults, LocalizableMessage expectedErrOutput)
+            throws UnsupportedEncodingException {
+        PrintStream outStream = null;
+        PrintStream errStream = null;
+        try {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            outStream = new PrintStream(out);
+            ByteArrayOutputStream err = new ByteArrayOutputStream();
+            errStream = new PrintStream(err);
+
+            MakeLDIF makeLDIF = new MakeLDIF(outStream, errStream);
+            makeLDIF.run(arguments);
+
+            if (expectsResults) {
+                assertThat(out.size()).isGreaterThan(0);
+            } else {
+                assertThat(out.size()).isEqualTo(0);
+            }
+
+            assertThat(err.toString("UTF-8")).contains(Utils.wrapText(expectedErrOutput, Utils.MAX_LINE_WIDTH));
+        } finally {
+            StaticUtils.closeSilently(outStream, errStream);
+        }
+    }
+
+    /** Arguments passed to the command */
+    private String[] args(String...arguments) {
+        return arguments;
+    }
+
+    /** A message the error output is expected to contain. */
+    private LocalizableMessage expectedErrOutput(LocalizableMessage val) {
+        return val;
+    }
+
+
+}

--
Gitblit v1.10.0