| opends/build.xml | ●●●●● patch | view | raw | blame | history | |
| opends/resource/README | ●●●●● patch | view | raw | blame | history | |
| opends/resource/setup.bat | ●●●●● patch | view | raw | blame | history | |
| opends/resource/setup.sh | ●●●●● patch | view | raw | blame | history | |
| opends/src/server/org/opends/server/messages/ToolMessages.java | ●●●●● patch | view | raw | blame | history | |
| opends/src/server/org/opends/server/tools/InstallDS.java | ●●●●● patch | view | raw | blame | history | |
| opends/src/server/org/opends/server/util/PasswordReader.java | ●●●●● patch | view | raw | blame | history | |
| opends/src/server/org/opends/server/util/StaticUtils.java | ●●●●● patch | view | raw | blame | history |
opends/build.xml
@@ -452,6 +452,15 @@ <fileset file="${resource.dir}/README" /> </copy> <copy todir="${pdir}"> <fileset file="${resource.dir}/setup.sh" /> </copy> <copy todir="${pdir}"> <fileset file="${resource.dir}/setup.bat" /> </copy> <chmod file="${pdir}/*.sh" perm="755" /> <chmod file="${pdir}/bin/*.sh" perm="755" /> </target> opends/resource/README
@@ -3,6 +3,10 @@ This archive contains the OpenDS Directory Server. Complete documentation for this product may be found online at https://OpenDS.dev.java.net/. To configure the server, run the setup.sh script on UNIX-based platforms, or the setup.bat batch file on Windows. To start the server, run bin/start-ds.sh on UNIX-based platforms, or bin\start-ds.bat on Windows systems. This product is made available under the Common Development and Distribution License (CDDL). The complete text for this license, and for alternate licenses of included components, may be found in the legal-notices directory. opends/resource/setup.bat
New file @@ -0,0 +1,56 @@ @echo off rem CDDL HEADER START rem rem The contents of this file are subject to the terms of the rem Common Development and Distribution License, Version 1.0 only rem (the "License"). You may not use this file except in compliance rem with the License. rem rem You can obtain a copy of the license at rem trunk/opends/resource/legal-notices/OpenDS.LICENSE rem or https://OpenDS.dev.java.net/OpenDS.LICENSE. rem See the License for the specific language governing permissions rem and limitations under the License. rem rem When distributing Covered Code, include this CDDL HEADER in each rem file and include the License file at rem trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, rem add the following below this CDDL HEADER, with the fields enclosed rem by brackets "[]" replaced with your own identifying * information: rem Portions Copyright [yyyy] [name of copyright owner] rem rem CDDL HEADER END rem rem rem Portions Copyright 2006 Sun Microsystems, Inc. setlocal set DIR_HOME=%~dP0 set INSTANCE_ROOT=%DIR_HOME% if "%JAVA_BIN%" == "" goto noJavaBin goto setClassPath :noJavaBin if "%JAVA_HOME%" == "" goto noJavaHome if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome set JAVA_BIN="%JAVA_HOME%\bin\java.exe" goto setClassPath :noJavaHome echo Error: JAVA_HOME environment variable is not set. echo Please set it to a valid Java 5 installation. goto end :setClassPath FOR %%x in (%DIR_HOME%\lib\*.jar) DO call "%DIR_HOME%\bin\setcp.bat" %%x cd %DIR_HOME% %JAVA_BIN% %JAVA_ARGS% -classpath "%CLASSPATH%" org.opends.server.tools.InstallDS --configClass org.opends.server.config.ConfigFileHandler --configFile %DIR_HOME%\config\config.ldif %* :end opends/resource/setup.sh
New file @@ -0,0 +1,83 @@ #!/bin/sh # # 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. # Capture the current working directory so that we can change to it later. # Then apture the location of this script and the Directory Server instance # root so that we can use them to create appropriate paths. WORKING_DIR=`pwd` cd `dirname $0` SCRIPT_DIR=`pwd` INSTANCE_ROOT=${SCRIPT_DIR} export INSTANCE_ROOT cd ${WORKING_DIR} # See if JAVA_HOME is set. If not, then see if there is a java executable in # the path and try to figure it out. if test -z "${JAVA_BIN}" then if test -z "${JAVA_HOME}" then JAVA_BIN=`which java 2> /dev/null` if test $? -eq 0 then export JAVA_BIN else echo "Please set JAVA_HOME to the root of a Java 5.0 installation." exit 1 fi else JAVA_BIN=${JAVA_HOME}/bin/java export JAVA_BIN fi fi CLASSPATH=${INSTANCE_ROOT}/classes for JAR in ${INSTANCE_ROOT}/lib/*.jar do CLASSPATH=${CLASSPATH}:${JAR} done export CLASSPATH # Determine whether the detected Java environment is acceptable for use. ${JAVA_BIN} ${JAVA_ARGS} org.opends.server.tools.InstallDS -t if test $? -ne 0 then echo "ERROR: The detected Java version could not be used. Please set " echo " JAVA_HOME to the root of a Java 5.0 installation." exit 1 fi ${JAVA_BIN} ${JAVA_ARGS} org.opends.server.tools.InstallDS \ --configClass org.opends.server.config.ConfigFileHandler \ --configFile ${INSTANCE_ROOT}/config/config.ldif "${@}" opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -4756,6 +4756,453 @@ /** * The message ID for the message that will be used as the description for the * testOnly argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_TESTONLY = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 485; /** * The message ID for the message that will be used as the description for the * programName argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_PROGNAME = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 486; /** * The message ID for the message that will be used as the description for the * configFile argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_CONFIG_FILE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 487; /** * The message ID for the message that will be used as the description for the * configClass argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_CONFIG_CLASS = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 488; /** * The message ID for the message that will be used as the description for the * silentInstall argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_SILENT = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 489; /** * The message ID for the message that will be used as the description for the * baseDN argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_BASEDN = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 490; /** * The message ID for the message that will be used as the description for the * addBaseEntry argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_ADDBASE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 491; /** * The message ID for the message that will be used as the description for the * importLDIF argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_IMPORTLDIF = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 492; /** * The message ID for the message that will be used as the description for the * ldapPort argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_LDAPPORT = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 493; /** * The message ID for the message that will be used as the description for the * skipPortCheck argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_SKIPPORT = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 494; /** * The message ID for the message that will be used as the description for the * rootDN argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_ROOTDN = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 495; /** * The message ID for the message that will be used as the description for the * rootPassword argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_ROOTPW = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 496; /** * The message ID for the message that will be used as the description for the * rootPasswordFile argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_ROOTPWFILE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 497; /** * The message ID for the message that will be used as the description for the * help argument. This does not take any arguments. */ public static final int MSGID_INSTALLDS_DESCRIPTION_HELP = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 498; /** * The message ID for the message that will be used if the user did not * specify the path to the Directory Server configuration file. This takes a * single argument, which is the name of the command-line option that should * be used to provide that information. */ public static final int MSGID_INSTALLDS_NO_CONFIG_FILE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 499; /** * The message ID for the message that will be used if an error occurs while * initializing the Directory Server JMX subsystem. This takes two arguments, * which are the path to the Directory Server configuration file and a message * explaining the problem that occurred. */ public static final int MSGID_INSTALLDS_CANNOT_INITIALIZE_JMX = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 500; /** * The message ID for the message that will be used if an error occurs while * initializing the Directory Server configuration. This takes two * arguments, which are the path to the Directory Server configuration file * and a message explaining the problem that occurred. */ public static final int MSGID_INSTALLDS_CANNOT_INITIALIZE_CONFIG = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 501; /** * The message ID for the message that will be used if an error occurs while * initializing the Directory Server schema. This takes two arguments, which * are the path to the Directory Server configuration file and a message * explaining the problem that occurred. */ public static final int MSGID_INSTALLDS_CANNOT_INITIALIZE_SCHEMA = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 502; /** * The message ID for the message that will be used if an error occurs while * trying to parse a string as a DN. This takes two arguments, which are the * DN string and a message explaining the problem that occurred. */ public static final int MSGID_INSTALLDS_CANNOT_PARSE_DN = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 503; /** * The message ID for the message that will be used as the prompt to provide * the directory base DN. It does not take any arguments. */ public static final int MSGID_INSTALLDS_PROMPT_BASEDN = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 504; /** * The message ID for the message that will be used as the prompt to determine * whether to import data from LDIF. It does not take any arguments. */ public static final int MSGID_INSTALLDS_PROMPT_IMPORT = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 505; /** * The message ID for the message that will be used as the prompt to provide * the path to the LDIF file to import. It does not take any arguments. */ public static final int MSGID_INSTALLDS_PROMPT_IMPORT_FILE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 506; /** * The message ID for the message that will be used if two conflicting * arguments were provided to the program. This takes two arguments, which * are the long forms of the conflicting arguments. */ public static final int MSGID_INSTALLDS_TWO_CONFLICTING_ARGUMENTS = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 507; /** * The message ID for the message that will be used as the prompt to determine * whether to add the base entry. It does not take any arguments. */ public static final int MSGID_INSTALLDS_PROMPT_ADDBASE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 508; /** * The message ID for the message that will be used as the prompt to determine * the LDAP port number to use. It does not take any arguments. */ public static final int MSGID_INSTALLDS_PROMPT_LDAPPORT = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 509; /** * The message ID for the message that will be used if an error occurs while * attempting to bind to a privileged port. This takes two arguments, which * are the port number and a message explaining the problem that occurred. */ public static final int MSGID_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 510; /** * The message ID for the message that will be used if an error occurs while * attempting to bind to a non-privileged port. This takes two arguments, * which are the port number and a message explaining the problem that * occurred. */ public static final int MSGID_INSTALLDS_CANNOT_BIND_TO_PORT = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 511; /** * The message ID for the message that will be used as the prompt to determine * the initial root DN. It does not take any arguments. */ public static final int MSGID_INSTALLDS_PROMPT_ROOT_DN = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 512; /** * The message ID for the message that will be used if no root password was * provided when performing a silent installation. This takes two arguments, * which are the long forms of the root password and root password file * arguments. */ public static final int MSGID_INSTALLDS_NO_ROOT_PASSWORD = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 513; /** * The message ID for the message that will be used as the prompt to request * the initial root password for the first time. This does not take any * arguments. */ public static final int MSGID_INSTALLDS_PROMPT_ROOT_PASSWORD = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 514; /** * The message ID for the message that will be used as the prompt to confirm * the initial root password. This does not take any arguments. */ public static final int MSGID_INSTALLDS_PROMPT_CONFIRM_ROOT_PASSWORD = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 515; /** * The message ID for the message that will be used to indicate that the * server configuration is being updated. This does not take any arguments. */ public static final int MSGID_INSTALLDS_STATUS_CONFIGURING_DS = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 516; /** * The message ID for the message that will be used to indicate that the * base LDIF file is being created. This does not take any arguments. */ public static final int MSGID_INSTALLDS_STATUS_CREATING_BASE_LDIF = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 517; /** * The message ID for the message that will be used if an error occurs while * creating the base LDIF file. This takes a single argument, which is a * message explaining the problem that occurred. */ public static final int MSGID_INSTALLDS_CANNOT_CREATE_BASE_ENTRY_LDIF = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 518; /** * The message ID for the message that will be used to indicate that the * LDIF data is being imported. This does not take any arguments. */ public static final int MSGID_INSTALLDS_STATUS_IMPORTING_LDIF = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 519; /** * The message ID for the message that will be used to indicate that the setup * process was successful. This does not take any arguments. */ public static final int MSGID_INSTALLDS_STATUS_SUCCESS = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 520; /** * The message ID for the message that will be used as the prompt value for * Boolean "true" or "yes" values. */ public static final int MSGID_INSTALLDS_PROMPT_VALUE_YES = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 521; /** * The message ID for the message that will be used as the prompt value for * Boolean "false" or "no" values. */ public static final int MSGID_INSTALLDS_PROMPT_VALUE_NO = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 522; /** * The message ID for the message that will be used to indicate that the * Boolean value could not be interpreted. This does not take any arguments. */ public static final int MSGID_INSTALLDS_INVALID_YESNO_RESPONSE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 523; /** * The message ID for the message that will be used to indicate that the * response value could not be interpreted as an integer. This does not take * any arguments. */ public static final int MSGID_INSTALLDS_INVALID_INTEGER_RESPONSE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 524; /** * The message ID for the message that will be used to indicate that the * provided integer value was below the lower bound. This takes a single * argument, which is the lower bound. */ public static final int MSGID_INSTALLDS_INTEGER_BELOW_LOWER_BOUND = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 525; /** * The message ID for the message that will be used to indicate that the * provided integer value was above the upper bound. This takes a single * argument, which is the upper bound. */ public static final int MSGID_INSTALLDS_INTEGER_ABOVE_UPPER_BOUND = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 526; /** * The message ID for the message that will be used to indicate that the * response value could not be interpreted as a DN. This does not take any * arguments. */ public static final int MSGID_INSTALLDS_INVALID_DN_RESPONSE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 527; /** * The message ID for the message that will be used to indicate that the * response value was an invalid zero-length string. This does not take any * arguments. */ public static final int MSGID_INSTALLDS_INVALID_STRING_RESPONSE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 528; /** * The message ID for the message that will be used to indicate that the * response value was an invalid zero-length string. This does not take any * arguments. */ public static final int MSGID_INSTALLDS_INVALID_PASSWORD_RESPONSE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 529; /** * The message ID for the message that will be used to indicate that the * provided password values do not match. This does not take any arguments. */ public static final int MSGID_INSTALLDS_PASSWORDS_DONT_MATCH = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 530; /** * The message ID for the message that will be used if an error occurs while * reading from standard input. This takes a single argument, which is a * message explaining the problem that occurred. */ public static final int MSGID_INSTALLDS_ERROR_READING_FROM_STDIN = CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 531; /** * Associates a set of generic messages with the message IDs defined in this * class. */ @@ -6336,6 +6783,149 @@ registerMessage(MSGID_CONFIGDS_WROTE_UPDATED_CONFIG, "Successfully wrote the updated Directory Server " + "configuration."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_TESTONLY, "Just verify that the JVM can be started properly."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_PROGNAME, "The setup command used to invoke this program."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_CONFIG_FILE, "The path to the Directory Server configuration file."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_CONFIG_CLASS, "The fully-qualified name of the Java class to use as " + "the Directory Server configuration handler. If this is " + "not provided, then a default of " + ConfigFileHandler.class.getName() + " will be used."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_SILENT, "Perform a silent installation."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_BASEDN, "Specifies the base DN for user information in the " + "Directory Server. Multiple base DNs may be provided " + "by using this option multiple times."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_ADDBASE, "Indicates whether to create the base entry in the " + "Directory Server database."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_IMPORTLDIF, "Specifies the path to an LDIF file containing data that " + "should be added to the Directory Server database. " + "Multiple LDIF files may be provided by using this " + "option multiple times."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_LDAPPORT, "Specifies the port on which the Directory Server should " + "listen for LDAP communication."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_SKIPPORT, "Skip the check to determine whether the specified LDAP " + "port is usable."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_ROOTDN, "Specifies the DN for the initial root user for the " + "Directory Server."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_ROOTPW, "Specifies the password for the initial root user for " + "the Directory Server."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_ROOTPWFILE, "Specifies the path to a file containing the password " + "for the initial root user for the Directory Server."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_HELP, "Displays usage information for this program."); registerMessage(MSGID_INSTALLDS_NO_CONFIG_FILE, "ERROR: No configuration file path was provided (use " + "the %s argument)."); registerMessage(MSGID_INSTALLDS_CANNOT_INITIALIZE_JMX, "An error occurred while attempting to initialize the " + "Directory Server JMX subsystem based on the information " + "in configuration file %s: %s."); registerMessage(MSGID_INSTALLDS_CANNOT_INITIALIZE_CONFIG, "An error occurred while attempting to process the " + "Directory Server configuration file %s: %s."); registerMessage(MSGID_INSTALLDS_CANNOT_INITIALIZE_SCHEMA, "An error occurred while attempting to initialize the " + "Directory Server schema based on the information in " + "configuration file %s: %s."); registerMessage(MSGID_INSTALLDS_CANNOT_PARSE_DN, "An error occurred while attempting to parse the string " + "\"%s\" as a valid DN: %s."); registerMessage(MSGID_INSTALLDS_PROMPT_BASEDN, "What do you wish to use as the base DN for the " + "directory data?"); registerMessage(MSGID_INSTALLDS_PROMPT_IMPORT, "Do you wish to populate the directory database with " + "information from an existing LDIF file?"); registerMessage(MSGID_INSTALLDS_PROMPT_IMPORT_FILE, "Please specify the path to the LDIF file containing " + "the data to import."); registerMessage(MSGID_INSTALLDS_TWO_CONFLICTING_ARGUMENTS, "ERROR: You may not provide both the %s and the %s " + "arguments at the same time."); registerMessage(MSGID_INSTALLDS_PROMPT_ADDBASE, "Would you like to have the base %s entry automatically " + "created in the directory database?"); registerMessage(MSGID_INSTALLDS_PROMPT_LDAPPORT, "On which port would you like the Directory Server to " + "accept connections from LDAP clients?"); registerMessage(MSGID_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT, "ERROR: Unable to bind to port %d: %s. This port may " + "already be in use, or if you are a nonroot user then " + "you may not be allowed to use port numbers 1024 or " + "below."); registerMessage(MSGID_INSTALLDS_CANNOT_BIND_TO_PORT, "ERROR: Unable to bind to port %d: %s. This port may " + "already be in use, or you may not have permission to " + "bind to it."); registerMessage(MSGID_INSTALLDS_PROMPT_ROOT_DN, "What would you like to use as the initial root user DN " + "for the Directory Server?"); registerMessage(MSGID_INSTALLDS_NO_ROOT_PASSWORD, "ERROR: No password was provided for the initial root "+ "user. When performing a silent installation, this must " + "be provided using either the %s or the %s argument."); registerMessage(MSGID_INSTALLDS_PROMPT_ROOT_PASSWORD, "Please provide the password to use for the initial root " + "user"); registerMessage(MSGID_INSTALLDS_PROMPT_CONFIRM_ROOT_PASSWORD, "Please re-enter the password for confirmation"); registerMessage(MSGID_INSTALLDS_STATUS_CONFIGURING_DS, "Applying the requested configuration to the " + "Directory Server...."); registerMessage(MSGID_INSTALLDS_STATUS_CREATING_BASE_LDIF, "Creating a temporary LDIF file with the initial base " + "entry contents...."); registerMessage(MSGID_INSTALLDS_CANNOT_CREATE_BASE_ENTRY_LDIF, "An error occurred while attempting to create the " + "base LDIF file: %s."); registerMessage(MSGID_INSTALLDS_STATUS_IMPORTING_LDIF, "Importing the LDIF data into the Directory Server " + "database...."); registerMessage(MSGID_INSTALLDS_STATUS_SUCCESS, "The OpenDS Directory Service setup process has " + "completed successfully."); registerMessage(MSGID_INSTALLDS_PROMPT_VALUE_YES, "yes"); registerMessage(MSGID_INSTALLDS_PROMPT_VALUE_NO, "no"); registerMessage(MSGID_INSTALLDS_INVALID_YESNO_RESPONSE, "ERROR: The provided value could not be interpreted as " + "a yes or no response. Please enter a response of " + "either \"yes\" or \"no\"."); registerMessage(MSGID_INSTALLDS_INVALID_INTEGER_RESPONSE, "ERROR: The provided response could not be interpreted " + "as an integer. Please provide the repsonse as an " + "integer value."); registerMessage(MSGID_INSTALLDS_INTEGER_BELOW_LOWER_BOUND, "ERROR: The provided value is less than the lowest " + "allowed value of %d."); registerMessage(MSGID_INSTALLDS_INTEGER_ABOVE_UPPER_BOUND, "ERROR: The provided value is greater than the largest " + "allowed value of %d."); registerMessage(MSGID_INSTALLDS_INVALID_DN_RESPONSE, "ERROR: The provided response could not be interpreted " + "as an LDAP DN."); registerMessage(MSGID_INSTALLDS_INVALID_STRING_RESPONSE, "ERROR: The response value may not be an empty string."); registerMessage(MSGID_INSTALLDS_INVALID_PASSWORD_RESPONSE, "ERROR: The password value may not be an empty string."); registerMessage(MSGID_INSTALLDS_PASSWORDS_DONT_MATCH, "ERROR: The provided password values do not match."); registerMessage(MSGID_INSTALLDS_ERROR_READING_FROM_STDIN, "ERROR: Unexpected failure while reading from standard " + "input: %s."); } } opends/src/server/org/opends/server/tools/InstallDS.java
New file @@ -0,0 +1,1140 @@ /* * 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.tools; import java.io.ByteArrayOutputStream; import java.io.File; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import org.opends.server.config.ConfigFileHandler; import org.opends.server.core.DirectoryServer; import org.opends.server.types.DN; import org.opends.server.types.ExistingFileBehavior; import org.opends.server.types.LDIFExportConfig; import org.opends.server.util.LDIFWriter; import org.opends.server.util.PasswordReader; import org.opends.server.util.args.ArgumentException; import org.opends.server.util.args.ArgumentParser; import org.opends.server.util.args.BooleanArgument; import org.opends.server.util.args.FileBasedArgument; import org.opends.server.util.args.IntegerArgument; import org.opends.server.util.args.StringArgument; import static org.opends.server.messages.MessageHandler.*; import static org.opends.server.messages.ToolMessages.*; import static org.opends.server.util.DynamicConstants.*; import static org.opends.server.util.StaticUtils.*; /** * This class provides a very simple mechanism for installing the OpenDS * Directory Service. It performs the following tasks: * <UL> * <LI>Ask the user what base DN should be used for the data</LI> * <LI>Ask the user whether to create the base entry, or to import LDIF</LI> * <LI>Ask the user for the LDAP port and make sure it's available</LI> * <LI>Ask the user for the default root DN and password</LI> * <LI>Ask the user if they want to start the server when done installing</LI> * </UL> */ public class InstallDS { /** * The fully-qualified name of this class for debugging purposes. */ private static final String CLASS_NAME = "org.opends.server.tools.InstallDS"; /** * Indicates whether we think we're running on a Windows system. */ private static boolean isWindows = false; /** * The version string for the server. */ private static String versionString = "OpenDS Directory Service"; /** * The name of the program used to launch this installation process. */ private static String programName = "setup"; /** * Invokes the <CODE>installMain</CODE> method with the provided arguments. * * @param args The command-line arguments to use for this program. */ public static void main(String[] args) { int exitCode = installMain(args); if (exitCode != 0) { System.exit(exitCode); } } /** * Prompts the user for the necessary information, installs the OpenDS * software in the appropriate location, and gives it the desired * configuration. * * @param args The command-line arguments to use for this program. * * @return A value of zero if the installation process was successful, or a * nonzero value if a problem occurred. */ public static int installMain(String[] args) { // Determine whether we think we're running on Windows. String osName = System.getProperty("os.name"); if ((osName != null) && (osName.toLowerCase().indexOf("windows") >= 0)) { isWindows = true; } // Construct the product version string and the setup filename. versionString = PRODUCT_NAME + " " + MAJOR_VERSION + "." + MINOR_VERSION; if ((VERSION_QUALIFIER == null) || (VERSION_QUALIFIER.length() == 0)) { versionString += "." + POINT_VERSION; } else { versionString += VERSION_QUALIFIER; } if (isWindows) { programName = "setup.bat"; } else { programName = "setup.sh"; } // Create and initialize the argument parser for this program. ArgumentParser argParser = new ArgumentParser(CLASS_NAME, false); BooleanArgument addBaseEntry; BooleanArgument testOnly; BooleanArgument showUsage; BooleanArgument silentInstall; BooleanArgument skipPortCheck; FileBasedArgument rootPWFile; IntegerArgument ldapPort; StringArgument baseDN; StringArgument configClass; StringArgument configFile; StringArgument importLDIF; StringArgument progName; StringArgument rootDN; StringArgument rootPWString; try { testOnly = new BooleanArgument("test", 't', "testOnly", MSGID_INSTALLDS_DESCRIPTION_TESTONLY); testOnly.setHidden(true); argParser.addArgument(testOnly); progName = new StringArgument("progname", 'P', "programName", false, false, true, "{programName}", programName, null, MSGID_INSTALLDS_DESCRIPTION_PROGNAME); progName.setHidden(true); argParser.addArgument(progName); configFile = new StringArgument("configfile", 'c', "configFile", false, false, true, "{configFile}", null, null, MSGID_INSTALLDS_DESCRIPTION_CONFIG_FILE); argParser.addArgument(configFile); configClass = new StringArgument("configclass", 'C', "configClass", false, false, true, "{configClass}", ConfigFileHandler.class.getName(), null, MSGID_INSTALLDS_DESCRIPTION_CONFIG_CLASS); argParser.addArgument(configClass); silentInstall = new BooleanArgument("silent", 's', "silentInstall", MSGID_INSTALLDS_DESCRIPTION_SILENT); argParser.addArgument(silentInstall); baseDN = new StringArgument("basedn", 'b', "baseDN", false, true, true, "{baseDN}", "dc=example,dc=com", null, MSGID_INSTALLDS_DESCRIPTION_BASEDN); argParser.addArgument(baseDN); addBaseEntry = new BooleanArgument("addbase", 'a', "addBaseEntry", MSGID_INSTALLDS_DESCRIPTION_ADDBASE); argParser.addArgument(addBaseEntry); importLDIF = new StringArgument("importldif", 'i', "importLDIF", false, true, true, "{ldifFile}", null, null, MSGID_INSTALLDS_DESCRIPTION_IMPORTLDIF); argParser.addArgument(importLDIF); ldapPort = new IntegerArgument("ldapport", 'p', "ldapPort", false, false, true, "{port}", 389, null, true, 1, true, 65535, MSGID_INSTALLDS_DESCRIPTION_LDAPPORT); argParser.addArgument(ldapPort); skipPortCheck = new BooleanArgument("skipportcheck", 'S', "skipPortCheck", MSGID_INSTALLDS_DESCRIPTION_SKIPPORT); argParser.addArgument(skipPortCheck); rootDN = new StringArgument("rootdn", 'D', "rootUserDN", false, true, true, "{rootDN}", "cn=Directory Manager", null, MSGID_INSTALLDS_DESCRIPTION_ROOTDN); argParser.addArgument(rootDN); rootPWString = new StringArgument("rootpwstring", 'w', "rootUserPassword", false, false, true, "{password}", null, null, MSGID_INSTALLDS_DESCRIPTION_ROOTPW); argParser.addArgument(rootPWString); rootPWFile = new FileBasedArgument("rootpwfile", 'W', "rootUserPasswordFile", false, false, "{filename}", null, null, MSGID_INSTALLDS_DESCRIPTION_ROOTPWFILE); argParser.addArgument(rootPWFile); showUsage = new BooleanArgument("help", 'H', "help", MSGID_INSTALLDS_DESCRIPTION_HELP); argParser.addArgument(showUsage); argParser.setUsageArgument(showUsage); } catch (ArgumentException ae) { System.err.println(ae.getMessage()); System.err.println(argParser.getUsage()); return 1; } // Parse all of the configuration arguments. try { argParser.parseArguments(args); } catch (ArgumentException ae) { System.err.println(ae.getMessage()); System.err.println(argParser.getUsage()); return 1; } // If either the showUsage or testOnly arguments were provided, then we're // done. if (showUsage.isPresent() || testOnly.isPresent()) { return 0; } // Make sure the path to the configuration file was given. String configFileName; if (configFile.isPresent()) { configFileName = configFile.getValue(); } else { int msgID = MSGID_INSTALLDS_NO_CONFIG_FILE; String message = getMessage(msgID, configFile.getLongIdentifier()); System.err.println(message); return 1; } // Get the configuration handler class name. String configClassName = configClass.getValue(); // If this isn't a silent install, then print the version string. if (! silentInstall.isPresent()) { System.out.println(versionString); } // Perform a base-level initialization that will be required to get // minimal functionality like DN parsing to work. DirectoryServer directoryServer = DirectoryServer.getInstance(); directoryServer.bootstrapClient(); try { directoryServer.initializeJMX(); } catch (Exception e) { int msgID = MSGID_INSTALLDS_CANNOT_INITIALIZE_JMX; String message = getMessage(msgID, String.valueOf(configFile.getValue()), e.getMessage()); System.err.println(message); return 1; } try { directoryServer.initializeConfiguration(configClass.getValue(), configFile.getValue()); } catch (Exception e) { int msgID = MSGID_INSTALLDS_CANNOT_INITIALIZE_CONFIG; String message = getMessage(msgID, String.valueOf(configFile.getValue()), e.getMessage()); System.err.println(message); return 1; } try { directoryServer.initializeSchema(); } catch (Exception e) { int msgID = MSGID_INSTALLDS_CANNOT_INITIALIZE_SCHEMA; String message = getMessage(msgID, String.valueOf(configFile.getValue()), e.getMessage()); System.err.println(message); return 1; } // 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(message); 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(message); 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 (importLDIF.isPresent()) { int msgID = MSGID_INSTALLDS_TWO_CONFLICTING_ARGUMENTS; String message = getMessage(msgID, addBaseEntry.getLongIdentifier(), importLDIF.getLongIdentifier()); System.err.println(message); return 1; } } else if (silentInstall.isPresent() || importLDIF.isPresent()) { 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()) { try { ldapPortNumber = ldapPort.getIntValue(); } catch (ArgumentException ae) { System.err.println(ae.getMessage()); return 1; } } else { while (true) { int msgID = MSGID_INSTALLDS_PROMPT_LDAPPORT; String message = getMessage(msgID); ldapPortNumber = promptForInteger(message, 389, 1, 65535); if (! skipPortCheck.isPresent()) { try { InetSocketAddress socketAddress = new InetSocketAddress(ldapPortNumber); ServerSocket serverSocket = new ServerSocket(); serverSocket.setReuseAddress(true); serverSocket.bind(socketAddress); serverSocket.close(); break; } catch (Exception e) { if (ldapPortNumber <= 1024) { msgID = MSGID_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT; message = getMessage(msgID, ldapPortNumber, e.getMessage()); System.err.println(message); return 1; } else { msgID = MSGID_INSTALLDS_CANNOT_BIND_TO_PORT; message = getMessage(msgID, ldapPortNumber, e.getMessage()); System.err.println(message); return 1; } } } } } // Determine the initial root user DN. LinkedList<DN> rootDNs; if (rootDN.isPresent()) { rootDNs = new LinkedList<DN>(); for (String s : rootDN.getValues()) { try { rootDNs.add(DN.decode(s)); } catch (Exception e) { int msgID = MSGID_INSTALLDS_CANNOT_PARSE_DN; String message = getMessage(msgID, s, e.getMessage()); System.err.println(message); return 1; } } } else if (silentInstall.isPresent()) { rootDNs = new LinkedList<DN>(); try { rootDNs.add(DN.decode(rootDN.getDefaultValue())); } catch (Exception e) { int msgID = MSGID_INSTALLDS_CANNOT_PARSE_DN; String message = getMessage(msgID, rootDN.getDefaultValue(), e.getMessage()); System.err.println(message); return 1; } } else { int msgID = MSGID_INSTALLDS_PROMPT_ROOT_DN; String message = getMessage(msgID); rootDNs = new LinkedList<DN>(); rootDNs.add(promptForDN(message, rootDN.getDefaultValue())); } // Determine the initial root user password. String rootPassword; if (rootPWString.isPresent()) { rootPassword = rootPWString.getValue(); if (rootPWFile.isPresent()) { int msgID = MSGID_INSTALLDS_TWO_CONFLICTING_ARGUMENTS; String message = getMessage(msgID, rootPWString.getLongIdentifier(), rootPWFile.getLongIdentifier()); System.err.println(message); return 1; } } else if (rootPWFile.isPresent()) { rootPassword = rootPWFile.getValue(); } else if (silentInstall.isPresent()) { int msgID = MSGID_INSTALLDS_NO_ROOT_PASSWORD; String message = getMessage(msgID, rootPWString.getLongIdentifier(), rootPWFile.getLongIdentifier()); System.err.println(message); return 1; } else { int msgID = MSGID_INSTALLDS_PROMPT_ROOT_PASSWORD; String initialPrompt = getMessage(msgID); msgID = MSGID_INSTALLDS_PROMPT_CONFIRM_ROOT_PASSWORD; String confirmPrompt = getMessage(msgID); rootPassword = new String(promptForPassword(initialPrompt, confirmPrompt)); } // At this point, we should be able to invoke the ConfigureDS utility to // apply the requested configuration. ArrayList<String> argList = new ArrayList<String>(); argList.add("-C"); argList.add(configClassName); argList.add("-c"); argList.add(configFileName); argList.add("-p"); argList.add(String.valueOf(ldapPortNumber)); for (DN dn : baseDNs) { argList.add("-b"); argList.add(dn.toString()); } for (DN dn : rootDNs) { argList.add("-D"); argList.add(dn.toString()); } argList.add("-w"); argList.add(rootPassword); String[] configureDSArguments = new String[argList.size()]; argList.toArray(configureDSArguments); if (! silentInstall.isPresent()) { System.out.println(); System.out.println(getMessage(MSGID_INSTALLDS_STATUS_CONFIGURING_DS)); } int returnValue = ConfigureDS.configMain(configureDSArguments); if (returnValue != 0) { return returnValue; } // If we should import data or add the base entry, then do so now. if (addBase) { // Create a temporary LDIF file that will hold the entry to add. if (! silentInstall.isPresent()) { System.out.println(); System.out.println(getMessage( MSGID_INSTALLDS_STATUS_CREATING_BASE_LDIF)); } try { File ldifFile = File.createTempFile("opends-base-entry", ".ldif"); String ldifFilePath = ldifFile.getAbsolutePath(); ldifFile.deleteOnExit(); LDIFExportConfig exportConfig = new LDIFExportConfig(ldifFilePath, ExistingFileBehavior.OVERWRITE); LDIFWriter writer = new LDIFWriter(exportConfig); for (DN dn : baseDNs) { writer.writeEntry(createEntry(dn)); } writer.close(); if (ldifFiles == null) { ldifFiles = new LinkedList<String>(); ldifFiles.add(ldifFilePath); } } catch (Exception e) { int msgID = MSGID_INSTALLDS_CANNOT_CREATE_BASE_ENTRY_LDIF; System.err.println(getMessage(msgID, String.valueOf(e))); return 1; } } if ((ldifFiles != null) && (! ldifFiles.isEmpty())) { if (! silentInstall.isPresent()) { System.out.println(); System.out.println(getMessage(MSGID_INSTALLDS_STATUS_IMPORTING_LDIF)); } // Use the ImportLDIF tool to perform the import. argList = new ArrayList<String>(); argList.add("-C"); argList.add(configClassName); argList.add("-f"); argList.add(configFileName); argList.add("-n"); argList.add("userRoot"); for (String s : ldifFiles) { argList.add("-l"); argList.add(s); } String[] importLDIFArguments = new String[argList.size()]; argList.toArray(importLDIFArguments); returnValue = ImportLDIF.mainImportLDIF(importLDIFArguments); if (returnValue != 0) { return returnValue; } } // If we've gotten here, then everything seems to have gone smoothly. if (! silentInstall.isPresent()) { System.out.println(); System.out.println(getMessage(MSGID_INSTALLDS_STATUS_SUCCESS)); } return 0; } /** * Interactively prompts (on standard output) the user to provide a Boolean * value. The answer provided must be one of "true", "t", "yes", "y", * "false", "f", "no", or "n", ignoring capitalization. It will keep * prompting until an acceptable value is given. * * @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</CODE> if * there should not be a default and the user must * explicitly provide a value. * * @return The <CODE>boolean</CODE> value read from the user input. */ private static boolean promptForBoolean(String prompt, Boolean defaultValue) { String wrappedPrompt = wrapText(prompt, 79); while (true) { System.out.println(); System.out.println(wrappedPrompt); if (defaultValue == null) { System.out.print(": "); } else { System.out.print("["); if (defaultValue) { System.out.print(getMessage(MSGID_INSTALLDS_PROMPT_VALUE_YES)); } else { System.out.print(getMessage(MSGID_INSTALLDS_PROMPT_VALUE_NO)); } System.out.print("]: "); } System.out.flush(); String response = toLowerCase(readLine()); if (response.equals("true") || response.equals("yes") || response.equals("t") || response.equals("y")) { return true; } else if (response.equals("false") || response.equals("no") || response.equals("f") || response.equals("n")) { return false; } else if (response.equals("")) { if (defaultValue == null) { System.err.println(getMessage( MSGID_INSTALLDS_INVALID_YESNO_RESPONSE)); } else { return defaultValue; } } else { System.err.println(getMessage(MSGID_INSTALLDS_INVALID_YESNO_RESPONSE)); } } } /** * Interactively prompts (on standard output) the user to provide an integer * value. The answer provided must be parseable as an integer, and may be * required to be within a given set of bounds. It will keep prompting until * an acceptable value is given. * * @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</CODE> if * there should not be a default and the user must * explicitly provide a value. * @param lowerBound The lower bound that should be enforced, or * <CODE>null</CODE> if there is none. * @param upperBound The upper bound that should be enforced, or * <CODE>null</CODE> if there is none. * * @return The <CODE>int</CODE> value read from the user input. */ private static int promptForInteger(String prompt, Integer defaultValue, Integer lowerBound, Integer upperBound) { String wrappedPrompt = wrapText(prompt, 79); while (true) { System.out.println(); System.out.println(wrappedPrompt); if (defaultValue == null) { System.out.print(": "); } else { System.out.print("["); System.out.print(defaultValue); System.out.print("]: "); } System.out.flush(); String response = readLine(); if (response.equals("")) { if (defaultValue == null) { int msgID = MSGID_INSTALLDS_INVALID_INTEGER_RESPONSE; System.err.println(getMessage(msgID)); } else { return defaultValue; } } else { try { int intValue = Integer.parseInt(response); if ((lowerBound != null) && (intValue < lowerBound)) { int msgID = MSGID_INSTALLDS_INTEGER_BELOW_LOWER_BOUND; System.err.println(getMessage(msgID, lowerBound)); } else if ((upperBound != null) && (intValue > upperBound)) { int msgID = MSGID_INSTALLDS_INTEGER_ABOVE_UPPER_BOUND; System.err.println(getMessage(msgID, upperBound)); } else { return intValue; } } catch (NumberFormatException nfe) { int msgID = MSGID_INSTALLDS_INVALID_INTEGER_RESPONSE; System.err.println(getMessage(msgID)); } } } } /** * Interactively prompts (on standard output) the user to provide a DN value. * Any non-empty string will be allowed if it can be parsed as a valid DN (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</CODE> if * there should not be a default and the user must * explicitly provide a value. * * @return The DN value read from the user. */ private static DN promptForDN(String prompt, String defaultValue) { String wrappedPrompt = wrapText(prompt, 79); while (true) { System.out.println(); System.out.println(wrappedPrompt); if (defaultValue == null) { System.out.print(": "); } else { System.out.print("["); System.out.print(defaultValue); System.out.print("]: "); } System.out.flush(); String response = readLine(); if (response.equals("")) { if (defaultValue == null) { int msgID = MSGID_INSTALLDS_INVALID_DN_RESPONSE; System.err.println(getMessage(msgID)); } else { try { return DN.decode(defaultValue); } catch (Exception e) { int msgID = MSGID_INSTALLDS_INVALID_DN_RESPONSE; System.err.println(getMessage(msgID)); } } } else { try { return DN.decode(response); } catch (Exception e) { int msgID = MSGID_INSTALLDS_INVALID_DN_RESPONSE; System.err.println(getMessage(msgID)); } } } } /** * Interactively prompts (on standard 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</CODE> if * there should not be a default and the user must * explicitly provide a value. * * @return The string value read from the user. */ private static String promptForString(String prompt, String defaultValue) { System.out.println(); String wrappedPrompt = wrapText(prompt, 79); while (true) { System.out.println(wrappedPrompt); if (defaultValue == null) { System.out.print(": "); } else { System.out.print("["); System.out.print(defaultValue); System.out.print("]: "); } System.out.flush(); String response = readLine(); if (response.equals("")) { if (defaultValue == null) { int msgID = MSGID_INSTALLDS_INVALID_STRING_RESPONSE; System.err.println(getMessage(msgID)); } else { return defaultValue; } } else { return response; } } } /** * Interactively prompts (on standard output) the user to provide a string * value. The response that the user provides will not be echoed, and it must * be entered twice for confirmation. No default value will be allowed, and * the string entered must contain at least one character. * * @param initialPrompt The initial prompt to present to the user. * @param reEntryPrompt The prompt to present to the user when requesting * that the value be re-entered for confirmation. * * @return The string value read from the user. */ private static char[] promptForPassword(String initialPrompt, String reEntryPrompt) { String wrappedInitialPrompt = wrapText(initialPrompt, 79); String wrappedReEntryPrompt = wrapText(reEntryPrompt, 79); while (true) { System.out.println(); System.out.print(wrappedInitialPrompt); System.out.print(": "); System.out.flush(); char[] password = PasswordReader.readPassword(); if ((password == null) || (password.length == 0)) { int msgID = MSGID_INSTALLDS_INVALID_PASSWORD_RESPONSE; System.err.println(getMessage(msgID)); } else { System.out.print(wrappedReEntryPrompt); System.out.print(": "); System.out.flush(); char[] confirmedPassword = PasswordReader.readPassword(); if ((confirmedPassword == null) || (! Arrays.equals(password, confirmedPassword))) { int msgID = MSGID_INSTALLDS_PASSWORDS_DONT_MATCH; System.err.println(getMessage(msgID)); } else { return password; } } } } /** * Reads a line of text from standard input. * * @return The line of text read from standard input, or <CODE>null</CODE> * if the end of the stream is reached or an error occurs while * attempting to read the response. */ private static String readLine() { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); while (true) { int b = System.in.read(); if ((b < 0) || (b == '\n')) { break; } else if (b == '\r') { int b2 = System.in.read(); if (b2 == '\n') { break; } else { baos.write(b); baos.write(b2); } } else { baos.write(b); } } return new String(baos.toByteArray(), "UTF-8"); } catch (Exception e) { int msgID = MSGID_INSTALLDS_ERROR_READING_FROM_STDIN; System.err.println(getMessage(msgID, String.valueOf(e))); return null; } } } opends/src/server/org/opends/server/util/PasswordReader.java
@@ -207,7 +207,7 @@ while (true) { int charRead = System.in.read(); if ((charRead == -1) || (charRead == '\r') || (charRead == '\n')) if ((charRead == -1) || (charRead == '\n')) { // This is the end of the value. if (pos == 0) @@ -222,6 +222,46 @@ return pwChars; } } else if (charRead == '\r') { int char2 = System.in.read(); if (char2 == '\n') { // This is the end of the value. if (pos == 0) { return null; } else { pwChars = new char[pos]; System.arraycopy(pwBuffer, 0, pwChars, 0, pos); Arrays.fill(pwBuffer, '\u0000'); return pwChars; } } else { // Append the characters to the buffer and continue. pwBuffer[pos++] = (char) charRead; if (pos >= pwBuffer.length) { char[] newBuffer = new char[pwBuffer.length+100]; System.arraycopy(pwBuffer, 0, newBuffer, 0, pwBuffer.length); Arrays.fill(pwBuffer, '\u0000'); pwBuffer = newBuffer; } pwBuffer[pos++] = (char) char2; if (pos >= pwBuffer.length) { char[] newBuffer = new char[pwBuffer.length+100]; System.arraycopy(pwBuffer, 0, newBuffer, 0, pwBuffer.length); Arrays.fill(pwBuffer, '\u0000'); pwBuffer = newBuffer; } } } else { // Append the value to the buffer and continue. opends/src/server/org/opends/server/util/StaticUtils.java
@@ -42,6 +42,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import org.opends.server.core.DirectoryServer; import org.opends.server.types.Attribute; @@ -3387,5 +3388,125 @@ return getMessage(MSGID_TIME_IN_DAYS_HOURS_MINUTES_SECONDS, d, h, m, s); } } /** * Inserts line breaks into the provided buffer to wrap text at no more than * the specified column width. Wrapping will only be done at space boundaries * and if there are no spaces within the specified width, then wrapping will * be performed at the first space after the specified column. * * @param text The text to be wrapped. * @param width The maximum number of characters to allow on a line if there * is a suitable breaking point. * * @return The wrapped text. */ public static String wrapText(String text, int width) { StringBuilder buffer = new StringBuilder(); StringTokenizer lineTokenizer = new StringTokenizer(text, "\r\n", true); while (lineTokenizer.hasMoreTokens()) { String line = lineTokenizer.nextToken(); if (line.equals("\r") || line.equals("\n")) { // It's an end-of-line character, so append it as-is. buffer.append(line); } else if (line.length() < width) { // The line fits in the specified width, so append it as-is. buffer.append(line); } else { // The line doesn't fit in the specified width, so it needs to be // wrapped. Do so at space boundaries. StringBuilder lineBuffer = new StringBuilder(); StringBuilder delimBuffer = new StringBuilder(); StringTokenizer wordTokenizer = new StringTokenizer(line, " ", true); while (wordTokenizer.hasMoreTokens()) { String word = wordTokenizer.nextToken(); if (word.equals(" ")) { // It's a space, so add it to the delim buffer only if the line // buffer is not empty. if (lineBuffer.length() > 0) { delimBuffer.append(word); } } else if (word.length() > width) { // This is a long word that can't be wrapped, so we'll just have to // make do. if (lineBuffer.length() > 0) { buffer.append(lineBuffer); buffer.append(EOL); lineBuffer = new StringBuilder(); } buffer.append(word); if (wordTokenizer.hasMoreTokens()) { // The next token must be a space, so remove it. If there are // still more tokens after that, then append an EOL. wordTokenizer.nextToken(); if (wordTokenizer.hasMoreTokens()) { buffer.append(EOL); } } if (delimBuffer.length() > 0) { delimBuffer = new StringBuilder(); } } else { // It's not a space, so see if we can fit it on the curent line. int newLineLength = lineBuffer.length() + delimBuffer.length() + word.length(); if (newLineLength < width) { // It does fit on the line, so add it. lineBuffer.append(delimBuffer).append(word); if (delimBuffer.length() > 0) { delimBuffer = new StringBuilder(); } } else { // It doesn't fit on the line, so end the current line and start // a new one. buffer.append(lineBuffer); buffer.append(EOL); lineBuffer = new StringBuilder(); lineBuffer.append(word); if (delimBuffer.length() > 0) { delimBuffer = new StringBuilder(); } } } } // If there's anything left in the line buffer, then add it to the // final buffer. buffer.append(lineBuffer); } } return buffer.toString(); } }