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

neil_a_wilson
13.19.2006 e1198d87e7a870b462ae4941b0c5b6420230bd0a
Add a new list-backends tool that may be used to list the backends in the
server along with their base DNs, as well as list all base DNs for a given
backend ID or list the backend ID for a given base DN.

Reviewed By: David Ely
OpenDS Issue Number: 44
4 files added
1 files modified
1427 ■■■■■ changed files
opends/resource/bin/list-backends 37 ●●●●● patch | view | raw | blame | history
opends/resource/bin/list-backends.bat 33 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/ToolMessages.java 318 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/ListBackends.java 641 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/ListBackendsTestCase.java 398 ●●●●● patch | view | raw | blame | history
opends/resource/bin/list-backends
New file
@@ -0,0 +1,37 @@
#!/bin/sh
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License, Version 1.0 only
# (the "License").  You may not use this file except in compliance
# with the License.
#
# You can obtain a copy of the license at
# trunk/opends/resource/legal-notices/OpenDS.LICENSE
# or https://OpenDS.dev.java.net/OpenDS.LICENSE.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at
# trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
# add the following below this CDDL HEADER, with the fields enclosed
# by brackets "[]" replaced with your own identifying * information:
#      Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
#      Portions Copyright 2006 Sun Microsystems, Inc.
# This script may be used to perform a restore of a Directory Server backend.
OPENDS_INVOKE_CLASS="org.opends.server.tools.ListBackends"
export OPENDS_INVOKE_CLASS
SCRIPT_NAME_ARG="-Dorg.opends.server.scriptName=list-backends"
export SCRIPT_NAME_ARG
SCRIPT_DIR=`dirname "${0}"`
"${SCRIPT_DIR}/_server-script.sh" "${@}"
opends/resource/bin/list-backends.bat
New file
@@ -0,0 +1,33 @@
@echo off
rem CDDL HEADER START
rem
rem The contents of this file are subject to the terms of the
rem Common Development and Distribution License, Version 1.0 only
rem (the "License").  You may not use this file except in compliance
rem with the License.
rem
rem You can obtain a copy of the license at
rem trunk/opends/resource/legal-notices/OpenDS.LICENSE
rem or https://OpenDS.dev.java.net/OpenDS.LICENSE.
rem See the License for the specific language governing permissions
rem and limitations under the License.
rem
rem When distributing Covered Code, include this CDDL HEADER in each
rem file and include the License file at
rem trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
rem add the following below this CDDL HEADER, with the fields enclosed
rem by brackets "[]" replaced with your own identifying * information:
rem      Portions Copyright [yyyy] [name of copyright owner]
rem
rem CDDL HEADER END
rem
rem
rem      Portions Copyright 2006 Sun Microsystems, Inc.
setlocal
set OPENDS_INVOKE_CLASS="org.opends.server.tools.ListBackends"
set SCRIPT_NAME_ARG="-Dorg.opends.server.scriptName=list-backends"
call "%~dP0\_server-script.bat" %*
opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -7060,6 +7060,249 @@
  /**
   * The message ID for the message that will be used as the description for the
   * list-backends tool.  This does not take any arguments.
   */
  public static final int MSGID_LISTBACKENDS_TOOL_DESCRIPTION =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 723;
  /**
   * The message ID for the message that will be used as the description of the
   * configClass argument.  This does not take any arguments.
   */
  public static final int MSGID_LISTBACKENDS_DESCRIPTION_CONFIG_CLASS =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 724;
  /**
   * The message ID for the message that will be used as the description of the
   * configFile argument.  This does not take any arguments.
   */
  public static final int MSGID_LISTBACKENDS_DESCRIPTION_CONFIG_FILE =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 725;
  /**
   * The message ID for the message that will be used as the description of the
   * backendID argument.  This does not take any arguments.
   */
  public static final int MSGID_LISTBACKENDS_DESCRIPTION_BACKEND_ID =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 726;
  /**
   * The message ID for the message that will be used as the description of the
   * baseDN argument.  This does not take any arguments.
   */
  public static final int MSGID_LISTBACKENDS_DESCRIPTION_BASE_DN =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 727;
  /**
   * The message ID for the message that will be used as the description of the
   * help argument.  This does not take any arguments.
   */
  public static final int MSGID_LISTBACKENDS_DESCRIPTION_HELP =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 728;
  /**
   * The message ID for the message that will be used if an error occurs while
   * attempting to initialize the command-line argument parser.  This takes a
   * single argument, which is a message explaining the problem that occurred.
   */
  public static final int MSGID_LISTBACKENDS_CANNOT_INITIALIZE_ARGS =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 729;
  /**
   * The message ID for the message that will be used if an error occurs while
   * parsing the provided command-line arguments.  This takes a single argument,
   * which is a message explaining the problem that occurred.
   */
  public static final int MSGID_LISTBACKENDS_ERROR_PARSING_ARGS =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 730;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to bootstrap the Directory Server.  This takes a single argument,
   * which is a string representation of the exception that was caught.
   */
  public static final int MSGID_LISTBACKENDS_SERVER_BOOTSTRAP_ERROR =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 731;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying load the Directory Server configuration.  This takes a single
   * argument which is a message with information about the problem that
   * occurred.
   */
  public static final int MSGID_LISTBACKENDS_CANNOT_LOAD_CONFIG =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 732;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to load the Directory Server schema.  This takes a single argument,
   * which is a message with information about the problem that occurred.
   */
  public static final int MSGID_LISTBACKENDS_CANNOT_LOAD_SCHEMA =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 733;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to read backend information from the configuration.  This takes a
   * single argument, which is a message explaining the problem that occurred.
   */
  public static final int MSGID_LISTBACKENDS_CANNOT_GET_BACKENDS =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 734;
  /**
   * The message ID for the message that will be used if a provided string can't
   * be parsed as a DN.  This takes two arguments, which are the provided string
   * and a message explaining the problem that occurred.
   */
  public static final int MSGID_LISTBACKENDS_INVALID_DN =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 735;
  /**
   * The message ID for the message that will be used to indicate that a
   * provided DN was not a base DN for any backend.  This takes a single
   * argument, which is the provided DN.
   */
  public static final int MSGID_LISTBACKENDS_NOT_BASE_DN =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 736;
  /**
   * The message ID for the message that will be used to indicate that a
   * provided DN was not appropriate for any backend.  This takes a single
   * argument, which is the provided DN.
   */
  public static final int MSGID_LISTBACKENDS_NO_BACKEND_FOR_DN =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 737;
  /**
   * The message ID for the message that will be used to indicate that a
   * provided DN was below the base DN for a backend in the server.  This takes
   * three arguments, which are the provided DN, the base DN for the
   * corresponding backend, and the backend ID.
   */
  public static final int MSGID_LISTBACKENDS_DN_BELOW_BASE =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 738;
  /**
   * The message ID for the message that will be used to indicate that a
   * provided DN a base DN for a backend.  This takes two arguments, which are
   * the provided DN and the corresponding backend ID.
   */
  public static final int MSGID_LISTBACKENDS_BASE_FOR_ID =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 739;
  /**
   * The message ID for the message that will be used as the label for the
   * backend ID column header.
   */
  public static final int MSGID_LISTBACKENDS_LABEL_BACKEND_ID =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 740;
  /**
   * The message ID for the message that will be used as the label for the base
   * DN column header.
   */
  public static final int MSGID_LISTBACKENDS_LABEL_BASE_DN =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 741;
  /**
   * The message ID for the message that will be used if the provided backend ID
   * is not associated with any backend configured in the server.  This takes a
   * single argument, which is the provided backend ID.
   */
  public static final int MSGID_LISTBACKENDS_NO_SUCH_BACKEND =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 742;
  /**
   * The message ID for the message that will be used if none of the provided
   * backend IDs are valid.  This does not take any arguments.
   */
  public static final int MSGID_LISTBACKENDS_NO_VALID_BACKENDS =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 743;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to decode the base DN for backend configuration entries.  This takes
   * two arguments, which are the base DN and a message explaining the problem
   * that occurred.
   */
  public static final int MSGID_LISTBACKENDS_CANNOT_DECODE_BACKEND_BASE_DN =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 744;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to retrieve the backend configuration base entry.  This takes two
   * arguments, which are the DN of the entry and a message explaining the
   * problem that occurred.
   */
  public static final int
       MSGID_LISTBACKENDS_CANNOT_RETRIEVE_BACKEND_BASE_ENTRY =
            CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 745;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to determine the backend ID.  This takes two arguments, which are
   * the DN of the backend configuration entry and a message explaining the
   * problem that occurred.
   */
  public static final int MSGID_LISTBACKENDS_CANNOT_DETERMINE_BACKEND_ID =
       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 746;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to determine the set of base DNs for a backend.  This takes two
   * arguments, which are the DN of the backend configuration entry and a string
   * representation of the exception that was caught.
   */
  public static final int
       MSGID_LISTBACKENDS_CANNOT_DETERMINE_BASES_FOR_BACKEND =
            CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 747;
  /**
   * Associates a set of generic messages with the message IDs defined in this
   * class.
   */
