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

kenneth_suter
22.48.2007 2d93a199604f010b176eac1e690272ea8fd61bf0
Expands the interface of both the export-ldif and import-ldif tools to include arguments that allow the task to be scheduled to run in the directory server's JVM through the task interface as well as through the existing method or operating within the running JVM.

- This introduces several classes that handle the plumbing of scheduling a task:

LDAPConnectionArgumentParser: an argument parser that comes pre-populated with the common options used to specify an LDAP connection and includes a method for creating a connection

TaskScheduleInformation: source of information important for creating the scheduled task entry in the backend

TaskScheduleClient: interacts on behalf of clients that wish to schedule tasks

TaskTool: base class that the tools can implement to handle decision about whether to operate locally or remotely

- For export-ldif I removed the short identifier -w for the wrap options since it conflicted with the -w password option.

- For import-ldif I removed the short identifiers -K for skipFile and -q for quiet since they conflicted with the options for specifying the keystore path and startTLS options respectively.
5 files added
3 files modified
1387 ■■■■■ changed files
opends/src/messages/messages/tools.properties 44 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/ExportLDIF.java 218 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/ImportLDIF.java 264 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/tasks/TaskScheduleInformation.java 65 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/tasks/TaskSchedulingClient.java 208 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/tasks/TaskTool.java 101 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/tasks/package-info.java 37 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/util/args/LDAPConnectionArgumentParser.java 450 ●●●●● patch | view | raw | blame | history
opends/src/messages/messages/tools.properties
@@ -2158,3 +2158,47 @@
 weight
FATAL_ERR_INITIALIZE_SERVER_ROOT_1293=An unexpected error occured \
  attempting to set the server's root directory to %s: %s
SEVERE_ERR_LDAP_CONN_MUTUALLY_EXCLUSIVE_ARGUMENTS_1294=ERROR:  You may not \
 provide both the %s and the %s arguments
SEVERE_ERR_LDAP_CONN_CANNOT_INITIALIZE_SSL_1295=ERROR:  Unable to perform SSL \
 initialization:  %s
SEVERE_ERR_LDAP_CONN_CANNOT_PARSE_SASL_OPTION_1296=ERROR:  The provided SASL \
 option string "%s" could not be parsed in the form "name=value"
SEVERE_ERR_LDAP_CONN_NO_SASL_MECHANISM_1297=ERROR:  One or more SASL options were \
 provided, but none of them were the "mech" option to specify which SASL \
 mechanism should be used
SEVERE_ERR_LDAP_CONN_CANNOT_DETERMINE_PORT_1298=ERROR:  Cannot parse the value of \
 the %s argument as an integer value between 1 and 65535:  %s
SEVERE_ERR_LDAP_CONN_CANNOT_CONNECT_1299=ERROR:  Cannot establish a connection to \
 the Directory Server:  %s
INFO_LDAP_CONN_DESCRIPTION_HOST_1300=Directory server hostname or IP address
INFO_LDAP_CONN_DESCRIPTION_PORT_1301=Directory server port number
INFO_LDAP_CONN_DESCRIPTION_USESSL_1302=Use SSL for secure communication with the \
 server
INFO_LDAP_CONN_DESCRIPTION_USESTARTTLS_1303=Use StartTLS for secure communication \
 with the server
INFO_LDAP_CONN_DESCRIPTION_BINDDN_1304=Specifies the DN to use to bind to the \
 server
INFO_LDAP_CONN_DESCRIPTION_BINDPW_1305=Specifies the password to use to bind to \
 the server
INFO_LDAP_CONN_DESCRIPTION_BINDPWFILE_1306=Bind password file
INFO_LDAP_CONN_DESCRIPTION_SASLOPTIONS_1307=SASL bind options
INFO_LDAP_CONN_DESCRIPTION_TRUST_ALL_1308=Trust all server SSL certificates
INFO_LDAP_CONN_DESCRIPTION_KSFILE_1309=Certificate keystore path
INFO_LDAP_CONN_DESCRIPTION_KSPW_1310=Certificate keystore PIN
INFO_LDAP_CONN_DESCRIPTION_KSPWFILE_1311=Certificate keystore PIN file
INFO_LDAP_CONN_DESCRIPTION_TSFILE_1312=Certificate trust store path
INFO_LDAP_CONN_DESCRIPTION_TSPW_1313=Certificate trust store PIN
INFO_LDAP_CONN_DESCRIPTION_TSPWFILE_1314=Certificate trust store PIN file
SEVERE_ERR_TASK_CLIENT_UNEXPECTED_CONNECTION_CLOSURE_1315=NOTICE:  The connection \
 to the Directory Server was closed while waiting for a response to the \
 shutdown request.  This likely means that the server has started the shutdown \
 process
SEVERE_ERR_TASK_CLIENT_IO_ERROR_1316=ERROR:  An I/O error occurred while attempting \
 to communicate with the Directory Server:  %s
SEVERE_ERR_TASK_CLIENT_DECODE_ERROR_1317=ERROR:  An error occurred while trying to \
 decode the response from the server:  %s
SEVERE_ERR_TASK_CLIENT_INVALID_RESPONSE_TYPE_1318=ERROR:  Expected an add response \
 message but got a %s message instead
INFO_TASK_CLIENT_TASK_SCHEDULED_1319=Scheduled task %s
opends/src/server/org/opends/server/tools/ExportLDIF.java
@@ -25,9 +25,6 @@
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.tools;
import org.opends.messages.Message;
import java.io.OutputStream;
import java.io.PrintStream;
@@ -39,6 +36,7 @@
import org.opends.server.api.ErrorLogPublisher;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.config.ConfigException;
import static org.opends.server.config.ConfigConstants.*;
import org.opends.server.core.CoreConfigManager;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.LockFileManager;
@@ -53,35 +51,42 @@
import org.opends.server.types.LDIFExportConfig;
import org.opends.server.types.NullOutputStream;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.RawAttribute;
import org.opends.server.util.args.ArgumentException;
import org.opends.server.util.args.ArgumentParser;
import org.opends.server.util.args.BooleanArgument;
import org.opends.server.util.args.IntegerArgument;
import org.opends.server.util.args.StringArgument;
import org.opends.server.util.args.LDAPConnectionArgumentParser;
import org.opends.messages.Message;
import static org.opends.messages.ToolMessages.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import static org.opends.server.tools.ToolConstants.*;
import org.opends.server.tools.tasks.TaskTool;
import org.opends.server.admin.std.server.BackendCfg;
import org.opends.server.protocols.ldap.LDAPAttribute;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.tasks.ExportTask;
/**
 * This program provides a utility that may be used to export the contents of a
 * Directory Server backend to an LDIF file.  This will be a process that is
 * intended to run separate from Directory Server and not internally within the
 * server process (e.g., via the tasks interface).
 * Directory Server backend to an LDIF file.  Depending on the arguments given,
 * this program will either perform the export directly as a process that
 * runs separate from Directory Server; or by scheduling a task to perform the
 * action within the Directory Server via the tasks interface.
 */
