From e1198d87e7a870b462ae4941b0c5b6420230bd0a Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Mon, 13 Nov 2006 14:19:39 +0000
Subject: [PATCH] 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.

---
 opends/src/server/org/opends/server/messages/ToolMessages.java                              |  318 +++++++++++++
 opends/tests/unit-tests-testng/src/server/org/opends/server/tools/ListBackendsTestCase.java |  398 ++++++++++++++++
 opends/resource/bin/list-backends.bat                                                       |   33 +
 opends/resource/bin/list-backends                                                           |   37 +
 opends/src/server/org/opends/server/tools/ListBackends.java                                 |  641 ++++++++++++++++++++++++++
 5 files changed, 1,427 insertions(+), 0 deletions(-)

diff --git a/opends/resource/bin/list-backends b/opends/resource/bin/list-backends
new file mode 100755
index 0000000..cb42924
--- /dev/null
+++ b/opends/resource/bin/list-backends
@@ -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" "${@}"
diff --git a/opends/resource/bin/list-backends.bat b/opends/resource/bin/list-backends.bat
new file mode 100755
index 0000000..82986c4
--- /dev/null
+++ b/opends/resource/bin/list-backends.bat
@@ -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" %*
+
diff --git a/opends/src/server/org/opends/server/messages/ToolMessages.java b/opends/src/server/org/opends/server/messages/ToolMessages.java
index 849fbe3..96c339e 100644
--- a/opends/src/server/org/opends/server/messages/ToolMessages.java
+++ b/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.");
   }
 }
 
diff --git a/opends/src/server/org/opends/server/tools/ListBackends.java b/opends/src/server/org/opends/server/tools/ListBackends.java
new file mode 100644
index 0000000..6c80a9f
--- /dev/null
+++ b/opends/src/server/org/opends/server/tools/ListBackends.java
@@ -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;
+  }
+}
+
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/ListBackendsTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/ListBackendsTestCase.java
new file mode 100644
index 0000000..5d133e9
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/tools/ListBackendsTestCase.java
@@ -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);
+  }
+}
+

--
Gitblit v1.10.0