![JAR search and dependency download from the Maven repository](/logo.png)
com.unboundid.util.CommandLineToolInteractiveModeProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of unboundid-ldapsdk-commercial-edition Show documentation
Show all versions of unboundid-ldapsdk-commercial-edition Show documentation
The UnboundID LDAP SDK for Java is a fast, comprehensive, and easy-to-use
Java API for communicating with LDAP directory servers and performing
related tasks like reading and writing LDIF, encoding and decoding data
using base64 and ASN.1 BER, and performing secure communication. This
package contains the Commercial Edition of the LDAP SDK, which includes
all of the general-purpose functionality contained in the Standard
Edition, plus additional functionality specific to UnboundID server
products.
The newest version!
/*
* Copyright 2015-2017 UnboundID Corp.
* All Rights Reserved.
*/
/*
* Copyright (C) 2015-2017 UnboundID Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
package com.unboundid.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeMap;
import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
import com.unboundid.ldap.sdk.BindRequest;
import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.CRAMMD5BindRequest;
import com.unboundid.ldap.sdk.DIGESTMD5BindRequest;
import com.unboundid.ldap.sdk.DN;
import com.unboundid.ldap.sdk.EXTERNALBindRequest;
import com.unboundid.ldap.sdk.ExtendedResult;
import com.unboundid.ldap.sdk.Filter;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.PLAINBindRequest;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.SearchScope;
import com.unboundid.ldap.sdk.SimpleBindRequest;
import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest;
import com.unboundid.util.args.Argument;
import com.unboundid.util.args.ArgumentException;
import com.unboundid.util.args.ArgumentHelper;
import com.unboundid.util.args.ArgumentListArgument;
import com.unboundid.util.args.ArgumentParser;
import com.unboundid.util.args.BooleanArgument;
import com.unboundid.util.args.BooleanValueArgument;
import com.unboundid.util.args.ControlArgument;
import com.unboundid.util.args.DNArgument;
import com.unboundid.util.args.DurationArgument;
import com.unboundid.util.args.FileArgument;
import com.unboundid.util.args.FilterArgument;
import com.unboundid.util.args.IntegerArgument;
import com.unboundid.util.args.ScopeArgument;
import com.unboundid.util.args.StringArgument;
import com.unboundid.util.args.SubCommand;
import com.unboundid.util.args.TimestampArgument;
import com.unboundid.util.ssl.KeyStoreKeyManager;
import com.unboundid.util.ssl.PromptTrustManager;
import com.unboundid.util.ssl.SSLUtil;
import com.unboundid.util.ssl.TrustAllTrustManager;
import com.unboundid.util.ssl.TrustStoreTrustManager;
import static com.unboundid.util.UtilityMessages.*;
/**
* This class performs the appropriate processing to obtain values to use for
* command-line arguments when a tool is invoked in interactive mode.
*/
@InternalUseOnly()
@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
final class CommandLineToolInteractiveModeProcessor
{
/**
* Indicates whether this processor is being run in a unit test environment.
* If so, then we will read passwords in a way that is compatible with the
* unit test framework.
*/
private static volatile boolean IN_UNIT_TEST = false;
// The argument parser for the command-line tool.
private final ArgumentParser parser;
// The reader that may be used to read from standard input.
private final BufferedReader systemInReader;
// The associated command-line tool.
private final CommandLineTool tool;
// The maximum column length to use when wrapping long lines.
private final int wrapColumn;
/**
* Creates a new instance of this command-line tool interactive mode
* processor with the provided information.
*
* @param tool The command-line tool for which to perform interactive mode
* processing.
* @param parser The argument parser for the provided command-line tool.
*/
CommandLineToolInteractiveModeProcessor(final CommandLineTool tool,
final ArgumentParser parser)
{
this.tool = tool;
this.parser = parser;
systemInReader = new BufferedReader(new InputStreamReader(System.in));
wrapColumn = StaticUtils.TERMINAL_WIDTH_COLUMNS - 1;
ArgumentHelper.reset(parser.getNamedArgument("interactive"));
}
/**
* Performs the appropriate interactive mode processing for the tool.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
void doInteractiveModeProcessing()
throws LDAPException
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_LAUNCHING.get(tool.getToolName()));
final List allArgs = new ArrayList(10);
final List subCommands = parser.getSubCommands();
if (! subCommands.isEmpty())
{
final SubCommand subcommand = promptForSubCommand();
ArgumentHelper.setSelectedSubCommand(parser, subcommand);
allArgs.add(subcommand.getPrimaryName());
}
final List ldapArgs = new ArrayList(10);
if (tool instanceof LDAPCommandLineTool)
{
promptForLDAPArguments(ldapArgs, true);
}
else if (tool instanceof MultiServerLDAPCommandLineTool)
{
promptForMultiServerLDAPArguments(ldapArgs, true);
}
allArgs.addAll(ldapArgs);
final List toolArgs = displayInteractiveMenu(ldapArgs);
allArgs.addAll(toolArgs);
tool.out();
if (allArgs.isEmpty())
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_RUNNING_WITH_NO_ARGS.get(tool.getToolName()));
}
else
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_RUNNING_WITH_ARGS.get(tool.getToolName()));
printArgs(allArgs);
}
tool.out();
}
/**
* Prints the provided arguments in a user-friendly way to standard output.
*
* @param args The arguments to be printed.
*/
private void printArgs(final List args)
{
for (int i=0; i < args.size(); i++)
{
final StringBuilder buffer = new StringBuilder();
buffer.append(" ");
final String arg = args.get(i);
buffer.append(ExampleCommandLineArgument.getCleanArgument(
arg).getLocalForm());
if (arg.startsWith("-") && ((i+1) < args.size()))
{
final String nextArg = args.get(i+1);
if (! nextArg.startsWith("-"))
{
buffer.append(' ');
buffer.append(ExampleCommandLineArgument.getCleanArgument(
nextArg).getLocalForm());
i++;
}
}
tool.out(buffer);
}
}
/**
* Interactively prompts for the subcommand that should be used when running
* the tool.
*
* @return The selected subcommand.
*
* @throws LDAPException If a problem is encountered while determining which
* subcommand to use.
*/
private SubCommand promptForSubCommand()
throws LDAPException
{
// Get all of the subcommands sorted by name.
final List subCommands = parser.getSubCommands();
final TreeMap subCommandsByName =
new TreeMap();
for (final SubCommand sc : subCommands)
{
subCommandsByName.put(sc.getPrimaryName(), sc);
}
// Create an array of the subcommand names we want to use.
int index = 0;
final String[] subCommandNames = new String[subCommandsByName.size()];
for (final SubCommand sc : subCommandsByName.values())
{
subCommandNames[index++] = sc.getPrimaryName();
}
// Prompt the user to determine which subcommand to use, and associate that
// with the target subcommand.
final int selectedSubCommandNumber = getNumberedMenuChoice(
INFO_INTERACTIVE_SUBCOMMAND_PROMPT.get(), false, null,
subCommandNames);
return parser.getSubCommand(subCommandNames[selectedSubCommandNumber]);
}
/**
* Interactively prompts for the arguments used to connect and optionally
* authenticate to the directory server.
*
* @param argList The list to which the string representations of all LDAP
* arguments should be added.
* @param test Indicates whether to attempt to use the arguments to
* establish an LDAP connection.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForLDAPArguments(final List argList,
final boolean test)
throws LDAPException
{
final LDAPCommandLineTool ldapTool = (LDAPCommandLineTool) tool;
argList.clear();
// Determine the type of connection security.
final BooleanArgument useSSLArgument = parser.getBooleanArgument("useSSL");
final BooleanArgument useStartTLSArgument =
parser.getBooleanArgument("useStartTLS");
final String defaultSecurityChoice;
if (useSSLArgument.isPresent())
{
defaultSecurityChoice = "2";
}
else if (useStartTLSArgument.isPresent())
{
defaultSecurityChoice = "3";
}
else
{
defaultSecurityChoice = "1";
}
ArgumentHelper.reset(useSSLArgument);
ArgumentHelper.reset(useStartTLSArgument);
final boolean useSSL;
final boolean useStartTLS;
final int securityType = getNumberedMenuChoice(
INFO_INTERACTIVE_LDAP_SECURITY_PROMPT.get(),
false,
defaultSecurityChoice,
INFO_INTERACTIVE_LDAP_SECURITY_OPTION_NONE.get(),
INFO_INTERACTIVE_LDAP_SECURITY_OPTION_SSL.get(),
INFO_INTERACTIVE_LDAP_SECURITY_OPTION_START_TLS.get());
switch (securityType)
{
case 1:
useSSL = true;
useStartTLS = false;
argList.add("--useSSL");
ArgumentHelper.incrementOccurrencesSuppressException(useSSLArgument);
break;
case 2:
useSSL = false;
useStartTLS = true;
argList.add("--useStartTLS");
ArgumentHelper.incrementOccurrencesSuppressException(
useStartTLSArgument);
break;
case 0:
default:
useSSL = false;
useStartTLS = false;
break;
}
// If the user wants to connect securely, then get the appropriate set of
// arguments pertaining to key and trust managers.
final StringArgument keyStorePasswordArgument =
parser.getStringArgument("keyStorePassword");
final StringArgument trustStorePasswordArgument =
parser.getStringArgument("trustStorePassword");
final StringArgument saslOptionArgument =
parser.getStringArgument("saslOption");
ArgumentHelper.reset(keyStorePasswordArgument);
ArgumentHelper.reset(trustStorePasswordArgument);
ArgumentHelper.reset(parser.getNamedArgument("keyStorePasswordFile"));
ArgumentHelper.reset(parser.getNamedArgument(
"promptForKeyStorePassword"));
ArgumentHelper.reset(parser.getNamedArgument("trustStorePasswordFile"));
ArgumentHelper.reset(parser.getNamedArgument(
"promptForTrustStorePassword"));
BindRequest bindRequest = null;
boolean trustAll = false;
byte[] keyStorePIN = null;
byte[] trustStorePIN = null;
File keyStorePath = null;
File trustStorePath = null;
String certificateNickname = null;
String keyStoreFormat = null;
String trustStoreFormat = null;
if (useSSL || useStartTLS)
{
final StringArgument keyStorePathArgument =
parser.getStringArgument("keyStorePath");
final StringArgument keyStoreFormatArgument =
parser.getStringArgument("keyStoreFormat");
// Determine if a client certificate should be presented.
final String defaultStoreTypeChoice;
if (keyStoreFormatArgument.isPresent())
{
final String format = keyStoreFormatArgument.getValue();
if (format.equalsIgnoreCase("PKCS12"))
{
defaultStoreTypeChoice = "3";
}
else
{
defaultStoreTypeChoice = "2";
}
}
else if (keyStorePathArgument.isPresent())
{
defaultStoreTypeChoice = "2";
}
else
{
defaultStoreTypeChoice = "1";
}
final String defaultKeyStorePath;
if (keyStorePathArgument.isPresent())
{
defaultKeyStorePath = keyStorePathArgument.getValue();
}
else
{
defaultKeyStorePath = null;
}
final String defaultCertNickname;
final StringArgument certNicknameArgument =
parser.getStringArgument("certNickname");
if (certNicknameArgument.isPresent())
{
defaultCertNickname = certNicknameArgument.getValue();
}
else
{
defaultCertNickname = null;
}
ArgumentHelper.reset(keyStorePathArgument);
ArgumentHelper.reset(keyStoreFormatArgument);
ArgumentHelper.reset(certNicknameArgument);
final int keystoreType = getNumberedMenuChoice(
INFO_INTERACTIVE_LDAP_CLIENT_CERT_PROMPT.get(),
false,
defaultStoreTypeChoice,
INFO_INTERACTIVE_LDAP_CLIENT_CERT_OPTION_NO.get(),
INFO_INTERACTIVE_LDAP_CLIENT_CERT_OPTION_JKS.get(),
INFO_INTERACTIVE_LDAP_CLIENT_CERT_OPTION_PKCS12.get());
ArgumentHelper.reset(keyStoreFormatArgument);
switch (keystoreType)
{
case 1:
keyStoreFormat = "JKS";
break;
case 2:
keyStoreFormat = "PKCS12";
break;
case 0:
default:
break;
}
if (keyStoreFormat != null)
{
ArgumentHelper.addValueSuppressException(keyStoreFormatArgument,
keyStoreFormat);
// Get the path to the keystore file.
keyStorePath = promptForPath(
INFO_INTERACTIVE_LDAP_KEYSTORE_PATH_PROMPT.get(),
defaultKeyStorePath, true, true, true, true, false);
argList.add("--keyStorePath");
argList.add(keyStorePath.getAbsolutePath());
ArgumentHelper.addValueSuppressException(keyStorePathArgument,
keyStorePath.getAbsolutePath());
// Get the PIN needed to access the keystore.
keyStorePIN = promptForPassword(
INFO_INTERACTIVE_LDAP_KEYSTORE_PIN_PROMPT.get(), false);
if (keyStorePIN != null)
{
argList.add("--keyStorePassword");
argList.add("***REDACTED***");
ArgumentHelper.addValueSuppressException(keyStorePasswordArgument,
StaticUtils.toUTF8String(keyStorePIN));
}
argList.add("--keyStoreFormat");
argList.add(keyStoreFormat);
certificateNickname = promptForString(
INFO_INTERACTIVE_LDAP_CERT_NICKNAME_PROMPT.get(),
defaultCertNickname, false);
if (certificateNickname != null)
{
argList.add("--certNickname");
argList.add(certificateNickname);
ArgumentHelper.addValueSuppressException(certNicknameArgument,
certificateNickname);
}
if (ldapTool.supportsAuthentication() && promptForBoolean(
INFO_INTERACTIVE_LDAP_CERT_AUTH_PROMPT.get(), false, true))
{
bindRequest = new EXTERNALBindRequest();
argList.add("--saslOption");
argList.add("mech=EXTERNAL");
ArgumentHelper.reset(saslOptionArgument);
ArgumentHelper.addValueSuppressException(saslOptionArgument,
"mech=EXTERNAL");
}
}
// Determine how to trust the server certificate.
final BooleanArgument trustAllArgument =
parser.getBooleanArgument("trustAll");
final StringArgument trustStorePathArgument =
parser.getStringArgument("trustStorePath");
final StringArgument trustStoreFormatArgument =
parser.getStringArgument("trustStoreFormat");
final String defaultTrustTypeChoice;
if (trustAllArgument.isPresent())
{
defaultTrustTypeChoice = "4";
}
else if (trustStoreFormatArgument.isPresent())
{
final String format = trustStoreFormatArgument.getValue();
if (format.equalsIgnoreCase("PKCS12"))
{
defaultTrustTypeChoice = "3";
}
else
{
defaultTrustTypeChoice = "2";
}
}
else if (trustStorePathArgument.isPresent())
{
defaultTrustTypeChoice = "2";
}
else
{
defaultTrustTypeChoice = "1";
}
final String defaultTrustStorePath;
if (trustStorePathArgument.isPresent())
{
defaultTrustStorePath = trustStorePathArgument.getValue();
}
else
{
defaultTrustStorePath = null;
}
ArgumentHelper.reset(trustAllArgument);
ArgumentHelper.reset(trustStorePathArgument);
ArgumentHelper.reset(trustStoreFormatArgument);
final int trustType = getNumberedMenuChoice(
INFO_INTERACTIVE_LDAP_TRUST_PROMPT.get(),
false,
defaultTrustTypeChoice,
INFO_INTERACTIVE_LDAP_TRUST_OPTION_PROMPT.get(),
INFO_INTERACTIVE_LDAP_TRUST_OPTION_JKS.get(),
INFO_INTERACTIVE_LDAP_TRUST_OPTION_PKCS12.get(),
INFO_INTERACTIVE_LDAP_TRUST_OPTION_BLIND.get());
switch (trustType)
{
case 1:
trustStoreFormat = "JKS";
break;
case 2:
trustStoreFormat = "PKCS12";
break;
case 3:
trustAll = true;
argList.add("--trustAll");
ArgumentHelper.incrementOccurrencesSuppressException(
trustAllArgument);
break;
case 0:
default:
// We will interactively prompt the user about whether to trust the
// certificate in the test section below. However, to avoid prompting
// the user twice, we will configure the tool behind the scenes to
// trust all certificates.
ArgumentHelper.incrementOccurrencesSuppressException(
trustAllArgument);
break;
}
if (trustStoreFormat != null)
{
ArgumentHelper.addValueSuppressException(trustStoreFormatArgument,
trustStoreFormat);
// Get the path to the truststore file.
trustStorePath = promptForPath(
INFO_INTERACTIVE_LDAP_TRUSTSTORE_PATH_PROMPT.get(),
defaultTrustStorePath, true, true, true, true, false);
argList.add("--trustStorePath");
argList.add(trustStorePath.getAbsolutePath());
ArgumentHelper.addValueSuppressException(trustStorePathArgument,
trustStorePath.getAbsolutePath());
// Get the PIN needed to access the truststore.
trustStorePIN = promptForPassword(
INFO_INTERACTIVE_LDAP_TRUSTSTORE_PIN_PROMPT.get(), false);
if (trustStorePIN != null)
{
argList.add("--trustStorePassword");
argList.add("***REDACTED***");
ArgumentHelper.addValueSuppressException(trustStorePasswordArgument,
StaticUtils.toUTF8String(trustStorePIN));
}
argList.add("--trustStoreFormat");
argList.add(trustStoreFormat);
}
}
else
{
ArgumentHelper.reset(parser.getNamedArgument("keyStorePath"));
ArgumentHelper.reset(parser.getNamedArgument("keyStoreFormat"));
ArgumentHelper.reset(parser.getNamedArgument("trustStorePath"));
ArgumentHelper.reset(parser.getNamedArgument("trustStoreFormat"));
ArgumentHelper.reset(parser.getNamedArgument("certNickname"));
}
// Get the address and port of the directory server.
final String defaultHostname;
final StringArgument hostnameArgument =
parser.getStringArgument("hostname");
if (hostnameArgument.isPresent())
{
defaultHostname = hostnameArgument.getValue();
}
else
{
defaultHostname = "localhost";
}
final int defaultPort;
final IntegerArgument portArgument =
parser.getIntegerArgument("port");
if (portArgument.getNumOccurrences() > 0)
{
// Note -- We're using getNumOccurrences here because isPresent also
// returns true if there is a default value, and that could be wrong in
// this case because the default value doesn't know about SSL.
defaultPort = portArgument.getValue();
}
else if (useSSL)
{
defaultPort = 636;
}
else
{
defaultPort = 389;
}
ArgumentHelper.reset(hostnameArgument);
ArgumentHelper.reset(portArgument);
final String hostname = promptForString(
INFO_INTERACTIVE_LDAP_PROMPT_HOST.get(), defaultHostname, true);
ArgumentHelper.addValueSuppressException(hostnameArgument, hostname);
final int port = promptForInteger(INFO_INTERACTIVE_LDAP_PROMPT_PORT.get(),
defaultPort, 1, 65535, true);
argList.add("--hostname");
argList.add(hostname);
argList.add("--port");
argList.add(String.valueOf(port));
ArgumentHelper.addValueSuppressException(portArgument,
String.valueOf(port));
// Determine how to authenticate to the directory server.
if (ldapTool.supportsAuthentication())
{
final DNArgument bindDNArgument =
parser.getDNArgument("bindDN");
final StringArgument bindPasswordArgument =
parser.getStringArgument("bindPassword");
ArgumentHelper.reset(bindPasswordArgument);
ArgumentHelper.reset(parser.getNamedArgument("bindPasswordFile"));
ArgumentHelper.reset(parser.getNamedArgument("promptForBindPassword"));
if (bindRequest == null)
{
final String defaultAuthTypeChoice;
final String defaultBindDN;
if (bindDNArgument.isPresent())
{
defaultAuthTypeChoice = "2";
defaultBindDN = bindDNArgument.getValue().toString();
}
else if (saslOptionArgument.isPresent())
{
defaultAuthTypeChoice = "3";
defaultBindDN = null;
}
else
{
defaultAuthTypeChoice = "1";
defaultBindDN = null;
}
ArgumentHelper.reset(bindDNArgument);
boolean useSimpleAuth = false;
boolean useSASLAuth = false;
final int authMethod = getNumberedMenuChoice(
INFO_INTERACTIVE_LDAP_AUTH_PROMPT.get(),
false,
defaultAuthTypeChoice,
INFO_INTERACTIVE_LDAP_AUTH_OPTION_NONE.get(),
INFO_INTERACTIVE_LDAP_AUTH_OPTION_SIMPLE.get(),
INFO_INTERACTIVE_LDAP_AUTH_OPTION_SASL.get());
switch (authMethod)
{
case 1:
useSimpleAuth = true;
break;
case 2:
useSASLAuth = true;
break;
case 0:
default:
break;
}
if (useSimpleAuth)
{
ArgumentHelper.reset(saslOptionArgument);
final DN bindDN = promptForDN(
INFO_INTERACTIVE_LDAP_AUTH_BIND_DN_PROMPT.get(), defaultBindDN,
true);
if (bindDN.isNullDN())
{
bindRequest = new SimpleBindRequest();
argList.add("--bindDN");
argList.add("");
argList.add("--bindPassword");
argList.add("");
ArgumentHelper.addValueSuppressException(bindDNArgument, "");
ArgumentHelper.addValueSuppressException(bindPasswordArgument, "");
}
else
{
final byte[] bindPassword = promptForPassword(
INFO_INTERACTIVE_LDAP_AUTH_PW_PROMPT.get(), true);
bindRequest = new SimpleBindRequest(bindDN, bindPassword);
argList.add("--bindDN");
argList.add(bindDN.toString());
argList.add("--bindPassword");
argList.add("***REDACTED***");
ArgumentHelper.addValueSuppressException(bindDNArgument,
bindDN.toString());
ArgumentHelper.addValueSuppressException(bindPasswordArgument,
StaticUtils.toUTF8String(bindPassword));
}
}
else if (useSASLAuth)
{
String defaultMechChoice = null;
String defaultAuthID = null;
String defaultAuthzID = null;
String defaultRealm = null;
if (saslOptionArgument.isPresent())
{
for (final String saslOption : saslOptionArgument.getValues())
{
final String lowerOption = StaticUtils.toLowerCase(saslOption);
if (lowerOption.equals("mech=cram-md5"))
{
defaultMechChoice = "1";
}
else if (lowerOption.equals("mech=digest-md5"))
{
defaultMechChoice = "2";
}
else if (lowerOption.equals("mech=plain"))
{
defaultMechChoice = "3";
}
else if (lowerOption.startsWith("authid="))
{
defaultAuthID = saslOption.substring(7);
}
else if (lowerOption.startsWith("authzid="))
{
defaultAuthzID = saslOption.substring(8);
}
else if (lowerOption.startsWith("realm="))
{
defaultRealm= saslOption.substring(6);
}
}
}
ArgumentHelper.reset(saslOptionArgument);
final int mech = getNumberedMenuChoice(
INFO_INTERACTIVE_LDAP_AUTH_SASL_PROMPT.get(),
false,
defaultMechChoice,
INFO_INTERACTIVE_LDAP_SASL_OPTION_CRAM_MD5.get(),
INFO_INTERACTIVE_LDAP_SASL_OPTION_DIGEST_MD5.get(),
INFO_INTERACTIVE_LDAP_SASL_OPTION_PLAIN.get());
switch (mech)
{
case 0:
String authID = promptForString(
INFO_INTERACTIVE_LDAP_AUTH_AUTHID_PROMPT.get(),
defaultAuthID, true);
byte[] pw = promptForPassword(
INFO_INTERACTIVE_LDAP_AUTH_PW_PROMPT.get(), true);
bindRequest = new CRAMMD5BindRequest(authID, pw);
argList.add("--saslOption");
argList.add("mech=CRAM-MD5");
argList.add("--saslOption");
argList.add("authID=" + authID);
argList.add("--bindPassword");
argList.add("***REDACTED***");
ArgumentHelper.addValueSuppressException(saslOptionArgument,
"mech=CRAM-MD5");
ArgumentHelper.addValueSuppressException(saslOptionArgument,
"authID=" + authID);
ArgumentHelper.addValueSuppressException(bindPasswordArgument,
StaticUtils.toUTF8String(pw));
break;
case 1:
authID = promptForString(
INFO_INTERACTIVE_LDAP_AUTH_AUTHID_PROMPT.get(),
defaultAuthID, true);
String authzID = promptForString(
INFO_INTERACTIVE_LDAP_AUTH_AUTHZID_PROMPT.get(),
defaultAuthzID, false);
final String realm = promptForString(
INFO_INTERACTIVE_LDAP_AUTH_REALM_PROMPT.get(), defaultRealm,
false);
pw = promptForPassword(INFO_INTERACTIVE_LDAP_AUTH_PW_PROMPT.get(),
true);
bindRequest = new DIGESTMD5BindRequest(authID, authzID, pw,
realm);
argList.add("--saslOption");
argList.add("mech=DIGEST-MD5");
argList.add("--saslOption");
argList.add("authID=" + authID);
ArgumentHelper.addValueSuppressException(saslOptionArgument,
"mech=DIGEST-MD5");
ArgumentHelper.addValueSuppressException(saslOptionArgument,
"authID=" + authID);
if (authzID != null)
{
argList.add("--saslOption");
argList.add("authzID=" + authzID);
ArgumentHelper.addValueSuppressException(saslOptionArgument,
"authzID=" + authzID);
}
if (realm != null)
{
argList.add("--saslOption");
argList.add("realm=" + realm);
ArgumentHelper.addValueSuppressException(saslOptionArgument,
"realm=" + realm);
}
argList.add("--bindPassword");
argList.add("***REDACTED***");
ArgumentHelper.addValueSuppressException(bindPasswordArgument,
StaticUtils.toUTF8String(pw));
break;
case 2:
authID = promptForString(
INFO_INTERACTIVE_LDAP_AUTH_AUTHID_PROMPT.get(),
defaultAuthID, true);
authzID = promptForString(
INFO_INTERACTIVE_LDAP_AUTH_AUTHZID_PROMPT.get(),
defaultAuthzID, false);
pw = promptForPassword(INFO_INTERACTIVE_LDAP_AUTH_PW_PROMPT.get(),
true);
bindRequest = new PLAINBindRequest(authID, authzID, pw);
argList.add("--saslOption");
argList.add("mech=PLAIN");
argList.add("--saslOption");
argList.add("authID=" + authID);
ArgumentHelper.addValueSuppressException(saslOptionArgument,
"mech=PLAIN");
ArgumentHelper.addValueSuppressException(saslOptionArgument,
"authID=" + authID);
if (authzID != null)
{
argList.add("--saslOption");
argList.add("authzID=" + authzID);
ArgumentHelper.addValueSuppressException(saslOptionArgument,
"authzID=" + authzID);
}
argList.add("--bindPassword");
argList.add("***REDACTED***");
ArgumentHelper.addValueSuppressException(bindPasswordArgument,
StaticUtils.toUTF8String(pw));
break;
}
}
}
else
{
ArgumentHelper.reset(bindDNArgument);
}
}
if (test)
{
// Perform the necessary initialization for SSL/TLS communication.
final SSLUtil sslUtil;
if (useSSL || useStartTLS)
{
final KeyManager keyManager;
if (keyStorePath == null)
{
keyManager = null;
}
else
{
final char[] pinChars;
if (keyStorePIN == null)
{
pinChars = null;
}
else
{
final String pinString = StaticUtils.toUTF8String(keyStorePIN);
pinChars = pinString.toCharArray();
}
try
{
keyManager = new KeyStoreKeyManager(keyStorePath, pinChars,
keyStoreFormat, certificateNickname);
}
catch (final Exception e)
{
Debug.debugException(e);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_LDAP_CANNOT_CREATE_KEY_MANAGER.get(
StaticUtils.getExceptionMessage(e)));
if (promptForBoolean(
INFO_INTERACTIVE_LDAP_RETRY_PROMPT.get(), true, true))
{
promptForLDAPArguments(argList, test);
return;
}
else
{
throw new LDAPException(ResultCode.LOCAL_ERROR, "", e);
}
}
}
final TrustManager trustManager;
if (trustAll)
{
trustManager = new TrustAllTrustManager();
}
else if (trustStorePath == null)
{
trustManager = new PromptTrustManager();
}
else
{
final char[] pinChars;
if (trustStorePIN == null)
{
pinChars = null;
}
else
{
final String pinString = StaticUtils.toUTF8String(trustStorePIN);
pinChars = pinString.toCharArray();
}
try
{
trustManager = new TrustStoreTrustManager(trustStorePath, pinChars,
trustStoreFormat, true);
}
catch (final Exception e)
{
Debug.debugException(e);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_LDAP_CANNOT_CREATE_TRUST_MANAGER.get(
StaticUtils.getExceptionMessage(e)));
if (promptForBoolean(
INFO_INTERACTIVE_LDAP_RETRY_PROMPT.get(), true, true))
{
promptForLDAPArguments(argList, test);
return;
}
else
{
throw new LDAPException(ResultCode.LOCAL_ERROR, "", e);
}
}
}
sslUtil = new SSLUtil(keyManager, trustManager);
}
else
{
sslUtil = null;
}
// Create and establish the connection.
final LDAPConnection conn;
if (useSSL)
{
try
{
conn = new LDAPConnection(sslUtil.createSSLSocketFactory());
}
catch (final Exception e)
{
Debug.debugException(e);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_LDAP_CANNOT_CREATE_SOCKET_FACTORY.get(
StaticUtils.getExceptionMessage(e)),
e);
if (promptForBoolean(
INFO_INTERACTIVE_LDAP_RETRY_PROMPT.get(), true, true))
{
promptForLDAPArguments(argList, test);
return;
}
else
{
throw new LDAPException(ResultCode.LOCAL_ERROR, "", e);
}
}
}
else
{
conn = new LDAPConnection();
}
try
{
try
{
conn.connect(hostname, port);
}
catch (final LDAPException le)
{
Debug.debugException(le);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_LDAP_CANNOT_CONNECT.get(hostname, port,
le.getResultString()));
if (promptForBoolean(
INFO_INTERACTIVE_LDAP_RETRY_PROMPT.get(), true, true))
{
promptForLDAPArguments(argList, test);
return;
}
else
{
throw new LDAPException(le.getResultCode(), "", le);
}
}
// If we should use StartTLS to secure the connection, then do so now.
if (useStartTLS)
{
try
{
final ExtendedResult startTLSResult = conn.processExtendedOperation(
new StartTLSExtendedRequest(sslUtil.createSSLContext()));
if (startTLSResult.getResultCode() != ResultCode.SUCCESS)
{
throw new LDAPException(startTLSResult);
}
}
catch (final Exception e)
{
Debug.debugException(e);
final String msg;
if (e instanceof LDAPException)
{
msg = ((LDAPException) e).getResultString();
}
else
{
msg = StaticUtils.getExceptionMessage(e);
}
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_LDAP_CANNOT_PERFORM_STARTTLS.get(msg));
if (promptForBoolean(
INFO_INTERACTIVE_LDAP_RETRY_PROMPT.get(), true, true))
{
promptForLDAPArguments(argList, test);
return;
}
else
{
throw new LDAPException(ResultCode.LOCAL_ERROR, "", e);
}
}
}
// Authenticate the connection if appropriate.
if (bindRequest != null)
{
try
{
conn.bind(bindRequest);
}
catch (final LDAPException le)
{
Debug.debugException(le);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_LDAP_CANNOT_AUTHENTICATE.get(
le.getResultString()));
if (promptForBoolean(
INFO_INTERACTIVE_LDAP_RETRY_PROMPT.get(), true, true))
{
promptForLDAPArguments(argList, test);
return;
}
else
{
throw new LDAPException(le.getResultCode(), "", le);
}
}
}
}
finally
{
conn.close();
}
}
}
/**
* Interactively prompts for the arguments used to connect and optionally
* authenticate to multiple directory servers.
*
* @param argList The list to which the string representations of all LDAP
* arguments should be added.
* @param test Indicates whether to attempt to use the arguments to
* establish an LDAP connection.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForMultiServerLDAPArguments(final List argList,
final boolean test)
throws LDAPException
{
// FIXME -- Implement this.
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_INTERACTIVE_MULTI_SERVER_LDAP_NOT_SUPPORTED.get());
}
/**
* Displays a menu that allows the user to supply values for the command-line
* arguments. Note that this will not include arguments automatically added
* by the {@link LDAPCommandLineTool} API.
*
* @param ldapArgs A list of the arguments used to connect and authenticate
* to the LDAP server(s) in non-interactive mode. The
* contents of this list may be altered if the user opts to
* change the LDAP connection settings.
*
* @return The tool-specific arguments configured by the user.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private List displayInteractiveMenu(final List ldapArgs)
throws LDAPException
{
final ArrayList args =
new ArrayList(parser.getNamedArguments());
if (parser.getSelectedSubCommand() != null)
{
args.addAll(parser.getSelectedSubCommand().getArgumentParser().
getNamedArguments());
}
final Set usageArguments =
CommandLineTool.getUsageArgumentIdentifiers(tool);
final Set ldapArguments;
if (tool instanceof LDAPCommandLineTool)
{
ldapArguments = LDAPCommandLineTool.getLongLDAPArgumentIdentifiers(
((LDAPCommandLineTool) tool));
}
else
{
ldapArguments = Collections.emptySet();
}
int maxIdentifierLength = 0;
final String trailingArgsIdentifier =
INFO_INTEARCTIVE_MENU_TRAILING_ARGS_IDENTIFIER.get();
if (parser.allowsTrailingArguments())
{
maxIdentifierLength = trailingArgsIdentifier.length();
}
final Iterator argIterator = args.iterator();
while (argIterator.hasNext())
{
final Argument a = argIterator.next();
final String longID = a.getLongIdentifier();
if (usageArguments.contains(longID) || ldapArguments.contains(longID))
{
argIterator.remove();
}
else
{
maxIdentifierLength = Math.max(maxIdentifierLength,
a.getIdentifierString().length());
}
}
if (args.isEmpty() && (! parser.allowsTrailingArguments()))
{
return Collections.emptyList();
}
else
{
// First, prompt for all required arguments that don't have a default
// value.
for (final Argument arg : args)
{
if (! arg.isRequired())
{
continue;
}
final List valueStrings =
arg.getValueStringRepresentations(true);
if (! valueStrings.isEmpty())
{
continue;
}
promptForArgument(arg);
}
// If the tool requires trailing arguments, then prompt for them.
if (parser.requiresTrailingArguments())
{
promptForTrailingArguments();
}
argsLoop:
while (true)
{
final int maxNumberLength = String.valueOf(args.size()).length();
final int subsequentIndent = maxNumberLength + maxIdentifierLength + 4;
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_MENU_PROMPT.get());
int optionNumber = 1;
for (final Argument arg : args)
{
List valueStrings = arg.getValueStringRepresentations(true);
if (arg.isSensitive())
{
final int size = valueStrings.size();
switch (size)
{
case 0:
// No need to do any thing.
break;
case 1:
valueStrings = Collections.singletonList("***REDACTED***");
break;
default:
valueStrings = new ArrayList(size);
for (int i=0; i <= size; i++)
{
valueStrings.add("***REDACTED" + i + "***");
}
break;
}
}
switch (valueStrings.size())
{
case 0:
tool.wrapStandardOut(0, subsequentIndent, wrapColumn, true,
rightAlign(String.valueOf(optionNumber), maxNumberLength),
' ',
leftAlign(arg.getIdentifierString(), maxIdentifierLength),
" -");
break;
case 1:
tool.wrapStandardOut(0, subsequentIndent, wrapColumn, true,
rightAlign(String.valueOf(optionNumber), maxNumberLength),
' ',
leftAlign(arg.getIdentifierString(), maxIdentifierLength),
" - ", valueStrings.get(0));
break;
default:
tool.wrapStandardOut(0, subsequentIndent, wrapColumn, true,
rightAlign(String.valueOf(optionNumber), maxNumberLength),
' ',
leftAlign(arg.getIdentifierString(), maxIdentifierLength),
" - ", valueStrings.get(0));
for (int i=1; i < valueStrings.size(); i++)
{
tool.wrapStandardOut(0, subsequentIndent, wrapColumn, true,
rightAlign("", maxNumberLength), ' ',
leftAlign("", maxIdentifierLength),
" - ", valueStrings.get(i));
}
break;
}
optionNumber++;
}
if (parser.allowsTrailingArguments())
{
final List trailingArgs = parser.getTrailingArguments();
switch(trailingArgs.size())
{
case 0:
tool.wrapStandardOut(0, subsequentIndent, wrapColumn, true,
rightAlign("t", maxNumberLength),
' ',
leftAlign(trailingArgsIdentifier, maxIdentifierLength),
" -");
break;
case 1:
tool.wrapStandardOut(0, subsequentIndent, wrapColumn, true,
rightAlign("t", maxNumberLength), ' ',
leftAlign(trailingArgsIdentifier, maxIdentifierLength),
" - ", trailingArgs.get(0));
break;
default:
tool.wrapStandardOut(0, subsequentIndent, wrapColumn, true,
rightAlign("t", maxNumberLength), ' ',
leftAlign(trailingArgsIdentifier, maxIdentifierLength),
" - ", trailingArgs.get(0));
for (int i=1; i < trailingArgs.size(); i++)
{
tool.wrapStandardOut(0, subsequentIndent, wrapColumn, true,
rightAlign("", maxNumberLength), ' ',
leftAlign("", maxIdentifierLength),
" - ", trailingArgs.get(i));
}
break;
}
}
tool.out();
if (tool instanceof LDAPCommandLineTool)
{
final LDAPCommandLineTool ldapTool = (LDAPCommandLineTool) tool;
if (ldapTool.supportsAuthentication())
{
tool.wrapStandardOut((maxNumberLength - 1), subsequentIndent,
wrapColumn, true, "l - ",
INFO_INTERACTIVE_MENU_OPTION_REPROMPT_FOR_CONN_AUTH_ARGS.
get());
}
else
{
tool.wrapStandardOut((maxNumberLength - 1), subsequentIndent,
wrapColumn, true, "l - ",
INFO_INTERACTIVE_MENU_OPTION_REPROMPT_FOR_CONN_ARGS.get());
}
}
else if (tool instanceof MultiServerLDAPCommandLineTool)
{
tool.wrapStandardOut((maxNumberLength - 1), subsequentIndent,
wrapColumn, true, "l - ",
INFO_INTERACTIVE_MENU_OPTION_REPROMPT_FOR_CONN_AUTH_ARGS.
get());
}
tool.wrapStandardOut((maxNumberLength - 1), subsequentIndent,
wrapColumn, true, "d - ",
INFO_INTERACTIVE_MENU_OPTION_DISPLAY_ARGS.get(tool.getToolName()));
tool.wrapStandardOut((maxNumberLength - 1), subsequentIndent,
wrapColumn, true, "r - ",
INFO_INTERACTIVE_MENU_OPTION_RUN.get(tool.getToolName()));
tool.wrapStandardOut((maxNumberLength - 1), subsequentIndent,
wrapColumn, true, "q - ", INFO_INTERACTIVE_MENU_OPTION_QUIT.get());
tool.out();
tool.getOut().print(
INFO_INTERACTIVE_MENU_ENTER_CHOICE_WITHOUT_DEFAULT.get());
final Argument selectedArg;
try
{
while (true)
{
final String line = systemInReader.readLine().trim();
if (line.equalsIgnoreCase("t") &&
(tool.getMaxTrailingArguments() > 0))
{
promptForTrailingArguments();
continue argsLoop;
}
else if (line.equalsIgnoreCase("l"))
{
if (tool instanceof LDAPCommandLineTool)
{
promptForLDAPArguments(ldapArgs, true);
}
else if (tool instanceof MultiServerLDAPCommandLineTool)
{
promptForMultiServerLDAPArguments(ldapArgs, true);
}
else
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_ARG_MENU_INVALID_CHOICE.get());
tool.getOut().print(
INFO_INTERACTIVE_MENU_ENTER_CHOICE_WITHOUT_DEFAULT.get());
}
continue argsLoop;
}
else if (line.equalsIgnoreCase("d"))
{
try
{
tool.doExtendedArgumentValidation();
final ArrayList argStrings =
new ArrayList(2*args.size());
final SubCommand subcommand = parser.getSelectedSubCommand();
if (subcommand != null)
{
argStrings.add(subcommand.getPrimaryName());
}
argStrings.addAll(ldapArgs);
for (final Argument a : args)
{
ArgumentHelper.addToCommandLine(a, argStrings);
}
argStrings.addAll(parser.getTrailingArguments());
if (argStrings.isEmpty())
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_MENU_NO_CURRENT_ARGS.get(
tool.getToolName()));
}
else
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_MENU_CURRENT_ARGS_HEADER.get(
tool.getToolName()));
printArgs(argStrings);
}
tool.out();
promptForString(
INFO_INTERACTIVE_MENU_PROMPT_PRESS_ENTER_TO_CONTINUE.get(),
null, false);
continue argsLoop;
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
tool.err();
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_MENU_EXTENDED_VALIDATION_ERRORS.get(
ae.getMessage()));
tool.err();
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_MENU_CORRECT_VALIDATION_ERRORS.get());
tool.err();
promptForString(
INFO_INTERACTIVE_MENU_PROMPT_PRESS_ENTER_TO_CONTINUE.get(),
null, false);
continue argsLoop;
}
}
else if (line.equalsIgnoreCase("r"))
{
try
{
tool.doExtendedArgumentValidation();
break argsLoop;
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
tool.err();
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_MENU_EXTENDED_VALIDATION_ERRORS.get(
ae.getMessage()));
tool.err();
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_MENU_CORRECT_VALIDATION_ERRORS.get());
tool.err();
promptForString(
INFO_INTERACTIVE_MENU_PROMPT_PRESS_ENTER_TO_CONTINUE.get(),
null, false);
continue argsLoop;
}
}
else if (line.equalsIgnoreCase("q"))
{
throw new LDAPException(ResultCode.SUCCESS, "");
}
int selectedValue = -1;
try
{
selectedValue = Integer.parseInt(line);
}
catch (final Exception e)
{
Debug.debugException(e);
}
if ((selectedValue < 1) || (selectedValue > args.size()))
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_ARG_MENU_INVALID_CHOICE.get());
tool.getOut().print(
INFO_INTERACTIVE_MENU_ENTER_CHOICE_WITHOUT_DEFAULT.get());
}
else
{
selectedArg = args.get(selectedValue - 1);
break;
}
}
}
catch (final LDAPException le)
{
Debug.debugException(le);
throw le;
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_INTERACTIVE_MENU_CANNOT_READ_CHOICE.get(
StaticUtils.getExceptionMessage(e)),
e);
}
promptForArgument(selectedArg);
}
final ArrayList argStrings = new ArrayList(2*args.size());
for (final Argument a : args)
{
ArgumentHelper.addToCommandLine(a, argStrings);
}
argStrings.addAll(parser.getTrailingArguments());
return argStrings;
}
}
/**
* Prompts the user for the trailing argument value(s).
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForTrailingArguments()
throws LDAPException
{
tool.out();
ArgumentHelper.resetTrailingArguments(parser);
if (parser.getMaxTrailingArguments() == 1)
{
if (parser.requiresTrailingArguments())
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_TRAILING_DESC_SINGLE_REQUIRED.get(
tool.getToolName()));
}
else
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_TRAILING_DESC_SINGLE_OPTIONAL.get(
tool.getToolName()));
}
tool.out(" ", tool.getTrailingArgumentsPlaceholder());
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_TRAILING_PROMPT_SINGLE.get());
while (true)
{
final String trailingArgValue = promptForString(
INFO_INTERACTIVE_TRAILING_ARG_PROMPT.get(), null, false);
if (trailingArgValue == null)
{
return;
}
try
{
ArgumentHelper.addTrailingArgument(parser, trailingArgValue);
return;
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_TRAILING_VALUE_INVALID.get(ae.getMessage()));
}
}
}
else
{
if (parser.requiresTrailingArguments())
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_TRAILING_DESC_MULTIPLE_REQUIRED.get(
tool.getToolName(), parser.getMinTrailingArguments()));
}
else
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_TRAILING_DESC_MULTIPLE_OPTIONAL.get(
tool.getToolName()));
}
tool.out(" ", tool.getTrailingArgumentsPlaceholder());
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_TRAILING_PROMPT_MULTIPLE.get());
while (true)
{
final String trailingArgValue = promptForString(
INFO_INTERACTIVE_TRAILING_ARG_PROMPT.get(), null, false);
if (trailingArgValue == null)
{
return;
}
else
{
try
{
ArgumentHelper.addTrailingArgument(parser, trailingArgValue);
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_TRAILING_VALUE_INVALID.get(ae.getMessage()));
}
}
}
}
}
/**
* Prompts the user for the value(s) for the specified argument.
*
* @param a The argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForArgument(final Argument a)
throws LDAPException
{
tool.out();
final int maxValues = a.getMaxOccurrences();
if (maxValues == 1)
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_PROMPT_SPECIFY_SINGLE_VALUE.get(
a.getIdentifierString()));
}
else
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_PROMPT_SPECIFY_MULTIPLE_VALUES.get(
a.getIdentifierString()));
}
final String description = a.getDescription();
if ((description != null) && (description.length() > 0))
{
tool.out();
final String prompt = INFO_INTERACTIVE_ARG_PROMPT_DESCRIPTION.get();
tool.wrapStandardOut(0, prompt.length(), wrapColumn, true, prompt,
description);
}
final String constraints = a.getValueConstraints();
if ((constraints != null) && (constraints.length() > 0))
{
tool.out();
final String prompt = INFO_INTERACTIVE_ARG_PROMPT_CONSTRAINTS.get();
tool.wrapStandardOut(0, prompt.length(), wrapColumn, true, prompt,
constraints);
if (a.isRequired())
{
if (maxValues == 1)
{
tool.wrapStandardOut(prompt.length(), prompt.length(), wrapColumn,
true, INFO_INTERACTIVE_ARG_PROMPT_SINGLE_REQUIRED.get());
}
else
{
tool.wrapStandardOut(prompt.length(), prompt.length(), wrapColumn,
true, INFO_INTERACTIVE_ARG_PROMPT_AT_LEAST_ONE_REQUIRED.get());
}
}
}
else if (a.isRequired())
{
tool.out();
final String prompt = INFO_INTERACTIVE_ARG_PROMPT_CONSTRAINTS.get();
if (maxValues == 1)
{
tool.wrapStandardOut(0, prompt.length(), wrapColumn, true, prompt,
INFO_INTERACTIVE_ARG_PROMPT_SINGLE_REQUIRED.get());
}
else
{
tool.wrapStandardOut(0, prompt.length(), wrapColumn, true, prompt,
INFO_INTERACTIVE_ARG_PROMPT_AT_LEAST_ONE_REQUIRED.get());
}
}
if (a instanceof ArgumentListArgument)
{
promptForArgumentList((ArgumentListArgument) a);
}
else if (a instanceof BooleanArgument)
{
promptForBoolean((BooleanArgument) a);
}
else if (a instanceof BooleanValueArgument)
{
promptForBoolean((BooleanValueArgument) a);
}
else if (a instanceof ControlArgument)
{
promptForControl((ControlArgument) a);
}
else if (a instanceof DNArgument)
{
promptForDN((DNArgument) a);
}
else if (a instanceof DurationArgument)
{
promptForDuration((DurationArgument) a);
}
else if (a instanceof FileArgument)
{
promptForFile((FileArgument) a);
}
else if (a instanceof FilterArgument)
{
promptForFilter((FilterArgument) a);
}
else if (a instanceof IntegerArgument)
{
promptForInteger((IntegerArgument) a);
}
else if (a instanceof ScopeArgument)
{
promptForScope((ScopeArgument) a);
}
else if (a instanceof StringArgument)
{
promptForString((StringArgument) a);
}
else if (a instanceof TimestampArgument)
{
promptForTimestamp((TimestampArgument) a);
}
else
{
// This should never happen.
throw new AssertionError("Unexpected argument type " +
a.getClass().getName());
}
}
/**
* Prompts for one or more argument lists.
*
* @param a The argument list argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForArgumentList(final ArgumentListArgument a)
throws LDAPException
{
final List values = a.getValueStrings();
ArgumentHelper.reset(a);
if (a.getMaxOccurrences() == 1)
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUE.get());
tool.wrapStandardOut(5, 10, wrapColumn, true, values.get(0));
}
while (true)
{
final String newValue = promptForString(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, a.isRequired());
try
{
if (newValue != null)
{
ArgumentHelper.addValue(a, newValue);
}
return;
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_ARG_PROMPT_INVALID_VALUE.get(ae.getMessage()));
}
}
}
else
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUES.get());
for (final String s : values)
{
tool.wrapStandardOut(5, 10, wrapColumn, true, s);
}
}
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUES.get());
boolean first = true;
while (true)
{
final String s = promptForString(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null,
(first && a.isRequired()));
if (s == null)
{
return;
}
try
{
ArgumentHelper.addValue(a, s);
first = false;
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_ARG_PROMPT_INVALID_VALUE.get(ae.getMessage()));
}
}
}
}
/**
* Prompts for a Boolean value.
*
* @param a The Boolean argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForBoolean(final BooleanArgument a)
throws LDAPException
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn,true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUE.get());
tool.wrapStandardOut(5, 10, wrapColumn, true, a.isPresent());
ArgumentHelper.reset(a);
if (promptForBoolean(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, true))
{
ArgumentHelper.incrementOccurrencesSuppressException(a);
}
}
/**
* Prompts for a Boolean value.
*
* @param a The Boolean argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForBoolean(final BooleanValueArgument a)
throws LDAPException
{
final Boolean value = a.getValue();
ArgumentHelper.reset(a);
final Boolean b = promptForBoolean(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, a.isRequired());
if (b != null)
{
ArgumentHelper.addValueSuppressException(a, String.valueOf(b));
}
}
/**
* Prompts for one or more control values.
*
* @param a The control argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForControl(final ControlArgument a)
throws LDAPException
{
final List values = a.getValues();
ArgumentHelper.reset(a);
if (a.getMaxOccurrences() == 1)
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUE.get());
tool.wrapStandardOut(5, 10, wrapColumn, true, values.get(0));
}
while (true)
{
final String newValue = promptForString(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, false);
try
{
if (newValue == null)
{
ArgumentHelper.addValue(a, "");
}
else
{
ArgumentHelper.addValue(a, newValue);
}
return;
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_ARG_PROMPT_INVALID_VALUE.get(ae.getMessage()));
}
}
}
else
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUES.get());
for (final Control c : values)
{
tool.wrapStandardOut(5, 10, wrapColumn, true, c);
}
}
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUES.get());
boolean first = true;
while (true)
{
final String s = promptForString(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null,
(first && a.isRequired()));
if (s == null)
{
return;
}
try
{
ArgumentHelper.addValue(a, s);
first = false;
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_ARG_PROMPT_INVALID_VALUE.get(ae.getMessage()));
}
}
}
}
/**
* Prompts for one or more DN values.
*
* @param a The DN argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForDN(final DNArgument a)
throws LDAPException
{
final List values = a.getValues();
ArgumentHelper.reset(a);
if (a.getMaxOccurrences() == 1)
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUE.get());
tool.wrapStandardOut(5, 10, wrapColumn, true, values.get(0));
}
final DN dnValue = promptForDN(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, true);
ArgumentHelper.addValueSuppressException(a, String.valueOf(dnValue));
}
else
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUES.get());
for (final DN dn : values)
{
tool.wrapStandardOut(5, 10, wrapColumn, true, dn);
}
}
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUES.get());
boolean first = true;
while (true)
{
final boolean allowNullDN;
if (first)
{
first = false;
allowNullDN = ! a.isRequired();
}
else
{
allowNullDN = true;
}
final DN dnValue = promptForDN(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, allowNullDN);
if (dnValue.isNullDN())
{
return;
}
else
{
ArgumentHelper.addValueSuppressException(a, String.valueOf(dnValue));
}
}
}
}
/**
* Prompts for one or more duration values.
*
* @param a The duration argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForDuration(final DurationArgument a)
throws LDAPException
{
final List values = a.getValueStringRepresentations(true);
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUE.get());
tool.wrapStandardOut(5, 10, wrapColumn, true, values.get(0));
}
while (true)
{
final String newValue = promptForString(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, a.isRequired());
try
{
if (newValue != null)
{
ArgumentHelper.addValue(a, newValue);
}
return;
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_ARG_PROMPT_INVALID_VALUE.get(ae.getMessage()));
}
}
}
/**
* Prompts for one or more path values.
*
* @param a The file argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForFile(final FileArgument a)
throws LDAPException
{
final List values = a.getValues();
ArgumentHelper.reset(a);
if (a.getMaxOccurrences() == 1)
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUE.get());
tool.wrapStandardOut(5, 10, wrapColumn, true, values.get(0));
}
final File fileValue = promptForPath(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, a.isRequired(),
a.fileMustExist(), a.parentMustExist(), a.mustBeFile(),
a.mustBeDirectory());
if (fileValue != null)
{
ArgumentHelper.addValueSuppressException(a, fileValue.getPath());
}
}
else
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUES.get());
for (final File f : values)
{
tool.wrapStandardOut(5, 10, wrapColumn, true, f.getPath());
}
}
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUES.get());
boolean first = true;
while (true)
{
final boolean isRequired;
if (first)
{
first = false;
isRequired = a.isRequired();
}
else
{
isRequired = false;
}
final File fileValue = promptForPath(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, isRequired,
a.fileMustExist(), a.parentMustExist(), a.mustBeFile(),
a.mustBeDirectory());
if (fileValue == null)
{
return;
}
else
{
ArgumentHelper.addValueSuppressException(a, fileValue.getPath());
}
}
}
}
/**
* Prompts for one or more filter values.
*
* @param a The filter argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForFilter(final FilterArgument a)
throws LDAPException
{
final List values = a.getValues();
ArgumentHelper.reset(a);
if (a.getMaxOccurrences() == 1)
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUE.get());
tool.wrapStandardOut(5, 10, wrapColumn, true, values.get(0));
}
final Filter filterValue = promptForFilter(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, a.isRequired());
if (filterValue != null)
{
ArgumentHelper.addValueSuppressException(a, filterValue.toString());
}
}
else
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUES.get());
for (final Filter f : values)
{
tool.wrapStandardOut(5, 10, wrapColumn, true, String.valueOf(f));
}
}
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUES.get());
boolean first = true;
while (true)
{
final boolean isRequired;
if (first)
{
first = false;
isRequired = a.isRequired();
}
else
{
isRequired = false;
}
final Filter filterValue = promptForFilter(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, isRequired);
if (filterValue == null)
{
return;
}
else
{
ArgumentHelper.addValueSuppressException(a,
String.valueOf(filterValue));
}
}
}
}
/**
* Prompts for one or more integer values.
*
* @param a The integer argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForInteger(final IntegerArgument a)
throws LDAPException
{
final List values = a.getValues();
ArgumentHelper.reset(a);
if (a.getMaxOccurrences() == 1)
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUE.get());
tool.wrapStandardOut(5, 10, wrapColumn, true, values.get(0));
}
final Integer intValue = promptForInteger(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null,
a.getLowerBound(), a.getUpperBound(), a.isRequired());
if (intValue != null)
{
ArgumentHelper.addValueSuppressException(a,
String.valueOf(intValue));
}
}
else
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUES.get());
for (final Integer i : values)
{
tool.wrapStandardOut(5, 10, wrapColumn, true, i);
}
}
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUES.get());
boolean first = true;
while (true)
{
final boolean isRequired;
if (first)
{
first = false;
isRequired = a.isRequired();
}
else
{
isRequired = false;
}
final Integer intValue = promptForInteger(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null,
a.getLowerBound(), a.getUpperBound(), isRequired);
if (intValue == null)
{
return;
}
else
{
ArgumentHelper.addValueSuppressException(a,
String.valueOf(intValue));
}
}
}
}
/**
* Prompts for one or more scope values.
*
* @param a The scope argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForScope(final ScopeArgument a)
throws LDAPException
{
final SearchScope value = a.getValue();
ArgumentHelper.reset(a);
final String[] scopeValues =
{
"base",
"one",
"sub",
"subordinates"
};
tool.out();
if (value != null)
{
if (value.intValue() < scopeValues.length)
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUE.get());
tool.wrapStandardOut(5, 10, wrapColumn, true,
scopeValues[value.intValue()]);
}
}
final int newIntValue = getNumberedMenuChoice(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(),
(! a.isRequired()),
null,
scopeValues);
if (newIntValue >= 0)
{
ArgumentHelper.addValueSuppressException(a, scopeValues[newIntValue]);
}
}
/**
* Prompts for one or more string values.
*
* @param a The string argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForString(final StringArgument a)
throws LDAPException
{
// If the argument has a relatively small set of allowed values, then
// display a menu to allow the user to select one of those values.
if ((a.getAllowedValues() != null) && (! a.getAllowedValues().isEmpty()) &&
(a.getAllowedValues().size() <= 20))
{
promptForStringWithMenu(a);
return;
}
final List values = a.getValues();
ArgumentHelper.reset(a);
if (a.getMaxOccurrences() == 1)
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUE.get());
tool.wrapStandardOut(5, 10, wrapColumn, true, values.get(0));
}
while (true)
{
final String newValue;
if (a.isSensitive())
{
final byte[] newValueBytes = promptForPassword(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), a.isRequired());
if (newValueBytes == null)
{
newValue = null;
}
else
{
newValue = StaticUtils.toUTF8String(newValueBytes);
}
}
else
{
newValue = promptForString(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null,
a.isRequired());
}
try
{
if (newValue != null)
{
ArgumentHelper.addValue(a, newValue);
}
return;
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_ARG_PROMPT_INVALID_VALUE.get(ae.getMessage()));
}
}
}
else
{
if (! values.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUES.get());
for (final String s : values)
{
tool.wrapStandardOut(5, 10, wrapColumn, true, s);
}
}
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUES.get());
boolean first = true;
while (true)
{
final String s = promptForString(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null,
(first && a.isRequired()));
if (s == null)
{
return;
}
try
{
ArgumentHelper.addValue(a, s);
first = false;
}
catch (final ArgumentException ae)
{
Debug.debugException(ae);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_ARG_PROMPT_INVALID_VALUE.get(ae.getMessage()));
}
}
}
}
/**
* Prompts for one or more string values using a menu to display the allowed
* choices.
*
* @param a The string argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForStringWithMenu(final StringArgument a)
throws LDAPException
{
final List values = a.getValues();
ArgumentHelper.reset(a);
final String[] allowedValueArray = new String[a.getAllowedValues().size()];
a.getAllowedValues().toArray(allowedValueArray);
if (! values.isEmpty())
{
tool.out();
if (values.size() == 1)
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUE.get());
tool.wrapStandardOut(5, 10, wrapColumn, true, values.get(0));
}
else
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUES.get());
for (final String s : values)
{
tool.wrapStandardOut(5, 10, wrapColumn, true, s);
}
}
}
final String message;
if (a.getMaxOccurrences() > 1)
{
message = INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUES.get();
}
else
{
message = INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get();
}
final int firstChoice = getNumberedMenuChoice(message, (! a.isRequired()),
null, allowedValueArray);
if (firstChoice < 0)
{
return;
}
ArgumentHelper.addValueSuppressException(a, allowedValueArray[firstChoice]);
if (a.getMaxOccurrences() > 1)
{
while (true)
{
final String stringValue = promptForString(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, false);
if (stringValue == null)
{
return;
}
else if (stringValue.equalsIgnoreCase("q"))
{
throw new LDAPException(ResultCode.SUCCESS, "");
}
int selectedValue = -1;
try
{
selectedValue = Integer.parseInt(stringValue);
}
catch (final Exception e)
{
Debug.debugException(e);
}
if ((selectedValue < 1) || (selectedValue > allowedValueArray.length))
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_MENU_INVALID_CHOICE.get());
}
else
{
ArgumentHelper.addValueSuppressException(a,
allowedValueArray[selectedValue - 1]);
}
}
}
}
/**
* Prompts for one or more timestamp values.
*
* @param a The timestamp argument for which to prompt.
*
* @throws LDAPException If a problem is encountered while interacting with
* the user, or if the user wants to quit.
*/
private void promptForTimestamp(final TimestampArgument a)
throws LDAPException
{
final List stringValues = a.getValueStringRepresentations(true);
ArgumentHelper.reset(a);
if (a.getMaxOccurrences() == 1)
{
if (! stringValues.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUE.get());
tool.wrapStandardOut(5, 10, wrapColumn, true, stringValues.get(0));
}
final ObjectPair p = promptForTimestamp(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, a.isRequired());
if (p != null)
{
ArgumentHelper.addValueSuppressException(a, p.getSecond());
}
}
else
{
if (! stringValues.isEmpty())
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUES.get());
for (final String s : stringValues)
{
tool.wrapStandardOut(5, 10, wrapColumn, true, String.valueOf(s));
}
}
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUES.get());
boolean first = true;
while (true)
{
final boolean isRequired;
if (first)
{
first = false;
isRequired = a.isRequired();
}
else
{
isRequired = false;
}
final Filter filterValue = promptForFilter(
INFO_INTERACTIVE_ARG_PROMPT_NEW_VALUE.get(), null, isRequired);
if (filterValue == null)
{
return;
}
else
{
ArgumentHelper.addValueSuppressException(a,
String.valueOf(filterValue));
}
}
}
}
/**
* Displays a menu of numbered options, and waits for the user to select one
* of the options.
*
* @param prompt The string to display above the list of
* numbered options.
* @param allowUndefined Indicates whether to allow the value to remain
* undefined.
* @param defaultOptionString The number that corresponds to the default
* option that will be selected if the user
* presses ENTER without typing anything. This
* should be the display string value, so if it
* is a number then it should be one-based rather
* than zero-based. It may be {@code null} if no
* default string should be provided.
* @param options The set of text to display next to the
* numbered options.
*
* @return The index of the option that was selected, or -1 if an undefined
* value is allowed and that option was selected. Note that although
* the displayed menu will start numbering with one, the value
* returned will start numbering at zero so as to correspond with the
* elements in the provided options array.
*
* @throws LDAPException If an error occurs while determining which option
* the user has chosen, or if the user has chosen to
* quit rather than select a numbered option.
*/
private int getNumberedMenuChoice(final String prompt,
final boolean allowUndefined,
final String defaultOptionString,
final String... options)
throws LDAPException
{
final int maxNumberLength = String.valueOf(options.length).length();
final int subsequentIndent = maxNumberLength + 3;
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, true, prompt);
int optionNumber = 1;
for (final String option : options)
{
tool.wrapStandardOut(0, subsequentIndent, wrapColumn, true,
rightAlign(String.valueOf(optionNumber), maxNumberLength), " - ",
option);
optionNumber++;
}
tool.out();
if (allowUndefined)
{
tool.wrapStandardOut((maxNumberLength - 1), subsequentIndent, wrapColumn,
true, "u - ", INFO_INTERACTIVE_MENU_OPTION_UNDEFINED.get());
}
tool.wrapStandardOut((maxNumberLength - 1), subsequentIndent, wrapColumn,
true, "q - ", INFO_INTERACTIVE_MENU_OPTION_QUIT.get());
final String message;
if (defaultOptionString == null)
{
message = INFO_INTERACTIVE_MENU_ENTER_CHOICE_WITHOUT_DEFAULT.get();
}
else
{
message = INFO_INTERACTIVE_MENU_ENTER_CHOICE_WITH_DEFAULT.get(
defaultOptionString);
}
try
{
while (true)
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, false, message);
String line = systemInReader.readLine().trim();
if (line.equalsIgnoreCase("q"))
{
throw new LDAPException(ResultCode.SUCCESS, "");
}
else if (allowUndefined && line.equalsIgnoreCase("u"))
{
return -1;
}
if ((line.length() == 0) && (defaultOptionString != null))
{
line = defaultOptionString;
}
int selectedValue = -1;
try
{
selectedValue = Integer.parseInt(line);
}
catch (final Exception e)
{
Debug.debugException(e);
}
if ((selectedValue < 1) || (selectedValue > options.length))
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_MENU_INVALID_CHOICE.get());
}
else
{
return selectedValue - 1;
}
}
}
catch (final LDAPException le)
{
Debug.debugException(le);
throw le;
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_INTERACTIVE_MENU_CANNOT_READ_CHOICE.get(
StaticUtils.getExceptionMessage(e)),
e);
}
}
/**
* Prompts the user to enter a string value.
*
* @param prompt The prompt to display to the user.
* @param defaultValue The value that should be selected if the user
* presses ENTER without entering a value.
* @param requireValue Indicates whether a value is required.
*
* @return The string obtained from the user, or {@code null} if the user did
* not provide a value, there is no default value, and no value is
* required.
*
* @throws LDAPException If an error occurs while obtaining the value from
* the user.
*/
private String promptForString(final String prompt, final String defaultValue,
final boolean requireValue)
throws LDAPException
{
tool.out();
final String promptStr;
if (defaultValue == null)
{
promptStr = prompt + ": ";
}
else
{
promptStr = prompt + " [" + defaultValue + "]: ";
}
tool.wrapStandardOut(0, 0, wrapColumn, false, promptStr);
try
{
String line = systemInReader.readLine().trim();
if ((line.length() == 0) && (defaultValue != null))
{
line = defaultValue;
}
if (line.length() > 0)
{
return line;
}
else if (requireValue)
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_VALUE_REQUIRED.get());
return promptForString(prompt, defaultValue, requireValue);
}
else
{
return null;
}
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_INTERACTIVE_PROMPT_ERROR_READING_RESPONSE.get(
StaticUtils.getExceptionMessage(e)),
e);
}
}
/**
* Prompts the user to enter a Boolean value.
*
* @param prompt The prompt to display to the user.
* @param defaultValue The value that should be selected if the user
* presses ENTER without entering a value.
* @param requireValue Indicates whether a value is required.
*
* @return The Boolean value obtained from the user, or {@code null} if the
* user did not provide a value, there is no default value, and no
* value is required.
*
* @throws LDAPException If an error occurs while obtaining the value from
* the user.
*/
private Boolean promptForBoolean(final String prompt,
final Boolean defaultValue,
final boolean requireValue)
throws LDAPException
{
final String[] choices =
{
"true",
"false"
};
tool.out();
if (defaultValue != null)
{
tool.wrapStandardOut(0, 0, wrapColumn, true,
INFO_INTERACTIVE_ARG_DESC_CURRENT_VALUE.get());
tool.wrapStandardOut(5, 10, wrapColumn, true,
String.valueOf(defaultValue));
}
final int newIntValue = getNumberedMenuChoice(prompt, (! requireValue),
null, choices);
switch (newIntValue)
{
case 0:
return Boolean.TRUE;
case 1:
return Boolean.FALSE;
default:
return null;
}
}
/**
* Prompts the user to enter a distinguished name value.
*
* @param prompt The prompt to display to the user.
* @param defaultValue The value that should be selected if the user
* presses ENTER without entering a value.
* @param nullDNAllowed Indicates whether the user is allowed to select the
* null DN by pressing ENTER without entering a value.
* Note that it will not be possible to specify the
* null DN if a default value is supplied, since the
* default value will be chosen instead.
*
* @return The DN value obtained from the user. It may be the null DN if
* the user pressed ENTER without specifying a value.
*
* @throws LDAPException If an error occurs while obtaining the value from
* the user.
*/
private DN promptForDN(final String prompt, final String defaultValue,
final boolean nullDNAllowed)
throws LDAPException
{
tool.out();
final String promptStr;
if (defaultValue == null)
{
promptStr = prompt + ": ";
}
else
{
promptStr = prompt + " [" + defaultValue + "]: ";
}
tool.wrapStandardOut(0, 0, wrapColumn, false, promptStr);
try
{
String line = systemInReader.readLine().trim();
if (line.length() == 0)
{
if (defaultValue != null)
{
line = defaultValue;
}
if (line.length() == 0)
{
if (nullDNAllowed)
{
return DN.NULL_DN;
}
else
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_NULL_DN_NOT_ALLOWED.get());
return promptForDN(prompt, defaultValue, nullDNAllowed);
}
}
}
try
{
return new DN(line);
}
catch (final Exception e)
{
Debug.debugException(e);
tool.wrapErr(0, wrapColumn, ERR_INTERACTIVE_PROMPT_INVALID_DN.get());
return promptForDN(prompt, defaultValue, nullDNAllowed);
}
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_INTERACTIVE_PROMPT_ERROR_READING_RESPONSE.get(
StaticUtils.getExceptionMessage(e)),
e);
}
}
/**
* Prompts the user to enter a filter.
*
* @param prompt The prompt to display to the user.
* @param defaultValue The value that should be selected if the user
* presses ENTER without entering a value.
* @param requireValue Indicates whether a value is required.
*
* @return The filter obtained from the user, or {@code null} if the user did
* not provide a value, there is no default value, and no value is
* required.
*
* @throws LDAPException If an error occurs while obtaining the value from
* the user.
*/
private Filter promptForFilter(final String prompt, final Filter defaultValue,
final boolean requireValue)
throws LDAPException
{
tool.out();
final String promptStr;
if (defaultValue == null)
{
promptStr = prompt + ": ";
}
else
{
promptStr = prompt + " [" + defaultValue + "]: ";
}
tool.wrapStandardOut(0, 0, wrapColumn, false, promptStr);
try
{
String line = systemInReader.readLine().trim();
if ((line.length() == 0) && (defaultValue != null))
{
line = String.valueOf(defaultValue);
}
if (line.length() == 0)
{
if (requireValue)
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_VALUE_REQUIRED.get());
return promptForFilter(prompt, defaultValue, requireValue);
}
else
{
return null;
}
}
try
{
return Filter.create(line);
}
catch (final Exception e)
{
Debug.debugException(e);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_INVALID_FILTER.get());
return promptForFilter(prompt, defaultValue, requireValue);
}
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_INTERACTIVE_PROMPT_ERROR_READING_RESPONSE.get(
StaticUtils.getExceptionMessage(e)),
e);
}
}
/**
* Prompts the user to enter an integer value.
*
* @param prompt The prompt to display to the user.
* @param defaultValue The value that should be selected if the user
* presses ENTER without entering a value.
* @param lowerBound The lower bound for valid values.
* @param upperBound The upper bound for valid values.
* @param requireValue Indicates whether a value is required.
*
* @return The value obtained from the user, or {@code null} if the user did
* not provide a value, there is no default value, and no value is
* required.
*
* @throws LDAPException If an error occurs while obtaining the value from
* the user.
*/
private Integer promptForInteger(final String prompt,
final Integer defaultValue,
final Integer lowerBound,
final Integer upperBound,
final boolean requireValue)
throws LDAPException
{
tool.out();
final int max;
if (upperBound == null)
{
max = Integer.MAX_VALUE;
}
else
{
max = upperBound;
}
final int min;
if (lowerBound == null)
{
min = Integer.MIN_VALUE;
}
else
{
min = lowerBound;
}
final String promptStr;
if (defaultValue == null)
{
promptStr = prompt + ": ";
}
else
{
promptStr = prompt + " [" + defaultValue + "]: ";
}
tool.wrapStandardOut(0, 0, wrapColumn, false, promptStr);
try
{
String line = systemInReader.readLine().trim();
if ((line.length() == 0) && (defaultValue != null))
{
line = String.valueOf(defaultValue);
}
if (line.length() == 0)
{
if (requireValue)
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_VALUE_REQUIRED.get());
return promptForInteger(prompt, defaultValue, lowerBound, upperBound,
requireValue);
}
else
{
return null;
}
}
final int intValue;
try
{
intValue = Integer.parseInt(line);
}
catch (final Exception e)
{
Debug.debugException(e);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_INVALID_INTEGER_WITH_RANGE.get(min, max));
return promptForInteger(prompt, defaultValue, lowerBound, upperBound,
requireValue);
}
if ((intValue > max) || (intValue < min))
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_INVALID_INTEGER_WITH_RANGE.get(min, max));
return promptForInteger(prompt, defaultValue, lowerBound, upperBound,
requireValue);
}
return intValue;
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_INTERACTIVE_PROMPT_ERROR_READING_RESPONSE.get(
StaticUtils.getExceptionMessage(e)),
e);
}
}
/**
* Prompts the user to enter a path.
*
* @param prompt The prompt to display to the user.
* @param defaultValue The value that should be selected if the user
* presses ENTER without entering a value.
* @param requireValue Indicates whether a value is required.
* @param fileMustExist Indicates whether the value must represent a path
* that exists.
* @param parentMustExist Indicates whether the parent directory containing
* the specified path must exist.
* @param mustBeFile Indicates whether the path must represent a file.
* @param mustBeDirectory Indicates whether the path must represent a
* directory.
*
* @return The file obtained from the user, or {@code null} if the user did
* not provide a value, there is no default value, and no value is
* required.
*
* @throws LDAPException If an error occurs while obtaining the value from
* the user.
*/
private File promptForPath(final String prompt, final String defaultValue,
final boolean requireValue,
final boolean fileMustExist,
final boolean parentMustExist,
final boolean mustBeFile,
final boolean mustBeDirectory)
throws LDAPException
{
tool.out();
final String promptStr;
if (defaultValue == null)
{
promptStr = prompt + ": ";
}
else
{
promptStr = prompt + " [" + defaultValue + "]: ";
}
tool.wrapStandardOut(0, 0, wrapColumn, false, promptStr);
try
{
String line = systemInReader.readLine().trim();
if ((line.length() == 0) && (defaultValue != null))
{
line = String.valueOf(defaultValue);
}
if (line.length() == 0)
{
if (requireValue)
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_VALUE_REQUIRED.get());
return promptForPath(prompt, defaultValue, requireValue,
fileMustExist, parentMustExist, mustBeFile, mustBeDirectory);
}
else
{
return null;
}
}
final File f = new File(line);
if (! f.exists())
{
if (fileMustExist)
{
if (mustBeDirectory)
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_DIR_DOES_NOT_EXIST.get(
f.getAbsolutePath()));
return promptForPath(prompt, defaultValue, requireValue,
fileMustExist, parentMustExist, mustBeFile, mustBeDirectory);
}
else
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_FILE_DOES_NOT_EXIST.get(
f.getAbsolutePath()));
return promptForPath(prompt, defaultValue, requireValue,
fileMustExist, parentMustExist, mustBeFile, mustBeDirectory);
}
}
else if (parentMustExist)
{
final File parent = f.getParentFile();
if ((parent == null) || (! parent.exists()))
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_PARENT_DOES_NOT_EXIST.get(
f.getAbsolutePath()));
return promptForPath(prompt, defaultValue, requireValue,
fileMustExist, parentMustExist, mustBeFile, mustBeDirectory);
}
}
return f;
}
if (f.isDirectory())
{
if (mustBeFile)
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_PATH_MUST_BE_FILE.get(
f.getAbsolutePath()));
return promptForPath(prompt, defaultValue, requireValue,
fileMustExist, parentMustExist, mustBeFile, mustBeDirectory);
}
}
else if (mustBeDirectory)
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_PATH_MUST_BE_DIR.get(
f.getAbsolutePath()));
return promptForPath(prompt, defaultValue, requireValue,
fileMustExist, parentMustExist, mustBeFile, mustBeDirectory);
}
return f;
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_INTERACTIVE_PROMPT_ERROR_READING_RESPONSE.get(
StaticUtils.getExceptionMessage(e)),
e);
}
}
/**
* Prompts the user to enter a password.
*
* @param prompt The prompt to display to the user.
* @param requireValue Indicates whether a value is required.
*
* @return The password obtained from the user, or {@code null} if the user
* did not provide a value and no value is required.
*
* @throws LDAPException If an error occurs while obtaining the value from
* the user.
*/
private byte[] promptForPassword(final String prompt,
final boolean requireValue)
throws LDAPException
{
tool.out();
tool.wrapStandardOut(0, 0, wrapColumn, false, prompt, ": ");
try
{
final byte[] pwBytes;
try
{
if (IN_UNIT_TEST)
{
PasswordReader.setTestReader(systemInReader);
}
pwBytes = PasswordReader.readPassword();
}
finally
{
PasswordReader.setTestReader(null);
}
if ((pwBytes == null) || (pwBytes.length == 0))
{
if (requireValue)
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_VALUE_REQUIRED.get());
return promptForPassword(prompt, requireValue);
}
else
{
return null;
}
}
else
{
return pwBytes;
}
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_INTERACTIVE_PROMPT_ERROR_READING_RESPONSE.get(
StaticUtils.getExceptionMessage(e)),
e);
}
}
/**
* Prompts the user to enter a timestamp.
*
* @param prompt The prompt to display to the user.
* @param defaultValue The value that should be selected if the user
* presses ENTER without entering a value.
* @param requireValue Indicates whether a value is required.
*
* @return An object pair that contains both the parsed date and the string
* representation provided by the user, or {@code null} if the user
* did not provide a value, there is no default value, and no value
* is required.
*
* @throws LDAPException If an error occurs while obtaining the value from
* the user.
*/
private ObjectPair promptForTimestamp(final String prompt,
final Date defaultValue,
final boolean requireValue)
throws LDAPException
{
tool.out();
final String promptStr;
if (defaultValue == null)
{
promptStr = prompt + ": ";
}
else
{
promptStr = prompt + " [" + defaultValue + "]: ";
}
tool.wrapStandardOut(0, 0, wrapColumn, false, promptStr);
try
{
String line = systemInReader.readLine().trim();
if ((line.length() == 0) && (defaultValue != null))
{
line = String.valueOf(defaultValue);
}
if (line.length() == 0)
{
if (requireValue)
{
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_VALUE_REQUIRED.get());
return promptForTimestamp(prompt, defaultValue, requireValue);
}
else
{
return null;
}
}
try
{
return new ObjectPair(
TimestampArgument.parseTimestamp(line), line);
}
catch (final Exception e)
{
Debug.debugException(e);
tool.wrapErr(0, wrapColumn,
ERR_INTERACTIVE_PROMPT_INVALID_TIMESTAMP.get());
return promptForTimestamp(prompt, defaultValue, requireValue);
}
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_INTERACTIVE_PROMPT_ERROR_READING_RESPONSE.get(
StaticUtils.getExceptionMessage(e)),
e);
}
}
/**
* Creates a new string with enough initial spaces to ensure that the last
* character of the returned string is also the last character of the provided
* string.
*
* @param s The string to be right-aligned.
* @param w The number of characters to include in the string that is
* returned.
*
* @return A right-aligned representation of the provided string in the given
* width.
*/
private static String rightAlign(final String s, final int w)
{
final int l = s.length();
if (l >= w)
{
return s;
}
final StringBuilder buffer = new StringBuilder(w);
for (int i=0; i < (w-l); i++)
{
buffer.append(' ');
}
buffer.append(s);
return buffer.toString();
}
/**
* Creates a new string with enough trailing spaces to ensure that the
* returned string has the specified width.
*
* @param s The string to be left-aligned.
* @param w The number of characters to include in the string that is
* returned.
*
* @return A left-aligned representation of the provided string in the given
* width.
*/
private static String leftAlign(final String s, final int w)
{
final int l = s.length();
if (l >= w)
{
return s;
}
final StringBuilder buffer = new StringBuilder(w);
buffer.append(s);
while (buffer.length() < w)
{
buffer.append(' ');
}
return buffer.toString();
}
/**
* Specifies whether this processor is being run in a unit test environment.
*
* @param inUnitTest Indicates whether this processor is being run in a unit
* test environment.
*/
static void setInUnitTest(final boolean inUnitTest)
{
IN_UNIT_TEST = inUnitTest;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy