/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions Copyright [year] [name of copyright owner]".
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2016 ForgeRock AS.
*/
package org.opends.server.tools;
import static com.forgerock.opendj.cli.ArgumentConstants.*;
import static com.forgerock.opendj.cli.CliMessages.INFO_JMXPORT_PLACEHOLDER;
import static com.forgerock.opendj.cli.CliMessages.INFO_KEYSTORE_PWD_FILE_PLACEHOLDER;
import static com.forgerock.opendj.cli.CliMessages.INFO_NUM_ENTRIES_PLACEHOLDER;
import static com.forgerock.opendj.cli.CliMessages.INFO_PORT_PLACEHOLDER;
import static com.forgerock.opendj.cli.CliMessages.INFO_ROOT_USER_PWD_FILE_PLACEHOLDER;
import static com.forgerock.opendj.cli.CommonArguments.*;
import static com.forgerock.opendj.cli.Utils.addErrorMessageIfArgumentsConflict;
import static com.forgerock.opendj.util.OperatingSystem.*;
import static org.opends.messages.ToolMessages.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizableMessageDescriptor.Arg1;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.opends.quicksetup.Constants;
import org.opends.quicksetup.Installation;
import org.opends.quicksetup.UserData;
import org.opends.quicksetup.util.Utils;
import org.opends.server.config.AdministrationConnector;
import org.opends.server.core.DirectoryServer.DirectoryServerVersionHandler;
import com.forgerock.opendj.cli.Argument;
import com.forgerock.opendj.cli.ArgumentException;
import com.forgerock.opendj.cli.ArgumentParser;
import com.forgerock.opendj.cli.BooleanArgument;
import com.forgerock.opendj.cli.CliConstants;
import com.forgerock.opendj.cli.FileBasedArgument;
import com.forgerock.opendj.cli.IntegerArgument;
import com.forgerock.opendj.cli.StringArgument;
/**
* Class used to parse the arguments of the setup command-line and to check
* that there are not conflicting arguments (nor missing arguments in no prompt
* mode).
* Note that this class does not perform checks involving network (like if
* a given port is free) nor the validity of the certificate information
* provided.
*/
public class InstallDSArgumentParser extends ArgumentParser
{
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
private BooleanArgument cliArg;
BooleanArgument addBaseEntryArg;
private BooleanArgument showUsageArg;
BooleanArgument quietArg;
BooleanArgument noPromptArg;
BooleanArgument verboseArg;
private StringArgument propertiesFileArgument;
private BooleanArgument noPropertiesFileArgument;
BooleanArgument skipPortCheckArg;
BooleanArgument enableWindowsServiceArg;
BooleanArgument doNotStartArg;
BooleanArgument enableStartTLSArg;
BooleanArgument generateSelfSignedCertificateArg;
StringArgument hostNameArg;
BooleanArgument usePkcs11Arg;
StringArgument useBcfksArg;
private FileBasedArgument directoryManagerPwdFileArg;
private FileBasedArgument keyStorePasswordFileArg;
IntegerArgument ldapPortArg;
IntegerArgument adminConnectorPortArg;
IntegerArgument ldapsPortArg;
IntegerArgument jmxPortArg;
IntegerArgument sampleDataArg;
StringArgument baseDNArg;
StringArgument importLDIFArg;
StringArgument rejectedImportFileArg;
StringArgument skippedImportFileArg;
StringArgument directoryManagerDNArg;
private StringArgument directoryManagerPwdStringArg;
StringArgument useJavaKeyStoreArg;
StringArgument useJCEKSArg;
StringArgument usePkcs12Arg;
private StringArgument keyStorePasswordArg;
StringArgument certNicknameArg;
private StringArgument progNameArg;
private IntegerArgument connectTimeoutArg;
BooleanArgument acceptLicense;
StringArgument backendTypeArg;
/**
* The default constructor for this class.
* @param mainClassName the class name of the main class for the command-line
* that is being used.
*/
public InstallDSArgumentParser(String mainClassName)
{
super(mainClassName, INFO_INSTALLDS_TOOL_DESCRIPTION.get(), false);
setShortToolDescription(REF_SHORT_DESC_SETUP.get());
setVersionHandler(new DirectoryServerVersionHandler());
}
/**
* Initializes the arguments without parsing them.
* @throws ArgumentException if there was an error creating or adding the
* arguments. If this occurs is likely to be a bug.
*/
public void initializeArguments() throws ArgumentException
{
cliArg = cliArgument();
addArgument(cliArg);
progNameArg = StringArgument.builder("programName")
.shortIdentifier('P')
.description(INFO_INSTALLDS_DESCRIPTION_PROGNAME.get())
.hidden()
.defaultValue(Installation.getSetupFileName())
.valuePlaceholder(INFO_PROGRAM_NAME_PLACEHOLDER.get())
.buildArgument();
addArgument(progNameArg);
noPromptArg = noPromptArgument();
addArgument(noPromptArg);
quietArg = quietArgument();
addArgument(quietArg);
verboseArg = verboseArgument();
addArgument(verboseArg);
propertiesFileArgument =
StringArgument.builder(OPTION_LONG_PROP_FILE_PATH)
.description(INFO_DESCRIPTION_PROP_FILE_PATH.get())
.valuePlaceholder(INFO_PROP_FILE_PATH_PLACEHOLDER.get())
.buildArgument();
addArgument(propertiesFileArgument);
setFilePropertiesArgument(propertiesFileArgument);
noPropertiesFileArgument =
BooleanArgument.builder(OPTION_LONG_NO_PROP_FILE)
.description(INFO_DESCRIPTION_NO_PROP_FILE.get())
.buildArgument();
addArgument(noPropertiesFileArgument);
setNoPropertiesFileArgument(noPropertiesFileArgument);
baseDNArg =
StringArgument.builder(OPTION_LONG_BASEDN)
.shortIdentifier(OPTION_SHORT_BASEDN)
.description(INFO_INSTALLDS_DESCRIPTION_BASEDN.get())
.multiValued()
.valuePlaceholder(INFO_BASEDN_PLACEHOLDER.get())
.buildArgument();
addArgument(baseDNArg);
addBaseEntryArg =
BooleanArgument.builder("addBaseEntry")
.shortIdentifier('a')
.description(INFO_INSTALLDS_DESCRIPTION_ADDBASE.get())
.buildArgument();
addArgument(addBaseEntryArg);
importLDIFArg =
StringArgument.builder(OPTION_LONG_LDIF_FILE)
.shortIdentifier(OPTION_SHORT_LDIF_FILE)
.description(INFO_INSTALLDS_DESCRIPTION_IMPORTLDIF.get())
.multiValued()
.valuePlaceholder(INFO_LDIFFILE_PLACEHOLDER.get())
.buildArgument();
addArgument(importLDIFArg);
rejectedImportFileArg =
StringArgument.builder("rejectFile")
.shortIdentifier('R')
.description(INFO_INSTALLDS_DESCRIPTION_REJECTED_FILE.get())
.valuePlaceholder(INFO_REJECT_FILE_PLACEHOLDER.get())
.buildArgument();
addArgument(rejectedImportFileArg);
skippedImportFileArg =
StringArgument.builder("skipFile")
.description(INFO_INSTALLDS_DESCRIPTION_SKIPPED_FILE.get())
.valuePlaceholder(INFO_SKIP_FILE_PLACEHOLDER.get())
.buildArgument();
addArgument(skippedImportFileArg);
sampleDataArg =
IntegerArgument.builder("sampleData")
.shortIdentifier('d')
.description(INFO_INSTALLDS_DESCRIPTION_SAMPLE_DATA.get())
.lowerBound(0)
.defaultValue(0)
.valuePlaceholder(INFO_NUM_ENTRIES_PLACEHOLDER.get())
.buildArgument();
addArgument(sampleDataArg);
int defaultLdapPort = UserData.getDefaultPort();
if (defaultLdapPort == -1)
{
defaultLdapPort = 389;
}
ldapPortArg =
IntegerArgument.builder("ldapPort")
.shortIdentifier(OPTION_SHORT_PORT)
.description(INFO_INSTALLDS_DESCRIPTION_LDAPPORT.get())
.range(1, 65535)
.defaultValue(defaultLdapPort)
.valuePlaceholder(INFO_PORT_PLACEHOLDER.get())
.buildArgument();
addArgument(ldapPortArg);
int defaultAdminPort = UserData.getDefaultAdminConnectorPort();
if (defaultAdminPort == -1)
{
defaultAdminPort =
AdministrationConnector.DEFAULT_ADMINISTRATION_CONNECTOR_PORT;
}
adminConnectorPortArg =
IntegerArgument.builder("adminConnectorPort")
.description(INFO_INSTALLDS_DESCRIPTION_ADMINCONNECTORPORT.get())
.range(1, 65535)
.defaultValue(defaultAdminPort)
.valuePlaceholder(INFO_PORT_PLACEHOLDER.get())
.buildArgument();
addArgument(adminConnectorPortArg);
jmxPortArg =
IntegerArgument.builder("jmxPort")
.shortIdentifier('x')
.description(INFO_INSTALLDS_DESCRIPTION_JMXPORT.get())
.range(1, 65535)
.defaultValue(CliConstants.DEFAULT_JMX_PORT)
.valuePlaceholder(INFO_JMXPORT_PLACEHOLDER.get())
.buildArgument();
addArgument(jmxPortArg);
skipPortCheckArg =
BooleanArgument.builder("skipPortCheck")
.shortIdentifier('S')
.description(INFO_INSTALLDS_DESCRIPTION_SKIPPORT.get())
.buildArgument();
addArgument(skipPortCheckArg);
directoryManagerDNArg =
StringArgument.builder(OPTION_LONG_ROOT_USER_DN)
.shortIdentifier(OPTION_SHORT_ROOT_USER_DN)
.description(INFO_INSTALLDS_DESCRIPTION_ROOTDN.get())
.defaultValue("cn=Directory Manager")
.valuePlaceholder(INFO_ROOT_USER_DN_PLACEHOLDER.get())
.buildArgument();
addArgument(directoryManagerDNArg);
directoryManagerPwdStringArg =
StringArgument.builder("rootUserPassword")
.shortIdentifier(OPTION_SHORT_BINDPWD)
.description(INFO_INSTALLDS_DESCRIPTION_ROOTPW.get())
.valuePlaceholder(INFO_ROOT_USER_PWD_PLACEHOLDER.get())
.buildArgument();
addArgument(directoryManagerPwdStringArg);
directoryManagerPwdFileArg =
FileBasedArgument.builder("rootUserPasswordFile")
.shortIdentifier(OPTION_SHORT_BINDPWD_FILE)
.description(INFO_INSTALLDS_DESCRIPTION_ROOTPWFILE.get())
.valuePlaceholder(INFO_ROOT_USER_PWD_FILE_PLACEHOLDER.get())
.buildArgument();
addArgument(directoryManagerPwdFileArg);
enableWindowsServiceArg =
BooleanArgument.builder("enableWindowsService")
.shortIdentifier('e')
.description(INFO_INSTALLDS_DESCRIPTION_ENABLE_WINDOWS_SERVICE.get())
.buildArgument();
if (isWindows())
{
addArgument(enableWindowsServiceArg);
}
doNotStartArg =
BooleanArgument.builder("doNotStart")
.shortIdentifier('O')
.description(INFO_INSTALLDS_DESCRIPTION_DO_NOT_START.get())
.buildArgument();
addArgument(doNotStartArg);
enableStartTLSArg =
BooleanArgument.builder("enableStartTLS")
.shortIdentifier(OPTION_SHORT_START_TLS)
.description(INFO_INSTALLDS_DESCRIPTION_ENABLE_STARTTLS.get())
.buildArgument();
addArgument(enableStartTLSArg);
int defaultSecurePort = UserData.getDefaultSslPort(defaultLdapPort);
if (defaultSecurePort == -1)
{
defaultSecurePort = 636;
}
ldapsPortArg =
IntegerArgument.builder("ldapsPort")
.shortIdentifier(OPTION_SHORT_USE_SSL)
.description(INFO_INSTALLDS_DESCRIPTION_LDAPSPORT.get())
.range(1, 65535)
.defaultValue(defaultSecurePort)
.valuePlaceholder(INFO_PORT_PLACEHOLDER.get())
.buildArgument();
addArgument(ldapsPortArg);
generateSelfSignedCertificateArg =
BooleanArgument.builder("generateSelfSignedCertificate")
.description(INFO_INSTALLDS_DESCRIPTION_USE_SELF_SIGNED.get())
.buildArgument();
addArgument(generateSelfSignedCertificateArg);
hostNameArg =
StringArgument.builder(OPTION_LONG_HOST)
.shortIdentifier(OPTION_SHORT_HOST)
.description(INFO_INSTALLDS_DESCRIPTION_HOST_NAME.get())
.defaultValue(UserData.getDefaultHostName())
.valuePlaceholder(INFO_HOST_PLACEHOLDER.get())
.buildArgument();
addDefaultArgument(hostNameArg);
usePkcs11Arg =
BooleanArgument.builder("usePkcs11Keystore")
.description(INFO_INSTALLDS_DESCRIPTION_USE_PKCS11.get())
.buildArgument();
addArgument(usePkcs11Arg);
useBcfksArg =
StringArgument.builder("useBcfksKeystore")
.description(INFO_INSTALLDS_DESCRIPTION_USE_BCFKS.get())
.valuePlaceholder(INFO_KEYSTOREPATH_PLACEHOLDER.get())
.buildArgument();
addArgument(useBcfksArg);
useJavaKeyStoreArg =
StringArgument.builder("useJavaKeystore")
.description(INFO_INSTALLDS_DESCRIPTION_USE_JAVAKEYSTORE.get())
.valuePlaceholder(INFO_KEYSTOREPATH_PLACEHOLDER.get())
.buildArgument();
addArgument(useJavaKeyStoreArg);
useJCEKSArg =
StringArgument.builder("useJCEKS")
.description(INFO_INSTALLDS_DESCRIPTION_USE_JCEKS.get())
.valuePlaceholder(INFO_KEYSTOREPATH_PLACEHOLDER.get())
.buildArgument();
addArgument(useJCEKSArg);
usePkcs12Arg =
StringArgument.builder("usePkcs12keyStore")
.description(INFO_INSTALLDS_DESCRIPTION_USE_PKCS12.get())
.valuePlaceholder(INFO_KEYSTOREPATH_PLACEHOLDER.get())
.buildArgument();
addArgument(usePkcs12Arg);
keyStorePasswordArg =
StringArgument.builder(OPTION_LONG_KEYSTORE_PWD)
.shortIdentifier(OPTION_SHORT_KEYSTORE_PWD)
.description(INFO_INSTALLDS_DESCRIPTION_KEYSTOREPASSWORD.get())
.valuePlaceholder(INFO_KEYSTORE_PWD_PLACEHOLDER.get())
.buildArgument();
addDefaultArgument(keyStorePasswordArg);
keyStorePasswordFileArg =
FileBasedArgument.builder(OPTION_LONG_KEYSTORE_PWD_FILE)
.shortIdentifier(OPTION_SHORT_KEYSTORE_PWD_FILE)
.description(INFO_INSTALLDS_DESCRIPTION_KEYSTOREPASSWORD_FILE.get())
.valuePlaceholder(INFO_KEYSTORE_PWD_FILE_PLACEHOLDER.get())
.buildArgument();
addDefaultArgument(keyStorePasswordFileArg);
certNicknameArg =
StringArgument.builder(OPTION_LONG_CERT_NICKNAME)
.shortIdentifier(OPTION_SHORT_CERT_NICKNAME)
.description(INFO_INSTALLDS_DESCRIPTION_CERT_NICKNAME.get())
.multiValued()
.valuePlaceholder(INFO_NICKNAME_PLACEHOLDER.get())
.buildArgument();
addDefaultArgument(certNicknameArg);
connectTimeoutArg = connectTimeOutArgument();
addArgument(connectTimeoutArg);
acceptLicense = acceptLicenseArgument();
addArgument(acceptLicense);
showUsageArg = showUsageArgument();
addArgument(showUsageArg);
setUsageArgument(showUsageArg);
backendTypeArg =
StringArgument.builder(OPTION_LONG_BACKEND_TYPE)
.shortIdentifier(OPTION_SHORT_BACKEND_TYPE)
.description(INFO_INSTALLDS_DESCRIPTION_BACKEND_TYPE.get())
.defaultValue(BackendTypeHelper.filterSchemaBackendName(
new BackendTypeHelper().getBackendTypes().get(0).getName()))
.valuePlaceholder(INFO_INSTALLDS_BACKEND_TYPE_PLACEHOLDER.get())
.buildArgument();
addArgument(backendTypeArg);
}
/**
* Returns whether the command was launched in CLI mode or not.
* @return true if the command was launched to use CLI mode and
* false otherwise.
*/
public boolean isCli()
{
return cliArg.isPresent();
}
@Override
public void parseArguments(String[] args) throws ArgumentException
{
LinkedHashSet errorMessages = new LinkedHashSet<>();
try
{
super.parseArguments(args);
}
catch (ArgumentException ae)
{
logger.error(LocalizableMessage.raw("Error parsing arguments: "+ae, ae));
errorMessages.add(ae.getMessageObject());
}
if (!isUsageArgumentPresent() && !isVersionArgumentPresent())
{
checkServerPassword(errorMessages);
checkProvidedPorts(errorMessages);
checkImportDataArguments(errorMessages);
checkSecurityArguments(errorMessages);
if (!errorMessages.isEmpty())
{
throw new ArgumentException(ERR_CANNOT_INITIALIZE_ARGS.get(
Utils.getMessageFromCollection(errorMessages, Constants.LINE_SEPARATOR)));
}
}
}
/**
* Returns the directory manager password provided by the user. This method
* should be called after a call to parseArguments.
* @return the directory manager password provided by the user.
*/
public String getDirectoryManagerPassword()
{
if (directoryManagerPwdStringArg.isPresent())
{
return directoryManagerPwdStringArg.getValue();
}
else if (directoryManagerPwdFileArg.isPresent())
{
return directoryManagerPwdFileArg.getValue();
}
return null;
}
/**
* Returns the key store password provided by the user. This method should be
* called after a call to parseArguments.
* @return the key store password provided by the user.
*/
public String getKeyStorePassword()
{
if (keyStorePasswordArg.isPresent())
{
return keyStorePasswordArg.getValue();
}
else if (keyStorePasswordFileArg.isPresent())
{
return keyStorePasswordFileArg.getValue();
}
return null;
}
/**
* Checks that there are no conflicts with the directory manager passwords.
* If we are in no prompt mode, check that the password was provided.
* @param errorMessages the list of messages to which we add the error
* messages describing the problems encountered during the execution of the
* checking.
*/
private void checkServerPassword(Collection errorMessages)
{
addErrorMessageIfArgumentsConflict(errorMessages, directoryManagerPwdStringArg, directoryManagerPwdFileArg);
if (noPromptArg.isPresent() && !directoryManagerPwdStringArg.isPresent() &&
!directoryManagerPwdFileArg.isPresent())
{
errorMessages.add(ERR_INSTALLDS_NO_ROOT_PASSWORD.get(
directoryManagerPwdStringArg.getLongIdentifier(),
directoryManagerPwdFileArg.getLongIdentifier()));
}
}
/**
* Checks that there are no conflicts with the provided ports (like if the
* user provided the same port for different protocols).
* @param errorMessages the list of messages to which we add the error
* messages describing the problems encountered during the execution of the
* checking.
*/
private void checkProvidedPorts(Collection errorMessages)
{
try
{
Set ports = new HashSet<>();
ports.add(ldapPortArg.getIntValue());
checkPortAlreadyUsed(ports, adminConnectorPortArg.getIntValue(), errorMessages,
ERR_CONFIGDS_PORT_ALREADY_SPECIFIED);
if (jmxPortArg.isPresent())
{
checkPortAlreadyUsed(ports, jmxPortArg.getIntValue(), errorMessages, ERR_CONFIGDS_PORT_ALREADY_SPECIFIED);
}
if (ldapsPortArg.isPresent())
{
checkPortAlreadyUsed(ports, ldapsPortArg.getIntValue(), errorMessages, ERR_CONFIGDS_PORT_ALREADY_SPECIFIED);
}
}
catch (ArgumentException ae)
{
logger.error(LocalizableMessage.raw("Unexpected error. "+
"Assuming that it is caused by a previous parsing issue: "+ae, ae));
}
}
private void checkPortAlreadyUsed(Set ports, int port, Collection errorMessages,
Arg1