mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

neil_a_wilson
20.39.2006 6ce74d5e7ebd502c1d1d102860b6128f88b65585
Update the command-line setup tool to provide the ability to populate the
database with sample data, like the GUI version.

OpenDS Issue Number: 1021
1 files added
5 files modified
779 ■■■■■ changed files
opends/build.xml 83 ●●●● patch | view | raw | blame | history
opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java 69 ●●●●● patch | view | raw | blame | history
opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties 25 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/ToolMessages.java 119 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/InstallDS.java 364 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/util/CreateTemplate.java 119 ●●●●● patch | view | raw | blame | history
opends/build.xml
@@ -76,10 +76,11 @@
  <property name="dsml.gen.dir"     location="${build.dir}/dsml/gen"     />
  <property name="dsml.classes.dir" location="${build.dir}/dsml/classes" />
    <!-- Properties for use with the Quick Setup.                      -->
    <property name="quicksetup.src.dir"         location="src/quicksetup"             />
    <property name="quicksetup.classes.dir"    location="${build.dir}/quicksetup/classes"    />
  <!-- Properties for use with the Quick Setup.                      -->
  <property name="quicksetup.src.dir" location="src/quicksetup"       />
  <property name="quicksetup.classes.dir"
            location="${build.dir}/quicksetup/classes"                />
  <!-- Properties for code coverage testing.                            -->
  <property name="coverage.dir"         location="build/coverage"            />
  <property name="coverage.report.dir"  
@@ -230,18 +231,18 @@
    <taskdef resource="checkstyletask.properties"
         classpath="${checkstyle.dir}/checkstyle-all-4.1.jar" />
    <checkstyle config="${checkstyle.dir}/opends-checkstyle.xml"
         failOnViolation="true">
      <fileset dir="${src.dir}" includes="**/*.java" />
      <formatter type="plain" />
    </checkstyle>
    <checkstyle config="${checkstyle.dir}/opends-checkstyle.xml"
        failOnViolation="true">
      <fileset dir="${quicksetup.src.dir}" includes="**/*.java" />
    <checkstyle config="${checkstyle.dir}/opends-checkstyle.xml"
         failOnViolation="true">
      <fileset dir="${quicksetup.src.dir}" includes="**/*.java" />
      <formatter type="plain" />
     </checkstyle>
    </checkstyle>
    <checkstyle config="${checkstyle.dir}/opends-doctarget-checkstyle.xml"
         failOnViolation="true">
@@ -294,34 +295,34 @@
    </javac>
  </target>
    <!-- Compile the Quick Setup source files. -->
    <target name="compilequicksetup"
        depends="buildtools,compile"
        description="Compile the Quick Setup source files.">
        <mkdir dir="${quicksetup.classes.dir}" />
        <javac srcdir="${quicksetup.src.dir}" destdir="${quicksetup.classes.dir}" optimize="true"
            debug="on" debuglevel="lines,source" source="1.5" target="1.5"
            deprecation="true" fork="true" memoryInitialSize="${MEM}"
            memoryMaximumSize="${MEM}">
            <compilerarg value="-Xlint:all" />
  <!-- Compile the Quick Setup source files. -->
  <target name="compilequicksetup" depends="buildtools,compile"
          description="Compile the Quick Setup source files.">
            <classpath>
                <fileset dir="${build.dir}/build-tools">
                    <include name="build-tools.jar" />
                </fileset>
                <pathelement path="${classes.dir}"/>
            </classpath>
        </javac>
        <copy todir="${quicksetup.classes.dir}">
            <fileset dir="${quicksetup.src.dir}" includes="**/*.properties, **/*.gif, **/*.png" />
        </copy>
        <copy todir="${quicksetup.classes.dir}">
            <fileset dir="${classes.dir}"
                includes="**/DynamicConstants.class"/>
        </copy>
    <mkdir dir="${quicksetup.classes.dir}" />
    <javac srcdir="${quicksetup.src.dir}" destdir="${quicksetup.classes.dir}"
         optimize="true" debug="on" debuglevel="lines,source" source="1.5"
         target="1.5" deprecation="true" fork="true" memoryInitialSize="${MEM}"
         memoryMaximumSize="${MEM}">
      <compilerarg value="-Xlint:all" />
      <classpath>
        <fileset dir="${build.dir}/build-tools">
          <include name="build-tools.jar" />
        </fileset>
        <pathelement path="${classes.dir}"/>
      </classpath>
    </javac>
    <copy todir="${quicksetup.classes.dir}">
      <fileset dir="${quicksetup.src.dir}"
               includes="**/*.properties, **/*.gif, **/*.png" />
    </copy>
    <copy todir="${quicksetup.classes.dir}">
      <fileset dir="${classes.dir}"
               includes="**/DynamicConstants.class **/CreateTemplate.class" />
    </copy>
  </target>
  <!--
   ! Rebuild the Directory Server without destroying any existing configuration
   ! or data.  It will only overwrite the libraries, classes, and scripts, and
@@ -394,7 +395,7 @@
    <copy todir="${quicksetup.classes.dir}">
        <fileset dir="${classes.dir}"
            includes="**/DynamicConstants.class"/>
            includes="**/DynamicConstants.class **/CreateTemplate.class"/>
    </copy>
    <!-- Generate the quicksetup.jar file -->
@@ -674,9 +675,9 @@
    <preptestng file="${testng.dir}/testng.xml"
                tofile="${unittest.resource.dir}/testng.xml"
                grouplist="${test.groups}" 
        packagelist="${test.packages}"
                packagelist="${test.packages}"
                classList="${test.classes}" 
        methodList="${test.methods}" />
                methodList="${test.methods}" />
@@ -691,7 +692,7 @@
  <!-- Execute Directory Server TestNG unit tests specified from CLI -->
  <target name="testcustom"
      depends="testinit,runtests"
          depends="testinit,runtests"
          description="Execute the Directory Server TestNG unit tests specified from CLI.">
  </target>
@@ -722,7 +723,7 @@
  <!-- Execute the Directory Server TestNG unit tests specified from CLI in text mode with a coverage report. -->
  <target name="testcustomwithcoverage"
      depends="coverage,testcustom"
          depends="coverage,testcustom"
          description="Execute the Directory Server TestNG unit tests specified from CLI in text mode with a coverage report.">
  </target>
opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
@@ -44,6 +44,7 @@
import org.opends.quicksetup.i18n.ResourceProvider;
import org.opends.quicksetup.ui.UIFactory;
import org.opends.quicksetup.util.Utils;
import org.opends.server.util.CreateTemplate;
/**
 * This is an abstract class that is in charge of actually performing the
@@ -708,76 +709,18 @@
   */
  protected File createTemplateFile() throws InstallException
  {
    File templateFile = null;
    String baseDn = getUserData().getDataOptions().getBaseDn();
    int nEntries = getUserData().getDataOptions().getNumberEntries();
    try
    {
      templateFile = File.createTempFile("opends-template-file", ".template");
      templateFile.deleteOnExit();
    } catch (IOException ioe)
      return CreateTemplate.createTemplateFile(
                  getUserData().getDataOptions().getBaseDn(),
                  getUserData().getDataOptions().getNumberEntries());
    }
    catch (IOException ioe)
    {
      String failedMsg = getExceptionMsg("error-creating-temp-file", null, ioe);
      throw new InstallException(InstallException.Type.FILE_SYSTEM_ERROR,
          failedMsg, ioe);
    }
    StringBuffer buf = new StringBuffer();
    buf.append("define suffix=" + baseDn);
    if (nEntries > 0)
    {
      buf.append("\ndefine numusers=" + nEntries);
    }
    buf.append("\n").append("\nbranch: [suffix]").append("\n");
    buf.append("\nbranch: ou=People,[suffix]");
    if (nEntries > 0)
    {
      buf.append("\nsubordinateTemplate: person:[numusers]")
      .append("\n")
          .append("\ntemplate: person")
          .append("\nrdnAttr: uid")
          .append("\nobjectClass: top")
          .append("\nobjectClass: person")
          .append("\nobjectClass: organizationalPerson")
          .append("\nobjectClass: inetOrgPerson")
          .append("\ngivenName: <first>")
          .append("\nsn: <last>")
          .append("\ncn: {givenName} {sn}")
          .append("\ninitials: {givenName:1}")
          .append("<random:chars:ABCDEFGHIJKLMNOPQRSTUVWXYZ:1>{sn:1}")
          .append("\nemployeeNumber: <sequential:0>")
          .append("\nuid: user.{employeeNumber}")
          .append("\nmail: {uid}@maildomain.net")
          .append("\nuserPassword: password")
          .append("\ntelephoneNumber: <random:telephone>")
          .append("\nhomePhone: <random:telephone>")
          .append("\npager: <random:telephone>")
          .append("\nmobile: <random:telephone>")
          .append("\nstreet: <random:numeric:5> <file:streets> Street")
          .append("\nl: <file:cities>")
          .append("\nst: <file:states>")
          .append("\npostalCode: <random:numeric:5>")
          .append("\npostalAddress: {cn}${street}${l}, {st}  {postalCode}")
          .append("\ndescription: This is the description for {cn}.");
    }
    String path = templateFile.getAbsolutePath();
    try
    {
      Utils.createFile(path, buf.toString());
    } catch (IOException ioe)
    {
      String[] arg =
        { path };
      String failedMsg =
          getExceptionMsg("error-writing-to-temp-file", arg, ioe);
      throw new InstallException(InstallException.Type.FILE_SYSTEM_ERROR,
          failedMsg, ioe);
    }
    return templateFile;
  }
  /**
opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
@@ -18,6 +18,9 @@
file containing data that should be added to\n    the Directory Server \
database.  Multiple LDIF files may be provided by\n    using this option \
multiple times.\n\
-d {numEntries}  or   --sampleData {numEntries}\n    Specifies that the \
database should be populated with the specified number\n\    of sample \
entries.\n\
-p {port}  or   --ldapPort {port}\n    Specifies the port on which the \
Directory Server should listen for LDAP\n    communication.\n\
-S  or   --skipPortCheck\n    Skip the check to determine whether the \
@@ -93,7 +96,7 @@
directory-not-writable=You do not have write access on the directory {0}. \
You must have file right access on the Installation directory.
not-enough-disk-space=There is not enough free disk space under {0}.\nAt \
least {1} megabytes of free disk space are required to install OpenDS.
least {1} megabytes of free disk space are required to install OpenDS.
invalid-port-value-range=The LDAP Listener Port must be an integer between \
{0} and {1}.
cannot-bind-priviledged-port=Cannot bind to privileged port {0}.
@@ -102,7 +105,7 @@
not-a-directory-manager-dn=The provided Administrative User DN is not a valid \
DN.
directory-manager-dn-is-config-dn=The provided Administrative User DN is \
used for the configuration of the Directory Server.
used for the configuration of the Directory Server.
not-equal-pwd=The passwords you have provided do not match.
pwd-too-short=The minimum length required for the Administrative User \
password is {0} characters.
@@ -152,9 +155,9 @@
information-icon-tooltip=Information.
#
# Icon paths.  This is done to be able  to provide localizable icons (for
# Icon paths.  This is done to be able  to provide localizable icons (for
# instance for those icons containing a text).  If there is not a localized
# version of the icon it should be left as it is.
# version of the icon it should be left as it is.
# The path specified here are the relative resource name to the images.
#
current-step-icon=images/currentstep.png
@@ -172,9 +175,9 @@
#
welcome-panel-title=Welcome
# The following line contains some HTML tags.  translators should respect them.
# Concerning the URL, depending on how works the product page translators
# have to modify it or not: if the server uses the locale of the browser to display
# a language there is no translation to be done but if we have specific URL for
# Concerning the URL, depending on how works the product page translators
# have to modify it or not: if the server uses the locale of the browser to display
# a language there is no translation to be done but if we have specific URL for
# each language the URL must be localized.
welcome-panel-instructions=The OpenDS QuickSetup tool will ask you for some \
basic server and data configuration settings and will get your server up \
@@ -269,9 +272,9 @@
#
confirm-uninstall-panel-title=Confirm uninstall
# The following line contains some HTML tags.  translators should respect them.
# Concerning the URL, depending on how works the product page translators
# have to modify it or not: if the server uses the locale of the browser to display
# a language there is no translation to be done but if we have specific URL for
# Concerning the URL, depending on how works the product page translators
# have to modify it or not: if the server uses the locale of the browser to display
# a language there is no translation to be done but if we have specific URL for
# each language the URL must be localized.
confirm-uninstall-panel-instructions=The OpenDS Uninstall tool will \
stop the OpenDS server if it is running and will delete all the user data \
@@ -362,4 +365,4 @@
installstatus-installed=OpenDS Server Already Configured<br> \
QuickSetup can only be used with OpenDS Servers that have not yet been \
configured.  The current server:{0}
installstatus-not-installed=The Directory Server is not installed.
installstatus-not-installed=The Directory Server is not installed.
opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -7351,6 +7351,103 @@
  /**
   * The message ID for the message that will be used as the description for the
   * sampleData argument.  This does not take any arguments.
   */
  public static final int MSGID_INSTALLDS_DESCRIPTION_SAMPLE_DATA =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 753;
  /**
   * The message ID for the message that will be used as the heading when asking
   * the user how to populate the database.  This does not take any arguments.
   */
  public static final int MSGID_INSTALLDS_HEADER_POPULATE_TYPE =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 754;
  /**
   * The message ID for the message that will be used as the text for the
   * populate option that will create only the base entry.  This does not take
   * any arguments.
   */
  public static final int MSGID_INSTALLDS_POPULATE_OPTION_BASE_ONLY =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 755;
  /**
   * The message ID for the message that will be used as the text for the
   * populate option that will leave the database emtpy.  This does not take any
   * arguments.
   */
  public static final int MSGID_INSTALLDS_POPULATE_OPTION_LEAVE_EMPTY =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 756;
  /**
   * The message ID for the message that will be used as the text for the
   * populate option that will import data from LDIF.  This does not take any
   * arguments.
   */
  public static final int MSGID_INSTALLDS_POPULATE_OPTION_IMPORT_LDIF =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 757;
  /**
   * The message ID for the message that will be used as the text for the
   * populate option that will create only the base entry.  This does not take
   * any arguments.
   */
  public static final int MSGID_INSTALLDS_POPULATE_OPTION_GENERATE_SAMPLE =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 758;
  /**
   * The message ID for the message that will be used as the text for the prompt
   * asking the user how to populate the database.  This does not take any
   * arguments.
   */
  public static final int MSGID_INSTALLDS_PROMPT_POPULATE_CHOICE =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 759;
  /**
   * The message ID for the message that will be used to indicate that the
   * specified LDIF file does not exist.  This takes a single argument, which is
   * the specified LDIF file.
   */
  public static final int MSGID_INSTALLDS_NO_SUCH_LDIF_FILE =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 780;
  /**
   * The message ID for the message that will be used as the prompt for the
   * number of entries to generate.  This does not take any arguments.
   */
  public static final int MSGID_INSTALLDS_PROMPT_NUM_ENTRIES =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 781;
  /**
   * The message ID for the message that will be used if an error occurs when
   * trying to create the template for generating sample data.  This takes a
   * single argument, which is a message explaining the problem that occurred.
   */
  public static final int MSGID_INSTALLDS_CANNOT_CREATE_TEMPLATE_FILE =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 782;
  /**
   * Associates a set of generic messages with the message IDs defined in this
   * class.
   */
@@ -8873,6 +8970,9 @@
                    "should be added to the Directory Server database.  " +
                    "Multiple LDIF files may be provided by using this " +
                    "option multiple times.");
    registerMessage(MSGID_INSTALLDS_DESCRIPTION_SAMPLE_DATA,
                    "Specifies that the database should be populated with " +
                    "the specified number of sample entries.");
    registerMessage(MSGID_INSTALLDS_DESCRIPTION_LDAPPORT,
                    "Specifies the port on which the Directory Server should " +
                    "listen for LDAP communication.");
@@ -8995,6 +9095,25 @@
    registerMessage(MSGID_INSTALLDS_ERROR_READING_FROM_STDIN,
                    "ERROR:  Unexpected failure while reading from standard " +
                    "input:  %s.");
    registerMessage(MSGID_INSTALLDS_HEADER_POPULATE_TYPE,
                    "Options for populating the database:");
    registerMessage(MSGID_INSTALLDS_POPULATE_OPTION_BASE_ONLY,
                    "Only create the base entry");
    registerMessage(MSGID_INSTALLDS_POPULATE_OPTION_LEAVE_EMPTY,
                    "Leave the database empty");
    registerMessage(MSGID_INSTALLDS_POPULATE_OPTION_IMPORT_LDIF,
                    "Import data from an LDIF file");
    registerMessage(MSGID_INSTALLDS_POPULATE_OPTION_GENERATE_SAMPLE,
                    "Load automatically-generated sample data");
    registerMessage(MSGID_INSTALLDS_PROMPT_POPULATE_CHOICE,
                    "Database population selection:");
    registerMessage(MSGID_INSTALLDS_NO_SUCH_LDIF_FILE,
                    "ERROR:  The specified LDIF file %s does not exist.");
    registerMessage(MSGID_INSTALLDS_PROMPT_NUM_ENTRIES,
                    "Please specify the number of user entries to generate:");
    registerMessage(MSGID_INSTALLDS_CANNOT_CREATE_TEMPLATE_FILE,
                    "ERROR:  Cannot create the template file for generating " +
                    "sample data:  %s.");
    registerMessage(MSGID_MAKELDIF_TAG_INVALID_ARGUMENT_COUNT,
opends/src/server/org/opends/server/tools/InstallDS.java
@@ -41,6 +41,7 @@
import org.opends.server.types.DN;
import org.opends.server.types.ExistingFileBehavior;
import org.opends.server.types.LDIFExportConfig;
import org.opends.server.util.CreateTemplate;
import org.opends.server.util.LDIFWriter;
import org.opends.server.util.PasswordReader;
import org.opends.server.util.args.ArgumentException;
@@ -99,6 +100,35 @@
  /**
   * The value that indicates that only the base entry should be created.
   */
  private static final int POPULATE_TYPE_BASE_ONLY = 1;
  /**
   * The value that indicates that the database should be left empty.
   */
  private static final int POPULATE_TYPE_LEAVE_EMPTY = 2;
  /**
   * The value that indicates that data should be imported from an LDIF file.
   */
  private static final int POPULATE_TYPE_IMPORT_FROM_LDIF = 3;
  /**
   * The value that indicates that the database should be populated with sample
   * data.
   */
  private static final int POPULATE_TYPE_GENERATE_SAMPLE_DATA = 4;
  /**
   * Invokes the <CODE>installMain</CODE> method with the provided arguments.
   *
   * @param  args  The command-line arguments to use for this program.
@@ -159,6 +189,7 @@
    BooleanArgument   skipPortCheck;
    FileBasedArgument rootPWFile;
    IntegerArgument   ldapPort;
    IntegerArgument   sampleData;
    StringArgument    baseDN;
    StringArgument    configClass;
    StringArgument    configFile;
@@ -217,6 +248,12 @@
                                      MSGID_INSTALLDS_DESCRIPTION_IMPORTLDIF);
      argParser.addArgument(importLDIF);
      sampleData = new IntegerArgument("sampledata", 'd', "sampleData", false,
                                       false, true, "{numEntries}", 0, null,
                                       true, 0, false, 0,
                                       MSGID_INSTALLDS_DESCRIPTION_SAMPLE_DATA);
      argParser.addArgument(sampleData);
      ldapPort = new IntegerArgument("ldapport", 'p', "ldapPort", false, false,
                                     true, "{port}", 389, null, true, 1, true,
                                     65535,
@@ -277,6 +314,36 @@
    }
    // Make sure that the user didn't provide conflicting arguments.
    if (addBaseEntry.isPresent())
    {
      if (importLDIF.isPresent())
      {
        int    msgID   = MSGID_TOOL_CONFLICTING_ARGS;
        String message = getMessage(msgID, addBaseEntry.getLongIdentifier(),
                                    importLDIF.getLongIdentifier());
        System.err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
      else if (sampleData.isPresent())
      {
        int    msgID   = MSGID_TOOL_CONFLICTING_ARGS;
        String message = getMessage(msgID, addBaseEntry.getLongIdentifier(),
                                    sampleData.getLongIdentifier());
        System.err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
    }
    else if (importLDIF.isPresent() && sampleData.isPresent())
    {
      int    msgID   = MSGID_TOOL_CONFLICTING_ARGS;
      String message = getMessage(msgID, importLDIF.getLongIdentifier(),
                                  sampleData.getLongIdentifier());
      System.err.println(wrapText(message, MAX_LINE_WIDTH));
      return 1;
    }
    // Make sure the path to the configuration file was given.
    String configFileName;
    if (configFile.isPresent())
@@ -357,128 +424,6 @@
    }
    // Determine the directory base DN.
    LinkedList<DN> baseDNs;
    if (baseDN.isPresent())
    {
      baseDNs = new LinkedList<DN>();
      for (String s : baseDN.getValues())
      {
        try
        {
          baseDNs.add(DN.decode(s));
        }
        catch (Exception e)
        {
          int    msgID   = MSGID_INSTALLDS_CANNOT_PARSE_DN;
          String message = getMessage(msgID, s, e.getMessage());
          System.err.println(wrapText(message, MAX_LINE_WIDTH));
          return 1;
        }
      }
    }
    else if (silentInstall.isPresent())
    {
      try
      {
        baseDNs = new LinkedList<DN>();
        baseDNs.add(DN.decode(baseDN.getDefaultValue()));
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_INSTALLDS_CANNOT_PARSE_DN;
        String message = getMessage(msgID, baseDN.getDefaultValue(),
                                    e.getMessage());
        System.err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
    }
    else
    {
      int    msgID   = MSGID_INSTALLDS_PROMPT_BASEDN;
      String message = getMessage(msgID);
      baseDNs = new LinkedList<DN>();
      baseDNs.add(promptForDN(message, baseDN.getDefaultValue()));
    }
    // Determine whether to import data from LDIF.
    LinkedList<String> ldifFiles;
    if (silentInstall.isPresent())
    {
      if (importLDIF.isPresent())
      {
        ldifFiles = importLDIF.getValues();
      }
      else
      {
        ldifFiles = null;
      }
    }
    else if (importLDIF.isPresent())
    {
      ldifFiles = importLDIF.getValues();
    }
    else if (! baseDN.isPresent())
    {
      int     msgID          = MSGID_INSTALLDS_PROMPT_IMPORT;
      String  message        = getMessage(msgID);
      boolean importFromLDIF = promptForBoolean(message, false);
      if (importFromLDIF)
      {
        msgID   = MSGID_INSTALLDS_PROMPT_IMPORT_FILE;
        message = getMessage(msgID);
        ldifFiles = new LinkedList<String>();
        ldifFiles.add(promptForString(message, null));
      }
      else
      {
        ldifFiles = null;
      }
    }
    else
    {
      ldifFiles = null;
    }
    // Determine whether to add the base entry.
    boolean addBase;
    if (addBaseEntry.isPresent())
    {
      addBase = true;
      if ((ldifFiles != null) && (! ldifFiles.isEmpty()))
      {
        int msgID = MSGID_INSTALLDS_TWO_CONFLICTING_ARGUMENTS;
        String message = getMessage(msgID, addBaseEntry.getLongIdentifier(),
                                    importLDIF.getLongIdentifier());
        System.err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
    }
    else if (silentInstall.isPresent() ||
             ((ldifFiles != null) && (! ldifFiles.isEmpty())))
    {
      addBase = false;
    }
    else if (baseDN.isPresent())
    {
      addBase = false;
    }
    else
    {
      int    msgID   = MSGID_INSTALLDS_PROMPT_ADDBASE;
      String message = getMessage(msgID, baseDNs.getFirst().toString());
      addBase = promptForBoolean(message, true);
    }
    // Determine the LDAP port number.
    int ldapPortNumber;
    if (silentInstall.isPresent() || ldapPort.isPresent())
@@ -619,6 +564,137 @@
    }
    // Determine the directory base DN.
    LinkedList<DN> baseDNs;
    if (baseDN.isPresent())
    {
      baseDNs = new LinkedList<DN>();
      for (String s : baseDN.getValues())
      {
        try
        {
          baseDNs.add(DN.decode(s));
        }
        catch (Exception e)
        {
          int    msgID   = MSGID_INSTALLDS_CANNOT_PARSE_DN;
          String message = getMessage(msgID, s, e.getMessage());
          System.err.println(wrapText(message, MAX_LINE_WIDTH));
          return 1;
        }
      }
    }
    else if (silentInstall.isPresent())
    {
      try
      {
        baseDNs = new LinkedList<DN>();
        baseDNs.add(DN.decode(baseDN.getDefaultValue()));
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_INSTALLDS_CANNOT_PARSE_DN;
        String message = getMessage(msgID, baseDN.getDefaultValue(),
                                    e.getMessage());
        System.err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
    }
    else
    {
      int    msgID   = MSGID_INSTALLDS_PROMPT_BASEDN;
      String message = getMessage(msgID);
      baseDNs = new LinkedList<DN>();
      baseDNs.add(promptForDN(message, baseDN.getDefaultValue()));
    }
    // Determine how to populate the database.
    int                populateType = POPULATE_TYPE_LEAVE_EMPTY;
    int                numUsers     = -1;
    LinkedList<String> ldifFiles    = null;
    if (addBaseEntry.isPresent())
    {
      populateType = POPULATE_TYPE_BASE_ONLY;
    }
    else if (importLDIF.isPresent())
    {
      ldifFiles    = importLDIF.getValues();
      populateType = POPULATE_TYPE_IMPORT_FROM_LDIF;
    }
    else if (sampleData.isPresent())
    {
      try
      {
        numUsers     = sampleData.getIntValue();
        populateType = POPULATE_TYPE_GENERATE_SAMPLE_DATA;
      }
      catch (Exception e)
      {
        // This should never happen.
        e.printStackTrace();
        return 1;
      }
    }
    else if (silentInstall.isPresent())
    {
      populateType = POPULATE_TYPE_LEAVE_EMPTY;
    }
    else
    {
      int msgID = MSGID_INSTALLDS_HEADER_POPULATE_TYPE;
      System.out.println(wrapText(getMessage(msgID), MAX_LINE_WIDTH));
      msgID = MSGID_INSTALLDS_POPULATE_OPTION_BASE_ONLY;
      System.out.println(wrapText("1.  " + getMessage(msgID), MAX_LINE_WIDTH));
      msgID = MSGID_INSTALLDS_POPULATE_OPTION_LEAVE_EMPTY;
      System.out.println(wrapText("2.  " + getMessage(msgID), MAX_LINE_WIDTH));
      msgID = MSGID_INSTALLDS_POPULATE_OPTION_IMPORT_LDIF;
      System.out.println(wrapText("3.  " + getMessage(msgID), MAX_LINE_WIDTH));
      msgID = MSGID_INSTALLDS_POPULATE_OPTION_GENERATE_SAMPLE;
      System.out.println(wrapText("4.  " + getMessage(msgID), MAX_LINE_WIDTH));
      msgID = MSGID_INSTALLDS_PROMPT_POPULATE_CHOICE;
      populateType = promptForInteger(getMessage(msgID), 1, 1, 4);
      System.out.println();
      if (populateType == POPULATE_TYPE_IMPORT_FROM_LDIF)
      {
        ldifFiles = new LinkedList<String>();
        while (true)
        {
          msgID = MSGID_INSTALLDS_PROMPT_IMPORT_FILE;
          String message = getMessage(msgID);
          String path    = promptForString(message, "");
          if (new File(path).exists())
          {
            ldifFiles.add(path);
            System.out.println();
            break;
          }
          else
          {
            msgID   = MSGID_INSTALLDS_NO_SUCH_LDIF_FILE;
            message = getMessage(msgID, path);
            System.err.println(wrapText(message, MAX_LINE_WIDTH));
            System.err.println();
          }
        }
      }
      else if (populateType == POPULATE_TYPE_GENERATE_SAMPLE_DATA)
      {
        msgID = MSGID_INSTALLDS_PROMPT_NUM_ENTRIES;
        String message = getMessage(msgID);
        numUsers = promptForInteger(message, 2000, 0, Integer.MAX_VALUE);
        System.out.println();
      }
    }
    // At this point, we should be able to invoke the ConfigureDS utility to
    // apply the requested configuration.
    ArrayList<String> argList = new ArrayList<String>();
@@ -662,8 +738,8 @@
    }
    // If we should import data or add the base entry, then do so now.
    if (addBase)
    // If we need to create a base LDIF file or a template file, then do so now.
    if (populateType == POPULATE_TYPE_BASE_ONLY)
    {
      // Create a temporary LDIF file that will hold the entry to add.
      if (! silentInstall.isPresent())
@@ -692,8 +768,8 @@
        if (ldifFiles == null)
        {
          ldifFiles = new LinkedList<String>();
          ldifFiles.add(ldifFilePath);
        }
        ldifFiles.add(ldifFilePath);
      }
      catch (Exception e)
      {
@@ -704,6 +780,27 @@
        return 1;
      }
    }
    else if (populateType == POPULATE_TYPE_GENERATE_SAMPLE_DATA)
    {
      try
      {
        File templateFile = CreateTemplate.createTemplateFile(
                                 baseDNs.getFirst().toString(), numUsers);
        if (ldifFiles == null)
        {
          ldifFiles = new LinkedList<String>();
        }
        ldifFiles.add(templateFile.getAbsolutePath());
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_INSTALLDS_CANNOT_CREATE_TEMPLATE_FILE;
        String message = getMessage(msgID, String.valueOf(e));
        System.err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
    }
    if ((ldifFiles != null) && (! ldifFiles.isEmpty()))
    {
@@ -724,11 +821,24 @@
      for (String s : ldifFiles)
      {
        argList.add("-l");
        if (populateType == POPULATE_TYPE_GENERATE_SAMPLE_DATA)
        {
          argList.add("-t");
        }
        else
        {
          argList.add("-l");
        }
        argList.add(s);
      }
      if (addBase)
      if (populateType == POPULATE_TYPE_GENERATE_SAMPLE_DATA)
      {
        argList.add("-S");
        argList.add("0");
      }
      if (populateType == POPULATE_TYPE_BASE_ONLY)
      {
        argList.add("-q");
      }
opends/src/server/org/opends/server/util/CreateTemplate.java
New file
@@ -0,0 +1,119 @@
/*
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  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
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 */
package org.opends.server.util;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedList;
/**
 * This class may be used to generate a MakeLDIF template with a specified base
 * DN and number of user entries.
 */
public class CreateTemplate
{
  /**
   * Creates a MakeLDIF template file using the provided information.
   *
   * @param  baseDN      The base DN for the data in the template file.
   * @param  numEntries  The number of user entries the template file should
   *                     create.
   *
   * @return  The {@code File} object that references the created template file.
   *
   * @throws  IOException  If a problem occurs while writing the template file.
   */
  public static File createTemplateFile(String baseDN, int numEntries)
         throws IOException
  {
    File templateFile = File.createTempFile("opends-install", ".template");
    templateFile.deleteOnExit();
    LinkedList<String> lines = new LinkedList<String>();
    lines.add("define suffix=" + baseDN);
    if (numEntries > 0)
    {
      lines.add("define numusers=" + numEntries);
    }
    lines.add("");
    lines.add("branch: [suffix]");
    lines.add("");
    lines.add("branch: ou=People,[suffix]");
    if (numEntries > 0)
    {
      lines.add("subordinateTemplate: person:[numusers]");
      lines.add("");
      lines.add("template: person");
      lines.add("rdnAttr: uid");
      lines.add("objectClass: top");
      lines.add("objectClass: person");
      lines.add("objectClass: organizationalPerson");
      lines.add("objectClass: inetOrgPerson");
      lines.add("givenName: <first>");
      lines.add("sn: <last>");
      lines.add("cn: {givenName} {sn}");
      lines.add("initials: {givenName:1}" +
                "<random:chars:ABCDEFGHIJKLMNOPQRSTUVWXYZ:1>{sn:1}");
      lines.add("employeeNumber: <sequential:0>");
      lines.add("uid: user.{employeeNumber}");
      lines.add("mail: {uid}@maildomain.net");
      lines.add("userPassword: password");
      lines.add("telephoneNumber: <random:telephone>");
      lines.add("homePhone: <random:telephone>");
      lines.add("pager: <random:telephone>");
      lines.add("mobile: <random:telephone>");
      lines.add("street: <random:numeric:5> <file:streets> Street");
      lines.add("l: <file:cities>");
      lines.add("st: <file:states>");
      lines.add("postalCode: <random:numeric:5>");
      lines.add("postalAddress: {cn}${street}${l}, {st}  {postalCode}");
      lines.add("description: This is the description for {cn}.");
    }
    BufferedWriter writer = new BufferedWriter(new FileWriter(templateFile));
    for (String line : lines)
    {
      writer.write(line);
      writer.newLine();
    }
    writer.flush();
    writer.close();
    return templateFile;
  }
}