public class ExportLDIF
{
public class ExportLDIF extends TaskTool {
  private static ErrorLogPublisher errorLogPublisher = null;
  /**
   * The main method for ExportLDIF tool.
   *
   * @param  args  The command-line arguments provided to this program.
   */
  public static void main(String[] args)
  {
    int retCode = mainExportLDIF(args, true, System.out, System.err);
@@ -126,6 +131,32 @@
                                   OutputStream outStream,
                                   OutputStream errStream)
  {
    ExportLDIF tool = new ExportLDIF();
    return tool.process(args, initializeServer, outStream, errStream);
  }
  // Define the command-line arguments that may be used with this program.
  private BooleanArgument appendToLDIF            = null;
  private BooleanArgument compressLDIF            = null;
  private BooleanArgument displayUsage            = null;
  private BooleanArgument encryptLDIF             = null;
  private BooleanArgument excludeOperationalAttrs = null;
  private BooleanArgument signHash                = null;
  private IntegerArgument wrapColumn              = null;
  private StringArgument  backendID               = null;
  private StringArgument  configClass             = null;
  private StringArgument  configFile              = null;
  private StringArgument  excludeAttributeStrings = null;
  private StringArgument  excludeBranchStrings    = null;
  private StringArgument  excludeFilterStrings    = null;
  private StringArgument  includeAttributeStrings = null;
  private StringArgument  includeBranchStrings    = null;
  private StringArgument  includeFilterStrings    = null;
  private StringArgument  ldifFile                = null;
  private int process(String[] args, boolean initializeServer,
                      OutputStream outStream, OutputStream errStream) {
    PrintStream out;
    if (outStream == null)
    {
@@ -146,30 +177,10 @@
      err = new PrintStream(errStream);
    }
    // Define the command-line arguments that may be used with this program.
    BooleanArgument appendToLDIF            = null;
    BooleanArgument compressLDIF            = null;
    BooleanArgument displayUsage            = null;
    BooleanArgument encryptLDIF             = null;
    BooleanArgument excludeOperationalAttrs = null;
    BooleanArgument signHash                = null;
    IntegerArgument wrapColumn              = null;
    StringArgument  backendID               = null;
    StringArgument  configClass             = null;
    StringArgument  configFile              = null;
    StringArgument  excludeAttributeStrings = null;
    StringArgument  excludeBranchStrings    = null;
    StringArgument  excludeFilterStrings    = null;
    StringArgument  includeAttributeStrings = null;
    StringArgument  includeBranchStrings    = null;
    StringArgument  includeFilterStrings    = null;
    StringArgument  ldifFile                = null;
    // Create the command-line argument parser for use with this program.
    Message toolDescription = INFO_LDIFEXPORT_TOOL_DESCRIPTION.get();
    ArgumentParser argParser =
         new ArgumentParser("org.opends.server.tools.ExportLDIF",
    LDAPConnectionArgumentParser argParser =
         new LDAPConnectionArgumentParser("org.opends.server.tools.ExportLDIF",
                            toolDescription, false);
@@ -267,7 +278,7 @@
      wrapColumn =
           new IntegerArgument("wrapcolumn", 'w', "wrapColumn", false, false,
           new IntegerArgument("wrapcolumn", null, "wrapColumn", false, false,
                               true, "{wrapColumn}", 0, null, true, 0, false, 0,
                               INFO_LDIFEXPORT_DESCRIPTION_WRAP_COLUMN.get());
      argParser.addArgument(wrapColumn);
@@ -330,6 +341,147 @@
      return 0;
    }
    return process(argParser, initializeServer, out, err);
  }
  /**
   * {@inheritDoc}
   */
  public void addTaskAttributes(List<RawAttribute> attributes)
  {
    //
    // Required attributes
    //
    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>(1);
    values.add(new ASN1OctetString(ldifFile.getValue()));
    attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_LDIF_FILE, values));
    values = new ArrayList<ASN1OctetString>(1);
    values.add(new ASN1OctetString(backendID.getValue()));
    attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_BACKEND_ID, values));
    //
    // Optional attributes
    //
    if (appendToLDIF.getValue() != null &&
            !appendToLDIF.getValue().equals(appendToLDIF.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(appendToLDIF.getValue()));
      attributes.add(
              new LDAPAttribute(ATTR_TASK_EXPORT_APPEND_TO_LDIF, values));
    }
    if (compressLDIF.getValue() != null &&
            !compressLDIF.getValue().equals(compressLDIF.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(compressLDIF.getValue()));
      attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_COMPRESS_LDIF, values));
    }
    if (encryptLDIF.getValue() != null &&
            !encryptLDIF.getValue().equals(encryptLDIF.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(encryptLDIF.getValue()));
      attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_ENCRYPT_LDIF, values));
    }
    if (signHash.getValue() != null &&
            !signHash.getValue().equals(signHash.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(signHash.getValue()));
      attributes.add(
              new LDAPAttribute(ATTR_TASK_EXPORT_SIGN_HASH, values));
    }
    List<String> includeAttributes = includeAttributeStrings.getValues();
    if (includeAttributes != null && includeAttributes.size() > 0) {
      values = new ArrayList<ASN1OctetString>(includeAttributes.size());
      for (String includeAttribute : includeAttributes) {
        values.add(new ASN1OctetString(includeAttribute));
      }
      attributes.add(
              new LDAPAttribute(ATTR_TASK_EXPORT_INCLUDE_ATTRIBUTE, values));
    }
    List<String> excludeAttributes = excludeAttributeStrings.getValues();
    if (excludeAttributes != null && excludeAttributes.size() > 0) {
      values = new ArrayList<ASN1OctetString>(excludeAttributes.size());
      for (String excludeAttribute : excludeAttributes) {
        values.add(new ASN1OctetString(excludeAttribute));
      }
      attributes.add(
              new LDAPAttribute(ATTR_TASK_EXPORT_EXCLUDE_ATTRIBUTE, values));
    }
    List<String> includeFilters = includeFilterStrings.getValues();
    if (includeFilters != null && includeFilters.size() > 0) {
      values = new ArrayList<ASN1OctetString>(includeFilters.size());
      for (String includeFilter : includeFilters) {
        values.add(new ASN1OctetString(includeFilter));
      }
      attributes.add(
              new LDAPAttribute(ATTR_TASK_EXPORT_INCLUDE_FILTER, values));
    }
    List<String> excludeFilters = excludeFilterStrings.getValues();
    if (excludeFilters != null && excludeFilters.size() > 0) {
      values = new ArrayList<ASN1OctetString>(excludeFilters.size());
      for (String excludeFilter : excludeFilters) {
        values.add(new ASN1OctetString(excludeFilter));
      }
      attributes.add(
              new LDAPAttribute(ATTR_TASK_EXPORT_EXCLUDE_FILTER, values));
    }
    List<String> includeBranches = includeBranchStrings.getValues();
    if (includeBranches != null && includeBranches.size() > 0) {
      values = new ArrayList<ASN1OctetString>(includeBranches.size());
      for (String includeBranche : includeBranches) {
        values.add(new ASN1OctetString(includeBranche));
      }
      attributes.add(
              new LDAPAttribute(ATTR_TASK_EXPORT_INCLUDE_BRANCH, values));
    }
    List<String> excludeBranches = excludeBranchStrings.getValues();
    if (excludeBranches != null && excludeBranches.size() > 0) {
      values = new ArrayList<ASN1OctetString>(excludeBranches.size());
      for (String excludeBranche : excludeBranches) {
        values.add(new ASN1OctetString(excludeBranche));
      }
      attributes.add(
              new LDAPAttribute(ATTR_TASK_EXPORT_EXCLUDE_BRANCH, values));
    }
    if (wrapColumn.getValue() != null &&
            !wrapColumn.getValue().equals(wrapColumn.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(wrapColumn.getValue()));
      attributes.add(
              new LDAPAttribute(ATTR_TASK_EXPORT_WRAP_COLUMN, values));
    }
  }
  /**
   * {@inheritDoc}
   */
  public String getTaskObjectclass() {
    return "ds-task-export";
  }
  /**
   * {@inheritDoc}
   */
  public Class getTaskClass() {
    return ExportTask.class;
  }
  /**
   * {@inheritDoc}
   */
  protected int processLocal(boolean initializeServer,
                           PrintStream out,
                           PrintStream err) {
    // Perform the initial bootstrap of the Directory Server and process the
    // configuration.
opends/src/server/org/opends/server/tools/ImportLDIF.java
@@ -41,6 +41,7 @@
import org.opends.server.api.ErrorLogPublisher;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.config.ConfigException;
import static org.opends.server.config.ConfigConstants.*;
import org.opends.server.core.CoreConfigManager;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.LockFileManager;
@@ -58,19 +59,23 @@
import org.opends.server.types.LDIFImportResult;
import org.opends.server.types.NullOutputStream;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.RawAttribute;
import org.opends.server.util.args.ArgumentException;
import org.opends.server.util.args.ArgumentParser;
import org.opends.server.util.args.BooleanArgument;
import org.opends.server.util.args.IntegerArgument;
import org.opends.server.util.args.StringArgument;
import org.opends.server.util.args.LDAPConnectionArgumentParser;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.messages.ToolMessages.*;
import org.opends.messages.Message;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import static org.opends.server.tools.ToolConstants.*;
import org.opends.server.tools.tasks.TaskTool;
import org.opends.server.tasks.ImportTask;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.ldap.LDAPAttribute;
/**
@@ -79,8 +84,7 @@
 * intended to run separate from Directory Server and not internally within the
 * server process (e.g., via the tasks interface).
 */
public class ImportLDIF
{
public class ImportLDIF extends TaskTool {
  /**
   * The buffer size that should be used when reading data from LDIF.
   */
@@ -138,6 +142,39 @@
                                   OutputStream outStream,
                                   OutputStream errStream)
  {
    ImportLDIF tool = new ImportLDIF();
    return tool.process(args, initializeServer, outStream, errStream);
  }
  // Define the command-line arguments that may be used with this program.
  private BooleanArgument append                  = null;
  private BooleanArgument countRejects            = null;
  private BooleanArgument displayUsage            = null;
  private BooleanArgument isCompressed            = null;
  private BooleanArgument isEncrypted             = null;
  private BooleanArgument overwrite               = null;
  private BooleanArgument quietMode               = null;
  private BooleanArgument replaceExisting         = null;
  private BooleanArgument skipSchemaValidation    = null;
  private BooleanArgument clearBackend            = null;
  private IntegerArgument randomSeed              = null;
  private StringArgument  backendID               = null;
  private StringArgument  configClass             = null;
  private StringArgument  configFile              = null;
  private StringArgument  excludeAttributeStrings = null;
  private StringArgument  excludeBranchStrings    = null;
  private StringArgument  excludeFilterStrings    = null;
  private StringArgument  includeAttributeStrings = null;
  private StringArgument  includeBranchStrings    = null;
  private StringArgument  includeFilterStrings    = null;
  private StringArgument  ldifFiles               = null;
  private StringArgument  rejectFile              = null;
  private StringArgument  skipFile                = null;
  private StringArgument  templateFile            = null;
  private int process(String[] args, boolean initializeServer,
                      OutputStream outStream, OutputStream errStream) {
    PrintStream out;
    if (outStream == null)
    {
@@ -160,37 +197,11 @@
    // FIXME -- Need to add a mechanism for verifying the file signature.
    // Define the command-line arguments that may be used with this program.
    BooleanArgument append                  = null;
    BooleanArgument countRejects            = null;
    BooleanArgument displayUsage            = null;
    BooleanArgument isCompressed            = null;
    BooleanArgument isEncrypted             = null;
    BooleanArgument overwrite               = null;
    BooleanArgument quietMode               = null;
    BooleanArgument replaceExisting         = null;
    BooleanArgument skipSchemaValidation    = null;
    BooleanArgument clearBackend            = null;
    IntegerArgument randomSeed              = null;
    StringArgument  backendID               = null;
    StringArgument  configClass             = null;
    StringArgument  configFile              = null;
    StringArgument  excludeAttributeStrings = null;
    StringArgument  excludeBranchStrings    = null;
    StringArgument  excludeFilterStrings    = null;
    StringArgument  includeAttributeStrings = null;
    StringArgument  includeBranchStrings    = null;
    StringArgument  includeFilterStrings    = null;
    StringArgument  ldifFiles               = null;
    StringArgument  rejectFile              = null;
    StringArgument  skipFile                = null;
    StringArgument  templateFile            = null;
    // Create the command-line argument parser for use with this program.
    Message toolDescription = INFO_LDIFIMPORT_TOOL_DESCRIPTION.get();
    ArgumentParser argParser =
         new ArgumentParser("org.opends.server.tools.ImportLDIF",
    LDAPConnectionArgumentParser argParser =
         new LDAPConnectionArgumentParser("org.opends.server.tools.ImportLDIF",
                            toolDescription, false);
@@ -309,7 +320,7 @@
      skipFile =
           new StringArgument("skipfile", 'K', "skipFile", false, false,
           new StringArgument("skipfile", null, "skipFile", false, false,
                              true, "{skipFile}", null, null,
                              INFO_LDIFIMPORT_DESCRIPTION_SKIP_FILE.get());
      argParser.addArgument(skipFile);
@@ -354,7 +365,7 @@
      argParser.addArgument(isEncrypted);
      quietMode = new BooleanArgument("quietmode", 'q', "quiet",
      quietMode = new BooleanArgument("quietmode", null, "quiet",
                                      INFO_LDIFIMPORT_DESCRIPTION_QUIET.get());
      argParser.addArgument(quietMode);
@@ -430,6 +441,191 @@
      return 1;
    }
    return process(argParser, initializeServer, out, err);
  }
  /**
   * {@inheritDoc}
   */
  public void addTaskAttributes(List<RawAttribute> attributes)
  {
    //
    // Required attributes
    //
    ArrayList<ASN1OctetString> values;
    List<String> fileList = ldifFiles.getValues();
    if (fileList != null && fileList.size() > 0) {
      values = new ArrayList<ASN1OctetString>(fileList.size());
      for (String file : fileList) {
        values.add(new ASN1OctetString(file));
      }
      attributes.add(new LDAPAttribute(ATTR_IMPORT_LDIF_FILE, values));
    }
    //
    // Optional attributes
    //
    if (append.getValue() != null &&
            !append.getValue().equals(append.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(append.getValue()));
      attributes.add(new LDAPAttribute(ATTR_IMPORT_APPEND, values));
    }
    if (replaceExisting.getValue() != null &&
            !replaceExisting.getValue().equals(
                    replaceExisting.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(replaceExisting.getValue()));
      attributes.add(new LDAPAttribute(ATTR_IMPORT_REPLACE_EXISTING, values));
    }
    if (backendID.getValue() != null &&
            !backendID.getValue().equals(
                    backendID.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(backendID.getValue()));
      attributes.add(new LDAPAttribute(ATTR_IMPORT_BACKEND_ID, values));
    }
    List<String> includeAttributes = includeAttributeStrings.getValues();
    if (includeAttributes != null && includeAttributes.size() > 0) {
      values = new ArrayList<ASN1OctetString>(includeAttributes.size());
      for (String includeAttribute : includeAttributes) {
        values.add(new ASN1OctetString(includeAttribute));
      }
      attributes.add(new LDAPAttribute(ATTR_IMPORT_INCLUDE_ATTRIBUTE, values));
    }
    List<String> excludeAttributes = excludeAttributeStrings.getValues();
    if (excludeAttributes != null && excludeAttributes.size() > 0) {
      values = new ArrayList<ASN1OctetString>(excludeAttributes.size());
      for (String excludeAttribute : excludeAttributes) {
        values.add(new ASN1OctetString(excludeAttribute));
      }
      attributes.add(new LDAPAttribute(ATTR_IMPORT_EXCLUDE_ATTRIBUTE, values));
    }
    List<String> includeFilters = includeFilterStrings.getValues();
    if (includeFilters != null && includeFilters.size() > 0) {
      values = new ArrayList<ASN1OctetString>(includeFilters.size());
      for (String includeFilter : includeFilters) {
        values.add(new ASN1OctetString(includeFilter));
      }
      attributes.add(new LDAPAttribute(ATTR_IMPORT_INCLUDE_FILTER, values));
    }
    List<String> excludeFilters = excludeFilterStrings.getValues();
    if (excludeFilters != null && excludeFilters.size() > 0) {
      values = new ArrayList<ASN1OctetString>(excludeFilters.size());
      for (String excludeFilter : excludeFilters) {
        values.add(new ASN1OctetString(excludeFilter));
      }
      attributes.add(new LDAPAttribute(ATTR_IMPORT_EXCLUDE_FILTER, values));
    }
    List<String> includeBranches = includeBranchStrings.getValues();
    if (includeBranches != null && includeBranches.size() > 0) {
      values = new ArrayList<ASN1OctetString>(includeBranches.size());
      for (String includeBranche : includeBranches) {
        values.add(new ASN1OctetString(includeBranche));
      }
      attributes.add(new LDAPAttribute(ATTR_IMPORT_INCLUDE_BRANCH, values));
    }
    List<String> excludeBranches = excludeBranchStrings.getValues();
    if (excludeBranches != null && excludeBranches.size() > 0) {
      values = new ArrayList<ASN1OctetString>(excludeBranches.size());
      for (String excludeBranch : excludeBranches) {
        values.add(new ASN1OctetString(excludeBranch));
      }
      attributes.add(new LDAPAttribute(ATTR_IMPORT_EXCLUDE_BRANCH, values));
    }
    if (rejectFile.getValue() != null &&
            !rejectFile.getValue().equals(
                    rejectFile.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(rejectFile.getValue()));
      attributes.add(new LDAPAttribute(ATTR_IMPORT_REJECT_FILE, values));
    }
    if (skipFile.getValue() != null &&
            !skipFile.getValue().equals(
                    skipFile.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(skipFile.getValue()));
      attributes.add(new LDAPAttribute(ATTR_IMPORT_SKIP_FILE, values));
    }
    if (overwrite.getValue() != null &&
            !overwrite.getValue().equals(
                    overwrite.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(overwrite.getValue()));
      attributes.add(new LDAPAttribute(ATTR_IMPORT_OVERWRITE, values));
    }
    if (skipSchemaValidation.getValue() != null &&
            !skipSchemaValidation.getValue().equals(
                    skipSchemaValidation.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(skipSchemaValidation.getValue()));
      attributes.add(
              new LDAPAttribute(ATTR_IMPORT_SKIP_SCHEMA_VALIDATION, values));
    }
    if (isCompressed.getValue() != null &&
            !isCompressed.getValue().equals(
                    isCompressed.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(isCompressed.getValue()));
      attributes.add(
              new LDAPAttribute(ATTR_IMPORT_IS_COMPRESSED, values));
    }
    if (isEncrypted.getValue() != null &&
            !isEncrypted.getValue().equals(
                    isEncrypted.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(isEncrypted.getValue()));
      attributes.add(
              new LDAPAttribute(ATTR_IMPORT_IS_ENCRYPTED, values));
    }
    if (clearBackend.getValue() != null &&
            !clearBackend.getValue().equals(
                    clearBackend.getDefaultValue())) {
      values = new ArrayList<ASN1OctetString>(1);
      values.add(new ASN1OctetString(clearBackend.getValue()));
      attributes.add(
              new LDAPAttribute(ATTR_IMPORT_CLEAR_BACKEND, values));
    }
  }
  /**
   * {@inheritDoc}
   */
  public String getTaskObjectclass() {
    return "ds-task-import";
  }
  /**
   * {@inheritDoc}
   */
  public Class getTaskClass() {
    return ImportTask.class;
  }
  /**
   * {@inheritDoc}
   */
  protected int processLocal(boolean initializeServer,
                           PrintStream out,
                           PrintStream err) {
    // Perform the initial bootstrap of the Directory Server and process the
    // configuration.
    DirectoryServer directoryServer = DirectoryServer.getInstance();
opends/src/server/org/opends/server/tools/tasks/TaskScheduleInformation.java
New file
@@ -0,0 +1,65 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.tools.tasks;
import org.opends.server.types.RawAttribute;
import java.util.List;
/**
 * Interface for tools that are capable of scheduling a task remotely
 * through the task backend.
 *
 * @see TaskSchedulingClient
 */
public interface TaskScheduleInformation {
  /**
   * Adds utility specific attributes to <code>attributes</code> for
   * population of the entry that is added to the task backend.
   *
   * @param attributes that will be added to the task backend
   */
  void addTaskAttributes(List<RawAttribute> attributes);
  /**
   * Gets the objectclass used to represent scheduled instances of this
   * utility in the task backend.
   *
   * @return String representation of this utilities objectclass
   */
  String getTaskObjectclass();
  /**
   * Gets the Class that implements the utility to execute.
   *
   * @return class of the tasks implementation
   */
  Class getTaskClass();
}
opends/src/server/org/opends/server/tools/tasks/TaskSchedulingClient.java
New file
@@ -0,0 +1,208 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.tools.tasks;
import org.opends.server.types.LDAPException;
import org.opends.server.types.RawAttribute;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.asn1.ASN1Exception;
import org.opends.server.protocols.ldap.LDAPControl;
import org.opends.server.protocols.ldap.AddRequestProtocolOp;
import org.opends.server.protocols.ldap.LDAPMessage;
import org.opends.server.protocols.ldap.LDAPResultCode;
import org.opends.server.protocols.ldap.LDAPConstants;
import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp;
import org.opends.server.protocols.ldap.AddResponseProtocolOp;
import org.opends.server.protocols.ldap.LDAPAttribute;
import static org.opends.server.config.ConfigConstants.ATTR_TASK_ID;
import static org.opends.server.config.ConfigConstants.SCHEDULED_TASK_BASE_RDN;
import static org.opends.server.config.ConfigConstants.DN_TASK_ROOT;
import static org.opends.server.config.ConfigConstants.ATTR_OBJECTCLASS;
import static org.opends.server.config.ConfigConstants.ATTR_TASK_CLASS;
import org.opends.server.config.ConfigConstants;
import static org.opends.server.util.ServerConstants.MAX_LINE_WIDTH;
import static org.opends.server.util.StaticUtils.wrapText;
import org.opends.server.tools.LDAPConnection;
import org.opends.server.tools.LDAPReader;
import org.opends.server.tools.LDAPWriter;
import org.opends.messages.Message;
import static org.opends.messages.ToolMessages.*;
import java.util.UUID;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.io.IOException;
import java.io.PrintStream;
/**
 * Helper class for interacting with the task backend on behalf of utilities
 * that are capable of being scheduled.
 */
public class TaskSchedulingClient {
  /**
   * Connection through which task scheduling will take place.
   */
  protected LDAPConnection connection;
  /**
   * Creates a new TaskClient for interacting with the task backend remotely.
   * @param conn for accessing the task backend
   */
  public TaskSchedulingClient(LDAPConnection conn) {
    this.connection = conn;
  }
  /**
   * Schedule a task for execution by writing an entry to the task backend.
   *
   * @param information to be scheduled
   * @param out stream for writing error messages
   * @param err stream for writing error messages
   * @return int representing an LDAP return code
   */
  public synchronized int schedule(TaskScheduleInformation information,
                                   PrintStream out, PrintStream err) {
    // Attempt to connect and authenticate to the Directory Server.
    AtomicInteger nextMessageID = new AtomicInteger(1);
    LDAPReader reader = connection.getLDAPReader();
    LDAPWriter writer = connection.getLDAPWriter();
    // Construct the add request to send to the server.
    String taskID = UUID.randomUUID().toString();
    ASN1OctetString entryDN =
         new ASN1OctetString(ATTR_TASK_ID + "=" + taskID + "," +
                             SCHEDULED_TASK_BASE_RDN + "," + DN_TASK_ROOT);
    ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>();
    ArrayList<RawAttribute> attributes = new ArrayList<RawAttribute>();
    ArrayList<ASN1OctetString> ocValues = new ArrayList<ASN1OctetString>(3);
    ocValues.add(new ASN1OctetString("top"));
    ocValues.add(new ASN1OctetString(ConfigConstants.OC_TASK));
    ocValues.add(new ASN1OctetString(information.getTaskObjectclass()));
    attributes.add(new LDAPAttribute(ATTR_OBJECTCLASS, ocValues));
    ArrayList<ASN1OctetString> taskIDValues = new ArrayList<ASN1OctetString>(1);
    taskIDValues.add(new ASN1OctetString(taskID));
    attributes.add(new LDAPAttribute(ATTR_TASK_ID, taskIDValues));
    ArrayList<ASN1OctetString> classValues = new ArrayList<ASN1OctetString>(1);
    classValues.add(new ASN1OctetString(information.getTaskClass().getName()));
    attributes.add(new LDAPAttribute(ATTR_TASK_CLASS, classValues));
    information.addTaskAttributes(attributes);
    AddRequestProtocolOp addRequest = new AddRequestProtocolOp(entryDN,
                                                               attributes);
    LDAPMessage requestMessage =
         new LDAPMessage(nextMessageID.getAndIncrement(), addRequest, controls);
    // Send the request to the server and read the response.
    LDAPMessage responseMessage;
    try
    {
      writer.writeMessage(requestMessage);
      responseMessage = reader.readMessage();
      if (responseMessage == null)
      {
        Message message = ERR_TASK_CLIENT_UNEXPECTED_CONNECTION_CLOSURE.get();
        err.println(wrapText(message, MAX_LINE_WIDTH));
        return LDAPResultCode.CLIENT_SIDE_SERVER_DOWN;
      }
    }
    catch (IOException ioe)
    {
      Message message = ERR_TASK_CLIENT_IO_ERROR.get(String.valueOf(ioe));
      err.println(wrapText(message, MAX_LINE_WIDTH));
      return LDAPResultCode.CLIENT_SIDE_SERVER_DOWN;
    }
    catch (ASN1Exception ae)
    {
      Message message = ERR_TASK_CLIENT_DECODE_ERROR.get(ae.getMessage());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      return LDAPResultCode.CLIENT_SIDE_DECODING_ERROR;
    }
    catch (LDAPException le)
    {
      Message message = ERR_TASK_CLIENT_DECODE_ERROR.get(le.getMessage());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      return LDAPResultCode.CLIENT_SIDE_DECODING_ERROR;
    }
    if (responseMessage.getProtocolOpType() !=
        LDAPConstants.OP_TYPE_ADD_RESPONSE)
    {
      if (responseMessage.getProtocolOpType() ==
          LDAPConstants.OP_TYPE_EXTENDED_RESPONSE)
      {
        // It's possible that this is a notice of disconnection, which we can
        // probably interpret as a "success" in this case.
        ExtendedResponseProtocolOp extendedResponse =
             responseMessage.getExtendedResponseProtocolOp();
        String responseOID = extendedResponse.getOID();
        if ((responseOID != null) &&
            (responseOID.equals(LDAPConstants.OID_NOTICE_OF_DISCONNECTION)))
        {
          Message message = extendedResponse.getErrorMessage();
          if (message != null)
          {
            err.println(wrapText(message, MAX_LINE_WIDTH));
          }
          return extendedResponse.getResultCode();
        }
      }
      Message message = ERR_TASK_CLIENT_INVALID_RESPONSE_TYPE.get(
              responseMessage.getProtocolOpName());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      return LDAPResultCode.CLIENT_SIDE_LOCAL_ERROR;
    }
    AddResponseProtocolOp addResponse =
         responseMessage.getAddResponseProtocolOp();
    Message errorMessage = addResponse.getErrorMessage();
    if (errorMessage != null)
    {
      err.println(wrapText(errorMessage, MAX_LINE_WIDTH));
    }
    else
    {
      out.println(wrapText(INFO_TASK_CLIENT_TASK_SCHEDULED.get(taskID),
                           MAX_LINE_WIDTH));
    }
    return addResponse.getResultCode();
  }
}
opends/src/server/org/opends/server/tools/tasks/TaskTool.java
New file
@@ -0,0 +1,101 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.tools.tasks;
import org.opends.server.util.args.LDAPConnectionArgumentParser;
import org.opends.server.util.args.ArgumentException;
import static org.opends.server.util.StaticUtils.wrapText;
import static org.opends.server.util.ServerConstants.MAX_LINE_WIDTH;
import org.opends.server.protocols.ldap.LDAPResultCode;
import org.opends.server.tools.LDAPConnection;
import org.opends.server.tools.LDAPConnectionException;
import org.opends.messages.Message;
import static org.opends.messages.ToolMessages.ERR_LDAP_CONN_CANNOT_CONNECT;
import java.io.PrintStream;
/**
 * Base class for tools that are capable of operating either by running
 * local within this JVM or by scheduling a task to perform the same
 * action running within the directory server through the tasks interface.
 */
public abstract class TaskTool implements TaskScheduleInformation {
  /**
   * Either invokes initiates this tool's local action or schedule this
   * tool using the tasks interface based on user input.
   *
   * @param argParser used to parse user arguments
   * @param initializeServer indicates whether or not to initialize the
   *        directory server in the case of a local action
   * @param out stream to write messages
   * @param err stream to write messages
   * @return int indicating the result of this action
   */
  protected int process(LDAPConnectionArgumentParser argParser,
                        boolean initializeServer,
                        PrintStream out, PrintStream err) {
    int ret;
    if (argParser.isLdapOperation())
    {
      try {
        LDAPConnection conn = argParser.connect(out, err);
        TaskSchedulingClient tc = new TaskSchedulingClient(conn);
        ret = tc.schedule(this, out, err);
      } catch (LDAPConnectionException e) {
        Message message = ERR_LDAP_CONN_CANNOT_CONNECT.get(e.getMessage());
        err.println(wrapText(message, MAX_LINE_WIDTH));
        ret = LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR;
      } catch (ArgumentException e) {
        Message message = e.getMessageObject();
        err.println(wrapText(message, MAX_LINE_WIDTH));
        ret = LDAPResultCode.CLIENT_SIDE_PARAM_ERROR;
      }
    }
    else
    {
      ret = processLocal(initializeServer, out, err);
    }
    return ret;
  }
  /**
   * Called when this utility should perform its actions locally in this
   * JVM.
   *
   * @param initializeServer indicates whether or not to initialize the
   *        directory server in the case of a local action
   * @param out stream to write messages
   * @param err stream to write messages
   * @return int indicating the result of this action
   */
  abstract protected int processLocal(boolean initializeServer,
                                      PrintStream out,
                                      PrintStream err);
}
opends/src/server/org/opends/server/tools/tasks/package-info.java
New file
@@ -0,0 +1,37 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
/**
 * This package contains classes that support client tool interaction with the
 * tasks backend.
 */
@org.opends.server.types.PublicAPI(
     stability=org.opends.server.types.StabilityLevel.PRIVATE)
package org.opends.server.tools.tasks;
opends/src/server/org/opends/server/util/args/LDAPConnectionArgumentParser.java
New file
@@ -0,0 +1,450 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.util.args;
import org.opends.messages.Message;
import static org.opends.messages.ToolMessages.*;
import org.opends.server.tools.LDAPConnection;
import org.opends.server.tools.LDAPConnectionOptions;
import org.opends.server.tools.SSLConnectionFactory;
import org.opends.server.tools.SSLConnectionException;
import org.opends.server.tools.LDAPConnectionException;
import static org.opends.server.tools.ToolConstants.*;
import static org.opends.server.util.ServerConstants.MAX_LINE_WIDTH;
import static org.opends.server.util.StaticUtils.wrapText;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
import java.io.PrintStream;
/**
 * Creates an argument parser pre-populated with arguments for specifying
 * information for openning and LDAPConnection an LDAP connection.
 */
public class LDAPConnectionArgumentParser extends ArgumentParser {
  /** Argument indicating whether all SSL certs will be trusted. */
  protected BooleanArgument   trustAll;
  /** Argument indicating whether or not to use SSL. */
  protected BooleanArgument   useSSL;
  /** Argument indicating whether or not to use StartTLS. */
  protected BooleanArgument   useStartTLS;
  /** Argument indicating location of a bind password file. */
  protected FileBasedArgument bindPWFile;
  /** Argument indicating the location of the keystore password file. */
  protected FileBasedArgument keyStorePWFile;
  /** Argument indicating the location of the trust store password file. */
  protected FileBasedArgument trustStorePWFile;
  /** Argument indicating the port of the directory server. */
  protected IntegerArgument   port;
  /** Argument indicating the DN of the user with which to bind. */
  protected StringArgument    bindDN;
  /** Argument indicating the password of the user with which to bind. */
  protected StringArgument    bindPW;
  /** Argument indicating the nickname of the certificate to use. */
  protected StringArgument    certNickname;
  /** Argument indicating the hostname of the directory server. */
  protected StringArgument    host;
  /** Argument indicating the location of the keystore file. */
  protected StringArgument    keyStoreFile;
  /** Argument indicating the password fo the keystore. */
  protected StringArgument    keyStorePW;
  /** Argument indicating a SASL option. */
  protected StringArgument    saslOption;
  /** Argument indicating the location of the trust store file. */
  protected StringArgument    trustStoreFile;
  /** Argument indicating the password of the trust store. */
  protected StringArgument    trustStorePW;
  /**
   * {@inheritDoc}
   */
  public LDAPConnectionArgumentParser(String mainClassName,
                                      Message toolDescription,
                                      boolean longArgumentsCaseSensitive) {
    super(mainClassName, toolDescription, longArgumentsCaseSensitive);
    addLdapConnectionArguments();
  }
  /**
   * {@inheritDoc}
   */
  public LDAPConnectionArgumentParser(String mainClassName,
                                      Message toolDescription,
                                      boolean longArgumentsCaseSensitive,
                                      boolean allowsTrailingArguments,
                                      int minTrailingArguments,
                                      int maxTrailingArguments,
                                      String trailingArgsDisplayName) {
    super(mainClassName, toolDescription, longArgumentsCaseSensitive,
            allowsTrailingArguments, minTrailingArguments, maxTrailingArguments,
            trailingArgsDisplayName);
    addLdapConnectionArguments();
  }
  /**
   * Indicates whether or not the user has indicated that they would like
   * to perform a remote operation based on the arguments.
   *
   * @return true if the user wants to perform a remote operation;
   *         false otherwise
   */
  public boolean isLdapOperation() {
    // This may not be ideal in all cases.  We might want to assume no
    // host means 'localhost'.  However we would still need some way to
    // tell whether the user intends this invocation to be remote.
    return host.isPresent();
  }
  /**
   * Creates a new LDAPConnection and invokes a connect operation using
   * information provided in the parsed set of arguments that were provided
   * by the user.
   *
   * @param out stream to write messages
   * @param err stream to write messages
   * @return LDAPConnection created by this class from parsed arguments
   * @throws LDAPConnectionException if there was a problem connecting
   *         to the server indicated by the input arguments
   * @throws ArgumentException if there was a problem processing the input
   *         arguments
   */
  public LDAPConnection connect(PrintStream out, PrintStream err)
          throws LDAPConnectionException, ArgumentException
  {
    // If both a bind password and bind password file were provided, then return
    // an error.
    if (bindPW.isPresent() && bindPWFile.isPresent())
    {
      Message message = ERR_LDAP_CONN_MUTUALLY_EXCLUSIVE_ARGUMENTS.get(
              bindPW.getLongIdentifier(),
              bindPWFile.getLongIdentifier());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      throw new ArgumentException(message);
    }
    // If both a key store password and key store password file were provided,
    // then return an error.
    if (keyStorePW.isPresent() && keyStorePWFile.isPresent())
    {
      Message message = ERR_LDAP_CONN_MUTUALLY_EXCLUSIVE_ARGUMENTS.get(
              keyStorePW.getLongIdentifier(),
              keyStorePWFile.getLongIdentifier());
      throw new ArgumentException(message);
    }
    // If both a trust store password and trust store password file were
    // provided, then return an error.
    if (trustStorePW.isPresent() && trustStorePWFile.isPresent())
    {
      Message message = ERR_LDAP_CONN_MUTUALLY_EXCLUSIVE_ARGUMENTS.get(
              trustStorePW.getLongIdentifier(),
              trustStorePWFile.getLongIdentifier());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      throw new ArgumentException(message);
    }
    // Create the LDAP connection options object, which will be used to
    // customize the way that we connect to the server and specify a set of
    // basic defaults.
    LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions();
    connectionOptions.setVersionNumber(3);
    // See if we should use SSL or StartTLS when establishing the connection.
    // If so, then make sure only one of them was specified.
    if (useSSL.isPresent())
    {
      if (useStartTLS.isPresent())
      {
        Message message = ERR_LDAP_CONN_MUTUALLY_EXCLUSIVE_ARGUMENTS.get(
                useSSL.getLongIdentifier(),
                useStartTLS.getLongIdentifier());
        err.println(wrapText(message, MAX_LINE_WIDTH));
        throw new ArgumentException(message);
      }
      else
      {
        connectionOptions.setUseSSL(true);
      }
    }
    else if (useStartTLS.isPresent())
    {
      connectionOptions.setStartTLS(true);
    }
    // If we should blindly trust any certificate, then install the appropriate
    // SSL connection factory.
    if (useSSL.isPresent() || useStartTLS.isPresent())
    {
      try
      {
        String clientAlias;
        if (certNickname.isPresent())
        {
          clientAlias = certNickname.getValue();
        }
        else
        {
          clientAlias = null;
        }
        SSLConnectionFactory sslConnectionFactory = new SSLConnectionFactory();
        sslConnectionFactory.init(trustAll.isPresent(), keyStoreFile.getValue(),
                                  keyStorePW.getValue(), clientAlias,
                                  trustStoreFile.getValue(),
                                  trustStorePW.getValue());
        connectionOptions.setSSLConnectionFactory(sslConnectionFactory);
      }
      catch (SSLConnectionException sce)
      {
        Message message =
                ERR_LDAP_CONN_CANNOT_INITIALIZE_SSL.get(sce.getMessage());
        err.println(wrapText(message, MAX_LINE_WIDTH));
      }
    }
    // If one or more SASL options were provided, then make sure that one of
    // them was "mech" and specified a valid SASL mechanism.
    if (saslOption.isPresent())
    {
      String             mechanism = null;
      LinkedList<String> options   = new LinkedList<String>();
      for (String s : saslOption.getValues())
      {
        int equalPos = s.indexOf('=');
        if (equalPos <= 0)
        {
          Message message = ERR_LDAP_CONN_CANNOT_PARSE_SASL_OPTION.get(s);
          err.println(wrapText(message, MAX_LINE_WIDTH));
          throw new ArgumentException(message);
        }
        else
        {
          String name  = s.substring(0, equalPos);
          if (name.equalsIgnoreCase("mech"))
          {
            mechanism = s;
          }
          else
          {
            options.add(s);
          }
        }
      }
      if (mechanism == null)
      {
        Message message = ERR_LDAP_CONN_NO_SASL_MECHANISM.get();
        err.println(wrapText(message, MAX_LINE_WIDTH));
        throw new ArgumentException(message);
      }
      connectionOptions.setSASLMechanism(mechanism);
      for (String option : options)
      {
        connectionOptions.addSASLProperty(option);
      }
    }
    // Attempt to connect and authenticate to the Directory Server.
    AtomicInteger nextMessageID = new AtomicInteger(1);
    LDAPConnection connection = new LDAPConnection(
            host.getValue(), port.getIntValue(),
            connectionOptions, out, err);
    connection.connectToHost(bindDN.getValue(), bindPW.getValue(),
                             nextMessageID);
    return connection;
  }
  private void addLdapConnectionArguments() {
    try
    {
      host = new StringArgument(
              "host", OPTION_SHORT_HOST,
              OPTION_LONG_HOST, false, false, true,
              OPTION_VALUE_HOST, "127.0.0.1", null,
              INFO_LDAP_CONN_DESCRIPTION_HOST.get());
      addArgument(host);
      port = new IntegerArgument(
              "port", OPTION_SHORT_PORT,
              OPTION_LONG_PORT, false, false, true,
              OPTION_VALUE_PORT, 389, null, true, 1,
              true, 65535, INFO_LDAP_CONN_DESCRIPTION_PORT.get());
      addArgument(port);
      useSSL = new BooleanArgument(
              "usessl", OPTION_SHORT_USE_SSL,
              OPTION_LONG_USE_SSL,
              INFO_LDAP_CONN_DESCRIPTION_USESSL.get());
      addArgument(useSSL);
      useStartTLS = new BooleanArgument(
              "usestarttls", OPTION_SHORT_START_TLS,
              OPTION_LONG_START_TLS,
              INFO_LDAP_CONN_DESCRIPTION_USESTARTTLS.get());
      addArgument(useStartTLS);
      bindDN = new StringArgument(
              "binddn", OPTION_SHORT_BINDDN,
              OPTION_LONG_BINDDN, false, false, true,
              OPTION_VALUE_BINDDN, null, null,
              INFO_LDAP_CONN_DESCRIPTION_BINDDN.get());
      addArgument(bindDN);
      bindPW = new StringArgument(
              "bindpw", OPTION_SHORT_BINDPWD,
              OPTION_LONG_BINDPWD, false, false,
              true,
              OPTION_VALUE_BINDPWD, null, null,
              INFO_LDAP_CONN_DESCRIPTION_BINDPW.get());
      addArgument(bindPW);
      bindPWFile = new FileBasedArgument(
              "bindpwfile",
              OPTION_SHORT_BINDPWD_FILE,
              OPTION_LONG_BINDPWD_FILE,
              false, false,
              OPTION_VALUE_BINDPWD_FILE,
              null, null,
              INFO_LDAP_CONN_DESCRIPTION_BINDPWFILE.get());
      addArgument(bindPWFile);
      saslOption = new StringArgument(
              "sasloption", OPTION_SHORT_SASLOPTION,
              OPTION_LONG_SASLOPTION, false,
              true, true,
              OPTION_VALUE_SASLOPTION, null, null,
              INFO_LDAP_CONN_DESCRIPTION_SASLOPTIONS.get());
      addArgument(saslOption);
      trustAll = new BooleanArgument(
              "trustall", 'X', "trustAll",
              INFO_LDAP_CONN_DESCRIPTION_TRUST_ALL.get());
      addArgument(trustAll);
      keyStoreFile = new StringArgument(
              "keystorefile",
              OPTION_SHORT_KEYSTOREPATH,
              OPTION_LONG_KEYSTOREPATH,
              false, false, true,
              OPTION_VALUE_KEYSTOREPATH,
              null, null,
              INFO_LDAP_CONN_DESCRIPTION_KSFILE.get());
      addArgument(keyStoreFile);
      keyStorePW = new StringArgument(
              "keystorepw", OPTION_SHORT_KEYSTORE_PWD,
              OPTION_LONG_KEYSTORE_PWD,
              false, false, true,
              OPTION_VALUE_KEYSTORE_PWD,
              null, null,
              INFO_LDAP_CONN_DESCRIPTION_KSPW.get());
      addArgument(keyStorePW);
      keyStorePWFile = new FileBasedArgument(
              "keystorepwfile",
              OPTION_SHORT_KEYSTORE_PWD_FILE,
              OPTION_LONG_KEYSTORE_PWD_FILE,
              false, false,
              OPTION_VALUE_KEYSTORE_PWD_FILE,
              null, null,
              INFO_LDAP_CONN_DESCRIPTION_KSPWFILE.get());
      addArgument(keyStorePWFile);
      certNickname = new StringArgument(
              "certnickname", 'N', "certNickname",
              false, false, true, "{nickname}", null,
              null, INFO_DESCRIPTION_CERT_NICKNAME.get());
      addArgument(certNickname);
      trustStoreFile = new StringArgument(
              "truststorefile",
              OPTION_SHORT_TRUSTSTOREPATH,
              OPTION_LONG_TRUSTSTOREPATH,
              false, false, true,
              OPTION_VALUE_TRUSTSTOREPATH,
              null, null,
              INFO_LDAP_CONN_DESCRIPTION_TSFILE.get());
      addArgument(trustStoreFile);
      trustStorePW = new StringArgument(
              "truststorepw", 'T',
              OPTION_LONG_TRUSTSTORE_PWD,
              false, false,
              true, OPTION_VALUE_TRUSTSTORE_PWD, null,
              null, INFO_LDAP_CONN_DESCRIPTION_TSPW.get());
      addArgument(trustStorePW);
      trustStorePWFile = new FileBasedArgument(
              "truststorepwfile",
              OPTION_SHORT_TRUSTSTORE_PWD_FILE,
              OPTION_LONG_TRUSTSTORE_PWD_FILE,
              false, false,
              OPTION_VALUE_TRUSTSTORE_PWD_FILE, null, null,
              INFO_LDAP_CONN_DESCRIPTION_TSPWFILE.get());
      addArgument(trustStorePWFile);
    }
    catch (ArgumentException ae)
    {
      // Should never happen
    }
  }
}