@@ -9235,6 +9478,81 @@
    registerMessage(MSGID_WAIT4DEL_TOOL_DESCRIPTION,
                    "This utility may be used to wait for a file to be " +
                    "removed from the filesystem.");
    registerMessage(MSGID_LISTBACKENDS_TOOL_DESCRIPTION,
                    "This utility may be used to list the backends and base " +
                    "DNs configured in the Directory Server.");
    registerMessage(MSGID_LISTBACKENDS_DESCRIPTION_CONFIG_CLASS,
                    "The fully-qualified name of the Java class to use as " +
                    "the Directory Server configuration handler.  If this is " +
                    "not provided, then a default of " +
                    ConfigFileHandler.class.getName() + " will be used.");
    registerMessage(MSGID_LISTBACKENDS_DESCRIPTION_CONFIG_FILE,
                    "The path to the Directory Server configuration file, " +
                    "which will enable the use of the schema definitions " +
                    "when processing the updates.  If it is not provided, " +
                    "then schema processing will not be available.");
    registerMessage(MSGID_LISTBACKENDS_DESCRIPTION_BACKEND_ID,
                    "Backend ID of the backend for which to list the base DNs");
    registerMessage(MSGID_LISTBACKENDS_DESCRIPTION_BASE_DN,
                    "Base DN for which to list the backend ID");
    registerMessage(MSGID_LISTBACKENDS_DESCRIPTION_HELP,
                    "Display this usage information.");
    registerMessage(MSGID_LISTBACKENDS_CANNOT_INITIALIZE_ARGS,
                    "An unexpected error occurred while attempting to " +
                    "initialize the command-line arguments:  %s.");
    registerMessage(MSGID_LISTBACKENDS_ERROR_PARSING_ARGS,
                    "An error occurred while parsing the command-line " +
                    "arguments:  %s.");
    registerMessage(MSGID_LISTBACKENDS_SERVER_BOOTSTRAP_ERROR,
                    "An unexpected error occurred while attempting to " +
                    "bootstrap the Directory Server client-side code:  %s.");
    registerMessage(MSGID_LISTBACKENDS_CANNOT_LOAD_CONFIG,
                    "An error occurred while trying to load the Directory " +
                    "Server configuration:  %s.");
    registerMessage(MSGID_LISTBACKENDS_CANNOT_LOAD_SCHEMA,
                    "An error occurred while trying to load the Directory " +
                    "Server schema:  %s.");
    registerMessage(MSGID_LISTBACKENDS_CANNOT_GET_BACKENDS,
                    "An error occurred while trying to read backend " +
                    "information from the server configuration:  %s.");
    registerMessage(MSGID_LISTBACKENDS_INVALID_DN,
                    "The provided base DN value '%s' could not be parsed as " +
                    "a valid DN:  %s.");
    registerMessage(MSGID_LISTBACKENDS_NOT_BASE_DN,
                    "The provided DN '%s' is not a base DN for any backend " +
                    "configured in the Directory Server.");
    registerMessage(MSGID_LISTBACKENDS_NO_BACKEND_FOR_DN,
                    "The provided DN '%s' is not below any base DN for any " +
                    "of the backends configured in the Directory Server.");
    registerMessage(MSGID_LISTBACKENDS_DN_BELOW_BASE,
                    "The provided DN '%s' is below '%s' which is configured " +
                    "as a base DN for backend '%s'.");
    registerMessage(MSGID_LISTBACKENDS_BASE_FOR_ID,
                    "The provided DN '%s' is a base DN for backend '%s'.");
    registerMessage(MSGID_LISTBACKENDS_LABEL_BACKEND_ID,
                    "Backend ID");
    registerMessage(MSGID_LISTBACKENDS_LABEL_BASE_DN,
                    "Base DN");
    registerMessage(MSGID_LISTBACKENDS_NO_SUCH_BACKEND,
                    "There is no backend with ID '%s' in the server " +
                    "configuration.");
    registerMessage(MSGID_LISTBACKENDS_NO_VALID_BACKENDS,
                    "None of the provided backend IDs exist in the server " +
                    "configuration.");
    registerMessage(MSGID_LISTBACKENDS_CANNOT_DECODE_BACKEND_BASE_DN,
                    "Unable to decode the backend configuration base DN " +
                    "string \"%s\" as a valid DN:  %s.");
    registerMessage(MSGID_LISTBACKENDS_CANNOT_RETRIEVE_BACKEND_BASE_ENTRY,
                    "Unable to retrieve the backend configuration base entry " +
                    "\"%s\" from the server configuration:  %s.");
    registerMessage(MSGID_LISTBACKENDS_CANNOT_DETERMINE_BACKEND_ID,
                    "Cannot determine the backend ID for the backend defined " +
                    "in configuration entry %s:  %s.");
    registerMessage(MSGID_LISTBACKENDS_CANNOT_DETERMINE_BASES_FOR_BACKEND,
                    "Unable to determine the set of base DNs defined in " +
                    "backend configuration entry %s:  %s.");
  }
}
opends/src/server/org/opends/server/tools/ListBackends.java
New file
@@ -0,0 +1,641 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 */
package org.opends.server.tools;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.TreeMap;
import java.util.TreeSet;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.config.DNConfigAttribute;
import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.DirectoryServer;
import org.opends.server.extensions.ConfigFileHandler;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DN;
import org.opends.server.types.InitializationException;
import org.opends.server.types.NullOutputStream;
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.StringArgument;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.messages.ConfigMessages.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.messages.ToolMessages.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
/**
 * This program provides a utility that may be used to list the backends in the
 * server, as well as to determine which backend holds a given entry.
 */
public class ListBackends
{
  /**
   * Parses the provided command-line arguments and uses that information to
   * list the backend information.
   *
   * @param  args  The command-line arguments provided to this program.
   */
  public static void main(String[] args)
  {
    int retCode = listBackends(args, true, System.out, System.err);
    if(retCode != 0)
    {
      System.exit(retCode);
    }
  }
  /**
   * Parses the provided command-line arguments and uses that information to
   * list the backend information.
   *
   * @param  args  The command-line arguments provided to this program.
   *
   * @return  A return code indicating whether the processing was successful.
   */
  public static int listBackends(String[] args)
  {
    return listBackends(args, true, System.out, System.err);
  }
  /**
   * Parses the provided command-line arguments and uses that information to
   * list the backend information.
   *
   * @param  args              The command-line arguments provided to this
   *                           program.
   * @param  initializeServer  Indicates whether to initialize the server.
   * @param  outStream         The output stream to use for standard output, or
   *                           <CODE>null</CODE> if standard output is not
   *                           needed.
   * @param  errStream         The output stream to use for standard error, or
   *                           <CODE>null</CODE> if standard error is not
   *                           needed.
   *
   * @return  A return code indicating whether the processing was successful.
   */
  public static int listBackends(String[] args, boolean initializeServer,
                                 OutputStream outStream, OutputStream errStream)
  {
    PrintStream out;
    if (outStream == null)
    {
      out = NullOutputStream.printStream();
    }
    else
    {
      out = new PrintStream(outStream);
    }
    PrintStream err;
    if (errStream == null)
    {
      err = NullOutputStream.printStream();
    }
    else
    {
      err = new PrintStream(errStream);
    }
    // Define the command-line arguments that may be used with this program.
    BooleanArgument displayUsage = null;
    StringArgument  backendID    = null;
    StringArgument  baseDN       = null;
    StringArgument  configClass  = null;
    StringArgument  configFile   = null;
    // Create the command-line argument parser for use with this program.
    String toolDescription = getMessage(MSGID_LISTBACKENDS_TOOL_DESCRIPTION);
    ArgumentParser argParser =
         new ArgumentParser("org.opends.server.tools.ListBackends",
                            toolDescription, false);
    // Initialize all the command-line argument types and register them with the
    // parser.
    try
    {
      configClass =
           new StringArgument("configclass", 'C', "configClass", true, false,
                              true, "{configClass}",
                              ConfigFileHandler.class.getName(), null,
                              MSGID_LISTBACKENDS_DESCRIPTION_CONFIG_CLASS);
      configClass.setHidden(true);
      argParser.addArgument(configClass);
      configFile =
           new StringArgument("configfile", 'f', "configFile", true, false,
                              true, "{configFile}", null, null,
                              MSGID_LISTBACKENDS_DESCRIPTION_CONFIG_FILE);
      configFile.setHidden(true);
      argParser.addArgument(configFile);
      backendID = new StringArgument("backendid", 'n', "backendID", false,
                                     true, true, "{backendID}", null, null,
                                     MSGID_LISTBACKENDS_DESCRIPTION_BACKEND_ID);
      argParser.addArgument(backendID);
      baseDN = new StringArgument("basedn", 'b', "baseDN", false, true, true,
                                  "{baseDN}", null, null,
                                  MSGID_LISTBACKENDS_DESCRIPTION_BASE_DN);
      argParser.addArgument(baseDN);
      displayUsage = new BooleanArgument("help", 'H', "help",
                                         MSGID_LISTBACKENDS_DESCRIPTION_HELP);
      argParser.addArgument(displayUsage);
      argParser.setUsageArgument(displayUsage, out);
    }
    catch (ArgumentException ae)
    {
      int    msgID   = MSGID_LISTBACKENDS_CANNOT_INITIALIZE_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      return 1;
    }
    // Parse the command-line arguments provided to this program.
    try
    {
      argParser.parseArguments(args);
    }
    catch (ArgumentException ae)
    {
      int    msgID   = MSGID_LISTBACKENDS_ERROR_PARSING_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      err.println(argParser.getUsage());
      return 1;
    }
    // If we should just display usage information, then it's already been done
    // so just return.
    if (displayUsage.isPresent())
    {
      return 0;
    }
    // Make sure that the user did not provide both the backend ID and base DN
    // arguments.
    if (backendID.isPresent() && baseDN.isPresent())
    {
      int    msgID   = MSGID_TOOL_CONFLICTING_ARGS;
      String message = getMessage(msgID, backendID.getLongIdentifier(),
                                  baseDN.getLongIdentifier());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      return 1;
    }
    // Perform the initial bootstrap of the Directory Server and process the
    // configuration.
    DirectoryServer directoryServer = DirectoryServer.getInstance();
    if (initializeServer)
    {
      try
      {
        directoryServer.bootstrapClient();
        directoryServer.initializeJMX();
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_LISTBACKENDS_SERVER_BOOTSTRAP_ERROR;
        String message = getMessage(msgID, stackTraceToSingleLineString(e));
        err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
      try
      {
        directoryServer.initializeConfiguration(configClass.getValue(),
                                                configFile.getValue());
      }
      catch (InitializationException ie)
      {
        int    msgID   = MSGID_LISTBACKENDS_CANNOT_LOAD_CONFIG;
        String message = getMessage(msgID, ie.getMessage());
        err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_LISTBACKENDS_CANNOT_LOAD_CONFIG;
        String message = getMessage(msgID, stackTraceToSingleLineString(e));
        err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
      // Initialize the Directory Server schema elements.
      try
      {
        directoryServer.initializeSchema();
      }
      catch (ConfigException ce)
      {
        int    msgID   = MSGID_LISTBACKENDS_CANNOT_LOAD_SCHEMA;
        String message = getMessage(msgID, ce.getMessage());
        err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
      catch (InitializationException ie)
      {
        int    msgID   = MSGID_LISTBACKENDS_CANNOT_LOAD_SCHEMA;
        String message = getMessage(msgID, ie.getMessage());
        err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_LISTBACKENDS_CANNOT_LOAD_SCHEMA;
        String message = getMessage(msgID, stackTraceToSingleLineString(e));
        err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
    }
    // Retrieve a list of the backkends defined in the server.
    TreeMap<String,TreeSet<DN>> backends;
    try
    {
      backends = getBackends();
    }
    catch (ConfigException ce)
    {
      int    msgID   = MSGID_LISTBACKENDS_CANNOT_GET_BACKENDS;
      String message = getMessage(msgID, ce.getMessage());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      return 1;
    }
    catch (Exception e)
    {
      int    msgID   = MSGID_LISTBACKENDS_CANNOT_GET_BACKENDS;
      String message = getMessage(msgID, stackTraceToSingleLineString(e));
      err.println(wrapText(message, MAX_LINE_WIDTH));
      return 1;
    }
    // See what action we need to take based on the arguments provided.  If the
    // backend ID argument was present, then list the base DNs for that backend.
    // If the base DN argument was present, then list the backend for that base
    // DN.  If no arguments were provided, then list all backends and base DNs.
    if (baseDN.isPresent())
    {
      // Create a map from the base DNs of the backends to the corresponding
      // backend ID.
      TreeMap<DN,String> baseToIDMap = new TreeMap<DN,String>();
      for (String id : backends.keySet())
      {
        for (DN dn : backends.get(id))
        {
          baseToIDMap.put(dn, id);
        }
      }
      // Iterate through the base DN values specified by the user.  Determine
      // the backend for that entry, and whether the provided DN is a base DN
      // for that backend.
      for (String dnStr : baseDN.getValues())
      {
        DN dn;
        try
        {
          dn = DN.decode(dnStr);
        }
        catch (DirectoryException de)
        {
          int    msgID   = MSGID_LISTBACKENDS_INVALID_DN;
          String message = getMessage(msgID, dnStr, de.getMessage());
          err.println(wrapText(message, MAX_LINE_WIDTH));
          return 1;
        }
        catch (Exception e)
        {
          int    msgID   = MSGID_LISTBACKENDS_INVALID_DN;
          String message = getMessage(msgID, dnStr,
                                      stackTraceToSingleLineString(e));
          err.println(wrapText(message, MAX_LINE_WIDTH));
          return 1;
        }
        String id = baseToIDMap.get(dn);
        if (id == null)
        {
          int    msgID   = MSGID_LISTBACKENDS_NOT_BASE_DN;
          String message = getMessage(msgID, dn.toString());
          out.println(message);
          DN parentDN = dn.getParent();
          while (true)
          {
            if (parentDN == null)
            {
              msgID   = MSGID_LISTBACKENDS_NO_BACKEND_FOR_DN;
              message = getMessage(msgID, dn.toString());
              out.println(message);
              break;
            }
            else
            {
              id = baseToIDMap.get(parentDN);
              if (id != null)
              {
                msgID = MSGID_LISTBACKENDS_DN_BELOW_BASE;
                message = getMessage(msgID, dn.toString(), parentDN.toString(),
                                     id);
                out.println(message);
                break;
              }
            }
            parentDN = parentDN.getParent();
          }
        }
        else
        {
          int    msgID   = MSGID_LISTBACKENDS_BASE_FOR_ID;
          String message = getMessage(msgID, dn.toString(), id);
          out.println(message);
        }
      }
    }
    else
    {
      LinkedList<String> backendIDs;
      if (backendID.isPresent())
      {
        backendIDs = backendID.getValues();
      }
      else
      {
        backendIDs = new LinkedList<String>(backends.keySet());
      }
      // Figure out the length of the longest backend ID and base DN defined in
      // the server.  We'll use that information to try to align the output.
      String backendIDLabel  = getMessage(MSGID_LISTBACKENDS_LABEL_BACKEND_ID);
      String baseDNLabel     = getMessage(MSGID_LISTBACKENDS_LABEL_BASE_DN);
      int    backendIDLength = 10;
      int    baseDNLength    = 7;
      Iterator<String> iterator = backendIDs.iterator();
      while (iterator.hasNext())
      {
        String id = iterator.next();
        TreeSet<DN> baseDNs = backends.get(id);
        if (baseDNs == null)
        {
          int    msgID   = MSGID_LISTBACKENDS_NO_SUCH_BACKEND;
          String message = getMessage(msgID, id);
          err.println(wrapText(message, MAX_LINE_WIDTH));
          iterator.remove();
        }
        else
        {
          backendIDLength = Math.max(id.length(), backendIDLength);
          for (DN dn : baseDNs)
          {
            baseDNLength = Math.max(dn.toString().length(), baseDNLength);
          }
        }
      }
      if (backendIDs.isEmpty())
      {
        int    msgID   = MSGID_LISTBACKENDS_NO_VALID_BACKENDS;
        String message = getMessage(msgID);
        err.println(wrapText(message, MAX_LINE_WIDTH));
        return 1;
      }
      // Print the header line and the separator line.
      out.print(backendIDLabel);
      for (int i=backendIDLabel.length(); i < backendIDLength+2; i++)
      {
        out.print(" ");
      }
      out.println(baseDNLabel);
      for (int i=0; i < backendIDLength; i++)
      {
        out.print("-");
      }
      out.print("  ");
      for (int i=0; i < baseDNLength; i++)
      {
        out.print("-");
      }
      out.println();
      // Iterate through the backends and the base DNs for each backend.
      for (String id : backendIDs)
      {
        out.print(id);
        for (int i=id.length(); i < backendIDLength+2; i++)
        {
          out.print(" ");
        }
        TreeSet<DN> baseDNs = backends.get(id);
        Iterator<DN> dnIterator = baseDNs.iterator();
        out.println(dnIterator.next().toString());
        while (dnIterator.hasNext())
        {
          for (int i=0; i < backendIDLength+2; i++)
          {
            out.print(" ");
          }
          out.println(dnIterator.next().toString());
        }
      }
    }
    // If we've gotten here, then everything completed successfully.
    return 0;
  }
  /**
   * Retrieves information about the backends configured in the Directory Server
   * mapped between the backend ID to the set of base DNs for that backend.
   *
   * @return  Information about the backends configured in the Directory Server.
   *
   * @throws  ConfigException  If a problem occurs while reading the server
   *                           configuration.
   */
  private static TreeMap<String,TreeSet<DN>> getBackends()
          throws ConfigException
  {
    // Get the base entry for all backend configuration.
    DN backendBaseDN = null;
    try
    {
      backendBaseDN = DN.decode(DN_BACKEND_BASE);
    }
    catch (DirectoryException de)
    {
      int    msgID   = MSGID_LISTBACKENDS_CANNOT_DECODE_BACKEND_BASE_DN;
      String message = getMessage(msgID, DN_BACKEND_BASE, de.getErrorMessage());
      throw new ConfigException(msgID, message, de);
    }
    catch (Exception e)
    {
      int    msgID   = MSGID_LISTBACKENDS_CANNOT_DECODE_BACKEND_BASE_DN;
      String message = getMessage(msgID, DN_BACKEND_BASE,
                                  stackTraceToSingleLineString(e));
      throw new ConfigException(msgID, message, e);
    }
    ConfigEntry baseEntry = null;
    try
    {
      baseEntry = DirectoryServer.getConfigEntry(backendBaseDN);
    }
    catch (ConfigException ce)
    {
      int    msgID   = MSGID_LISTBACKENDS_CANNOT_RETRIEVE_BACKEND_BASE_ENTRY;
      String message = getMessage(msgID, DN_BACKEND_BASE, ce.getMessage());
      throw new ConfigException(msgID, message, ce);
    }
    catch (Exception e)
    {
      int    msgID   = MSGID_LISTBACKENDS_CANNOT_RETRIEVE_BACKEND_BASE_ENTRY;
      String message = getMessage(msgID, DN_BACKEND_BASE,
                                  stackTraceToSingleLineString(e));
      throw new ConfigException(msgID, message, e);
    }
    // Iterate through the immediate children, attempting to parse them as
    // backends.
    TreeMap<String,TreeSet<DN>> backendMap = new TreeMap<String,TreeSet<DN>>();
    for (ConfigEntry configEntry : baseEntry.getChildren().values())
    {
      // Get the backend ID attribute from the entry.  If there isn't one, then
      // skip the entry.
      String backendID = null;
      try
      {
        int msgID = MSGID_CONFIG_BACKEND_ATTR_DESCRIPTION_BACKEND_ID;
        StringConfigAttribute idStub =
             new StringConfigAttribute(ATTR_BACKEND_ID, getMessage(msgID),
                                       true, false, true);
        StringConfigAttribute idAttr =
             (StringConfigAttribute) configEntry.getConfigAttribute(idStub);
        if (idAttr == null)
        {
          continue;
        }
        else
        {
          backendID = idAttr.activeValue();
        }
      }
      catch (ConfigException ce)
      {
        int    msgID   = MSGID_LISTBACKENDS_CANNOT_DETERMINE_BACKEND_ID;
        String message = getMessage(msgID, String.valueOf(configEntry.getDN()),
                                    ce.getMessage());
        throw new ConfigException(msgID, message, ce);
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_LISTBACKENDS_CANNOT_DETERMINE_BACKEND_ID;
        String message = getMessage(msgID, String.valueOf(configEntry.getDN()),
                                    stackTraceToSingleLineString(e));
        throw new ConfigException(msgID, message, e);
      }
      // Get the base DN attribute from the entry.  If there isn't one, then
      // just skip this entry.
      TreeSet<DN> baseDNs = new TreeSet<DN>();
      try
      {
        int msgID = MSGID_CONFIG_BACKEND_ATTR_DESCRIPTION_BASE_DNS;
        DNConfigAttribute baseDNStub =
             new DNConfigAttribute(ATTR_BACKEND_BASE_DN, getMessage(msgID),
                                   true, true, true);
        DNConfigAttribute baseDNAttr =
             (DNConfigAttribute) configEntry.getConfigAttribute(baseDNStub);
        if (baseDNAttr != null)
        {
          baseDNs.addAll(baseDNAttr.activeValues());
        }
      }
      catch (Exception e)
      {
        int    msgID   = MSGID_LISTBACKENDS_CANNOT_DETERMINE_BASES_FOR_BACKEND;
        String message = getMessage(msgID, String.valueOf(configEntry.getDN()),
                                    stackTraceToSingleLineString(e));
        throw new ConfigException(msgID, message, e);
      }
      backendMap.put(backendID, baseDNs);
    }
    return backendMap;
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/tools/ListBackendsTestCase.java
New file
@@ -0,0 +1,398 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 */
package org.opends.server.tools;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.types.Entry;
import org.opends.server.types.OperatingSystem;
import org.opends.server.types.ResultCode;
import org.opends.server.util.Base64;
import static org.testng.Assert.*;
import static org.opends.server.util.ServerConstants.*;
/**
 * A set of test cases for the ListBackends tool.
 */
public class ListBackendsTestCase
       extends ToolsTestCase
{
  // The path to the Directory Server configuration file.
  private String configFilePath;
  /**
   * Ensures that the Directory Server is running and gets the config file path.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @BeforeClass()
  public void startServer()
         throws Exception
  {
    TestCaseUtils.startServer();
    configFilePath = DirectoryServer.getServerRoot() + File.separator +
                     "config" + File.separator + "config.ldif";
  }
  /**
   * Retrieves sets of invalid arguments that may not be used to initialize
   * the ListBackends tool.
   *
   * @return  Sets of invalid arguments that may not be used to initialize the
   *          ListBackends tool.
   */
  @DataProvider(name = "invalidArgs")
  public Object[][] getInvalidArgumentLists()
  {
    ArrayList<String[]> argLists   = new ArrayList<String[]>();
    ArrayList<String>   reasonList = new ArrayList<String>();
    String[] args = new String[] {};
    argLists.add(args);
    reasonList.add("No arguments");
    args = new String[]
    {
      "-c",
    };
    argLists.add(args);
    reasonList.add("No value for '-c' argument");
    args = new String[]
    {
      "-c",
    };
    argLists.add(args);
    reasonList.add("No value for '-f' argument");
    args = new String[]
    {
      "-n",
    };
    argLists.add(args);
    reasonList.add("No value for '-n' argument");
    args = new String[]
    {
      "-b",
    };
    argLists.add(args);
    reasonList.add("No value for '-b' argument");
    args = new String[]
    {
      "-I"
    };
    argLists.add(args);
    reasonList.add("Invalid short argument");
    args = new String[]
    {
      "--invalidLongArgument"
    };
    argLists.add(args);
    reasonList.add("Invalid long argument");
    args = new String[]
    {
      "--backendID", "nosuchbackend"
    };
    argLists.add(args);
    reasonList.add("No config file argument");
    args = new String[]
    {
      "--configFile", configFilePath,
      "--backendID", "nosuchbackend"
    };
    argLists.add(args);
    reasonList.add("Invalid backend ID");
    args = new String[]
    {
      "--configFile", configFilePath,
      "--baseDN", "invaliddn"
    };
    argLists.add(args);
    reasonList.add("Invalid base DN");
    args = new String[]
    {
      "--configFile", configFilePath,
      "--backendID", "userRoot",
      "--baseDN", "dc=example,dc=com"
    };
    argLists.add(args);
    reasonList.add("Both backend ID and base DN");
    Object[][] returnArray = new Object[argLists.size()][2];
    for (int i=0; i < argLists.size(); i++)
    {
      returnArray[i][0] = argLists.get(i);
      returnArray[i][1] = reasonList.get(i);
    }
    return returnArray;
  }
  /**
   * Tests the ListBackends tool with sets of invalid arguments.
   *
   * @param  args           The set of arguments to use for the ListBackends
   *                        tool.
   * @param  invalidReason  The reason the provided set of arguments is invalid.
   */
  @Test(dataProvider = "invalidArgs")
  public void testInvalidArguments(String[] args, String invalidReason)
  {
    assertFalse((ListBackends.listBackends(args, false, null, null) == 0),
                "Should have been invalid because:  " + invalidReason);
  }
  /**
   * Tests the ListBackends tool with the no arguments.
   */
  @Test()
  public void testNoArguments()
  {
    String[] args =
    {
      "--configFile", configFilePath
    };
    assertEquals(ListBackends.listBackends(args, false, null, null), 0);
  }
  /**
   * Tests the ListBackends tool with one instance of the --backendID argument
   * and a valid backend ID.
   */
  @Test()
  public void testSingleBackendID()
  {
    String[] args =
    {
      "--configFile", configFilePath,
      "--backendID", "userRoot"
    };
    assertEquals(ListBackends.listBackends(args, false, null, null), 0);
  }
  /**
   * Tests the ListBackends tool with multiple instances of the --backendID
   * argument valid backend IDs.
   */
  @Test()
  public void testMultipleBackendIDs()
  {
    String[] args =
    {
      "--configFile", configFilePath,
      "--backendID", "userRoot",
      "--backendID", "schema"
    };
    assertEquals(ListBackends.listBackends(args, false, null, null), 0);
  }
  /**
   * Tests the ListBackends tool with multiple instances of the --backendID
   * argument in which one is valid and one is not.
   */
  @Test()
  public void testMultipleBackendIDsPartiallyValid()
  {
    String[] args =
    {
      "--configFile", configFilePath,
      "--backendID", "userRoot",
      "--backendID", "invalid"
    };
    assertEquals(ListBackends.listBackends(args, false, null, null), 0);
  }
  /**
   * Tests the ListBackends tool with multiple instances of the --backendID
   * argument in which all are invalid.
   */
  @Test()
  public void testMultipleBackendIDsAllInvalid()
  {
    String[] args =
    {
      "--configFile", configFilePath,
      "--backendID", "invalid1",
      "--backendID", "invalid2"
    };
    assertFalse(ListBackends.listBackends(args, false, null, null) == 0);
  }
  /**
   * Tests the ListBackends tool with one instance of the --baseDN argument
   * and a valid DN that is a base DN.
   */
  @Test()
  public void testSingleBaseDN()
  {
    String[] args =
    {
      "--configFile", configFilePath,
      "--baseDN", "dc=example,dc=com"
    };
    assertEquals(ListBackends.listBackends(args, false, null, null), 0);
  }
  /**
   * Tests the ListBackends tool with one instance of the --baseDN argument
   * and a valid DN that is not a base DN but is directly below a valid base DN.
   */
  @Test()
  public void testSingleBaseDNBelowActualBaseDN()
  {
    String[] args =
    {
      "--configFile", configFilePath,
      "--baseDN", "ou=notbase,dc=example,dc=com"
    };
    assertEquals(ListBackends.listBackends(args, false, null, null), 0);
  }
  /**
   * Tests the ListBackends tool with one instance of the --baseDN argument
   * and a valid DN that is not a base DN but is two levels below a valid base
   * DN.
   */
  @Test()
  public void testSingleBaseDNTwoLevelsBelowActualBaseDN()
  {
    String[] args =
    {
      "--configFile", configFilePath,
      "--baseDN", "ou=notbase,ou=alsonotbase,dc=example,dc=com"
    };
    assertEquals(ListBackends.listBackends(args, false, null, null), 0);
  }
  /**
   * Tests the ListBackends tool with one instance of the --baseDN argument
   * and a valid DN that is not associated with any backend in the server
   */
  @Test()
  public void testSingleBaseDNNotBelowAnyBaseDN()
  {
    String[] args =
    {
      "--configFile", configFilePath,
      "--baseDN", "ou=nonexistent"
    };
    assertEquals(ListBackends.listBackends(args, false, null, null), 0);
  }
  /**
   * Tests the ListBackends tool with multiple instances of the "--baseDN"
   * argument with valid base DNs.
   */
  @Test()
  public void testMultipleBaseDNs()
  {
    String[] args =
    {
      "--configFile", configFilePath,
      "--baseDN", "dc=example,dc=com",
      "--baseDN", "cn=schema"
    };
    assertEquals(ListBackends.listBackends(args, false, null, null), 0);
  }
  /**
   * Tests the ListBackends tool with the "--help" option.
   */
  @Test()
  public void testHelp()
  {
    String[] args =
    {
      "--help"
    };
    assertEquals(ListBackends.listBackends(args, false, null, null), 0);
  }
}