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

neil_a_wilson
15.40.2006 6b7027bb28c10ddf23e00def117d352b736ffe4d
Update many of the command-line tools to make them more suitable for using
programatically. This includes adding an option to bypass the Directory Server
initialization (which is necessary if the server is already running in the same
JVM as the tool), as well as making it possible to redefine standard output and
standard error (e.g., so that the output can be parsed or discarded).

This also includes a SASL PLAIN test case that makes use of the LDAPSearch tool
to verify that PLAIN authentication works over LDAP as well as through the
internal interfaces.

OpenDS Issue Numbers: 652, 653
1 files added
7 files modified
867 ■■■■ changed files
opends/src/server/org/opends/server/tools/LDAPCompare.java 124 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPConnection.java 40 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPDelete.java 115 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPModify.java 150 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPSearch.java 163 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/StopDS.java 94 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/NullOutputStream.java 152 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java 29 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/LDAPCompare.java
@@ -30,6 +30,8 @@
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.text.ParseException;
import java.util.ArrayList;
@@ -48,6 +50,7 @@
import org.opends.server.protocols.ldap.LDAPMessage;
import org.opends.server.protocols.ldap.ProtocolOp;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.NullOutputStream;
import org.opends.server.util.Base64;
import org.opends.server.util.PasswordReader;
import org.opends.server.util.args.ArgumentException;
@@ -80,16 +83,27 @@
  // The message ID counter to use for requests.
  private AtomicInteger nextMessageID;
  // The print stream to use for standard error.
  private PrintStream err;
  // The print stream to use for standard output.
  private PrintStream out;
  /**
   * Constructor for the LDAPCompare object.
   *
   * @param  nextMessageID  The message ID counter to use for requests.
   * @param  out            The print stream to use for standard output.
   * @param  err            The print stream to use for standard error.
   */
  public LDAPCompare(AtomicInteger nextMessageID)
  public LDAPCompare(AtomicInteger nextMessageID, PrintStream out,
                     PrintStream err)
  {
    this.nextMessageID = nextMessageID;
    this.out           = out;
    this.err           = err;
  }
  /**
@@ -178,8 +192,7 @@
                                     attributeType, attrValOctetStr);
    int msgID = MSGID_PROCESSING_COMPARE_OPERATION;
    System.out.println(getMessage(msgID, attributeType, attrValOctetStr,
                                  dnOctetStr));
    out.println(getMessage(msgID, attributeType, attrValOctetStr, dnOctetStr));
    if(!compareOptions.showOperations())
    {
@@ -203,7 +216,7 @@
        {
          msgID = MSGID_OPERATION_FAILED;
          String msg = getMessage(msgID, "COMPARE", line, ae.getMessage());
          System.err.println(msg);
          err.println(msg);
          return;
        }
      }
@@ -224,16 +237,16 @@
        if(resultCode == COMPARE_FALSE)
        {
          msgID = MSGID_COMPARE_OPERATION_RESULT_FALSE;
          System.out.println(getMessage(msgID, line));
          out.println(getMessage(msgID, line));
        } else if(resultCode == COMPARE_TRUE)
        {
          msgID = MSGID_COMPARE_OPERATION_RESULT_TRUE;
          System.out.println(getMessage(msgID, line));
          out.println(getMessage(msgID, line));
        } else
        {
          msgID = MSGID_OPERATION_FAILED;
          String msg = getMessage(msgID, "COMPARE", line, errorMessage);
          System.err.println(msg);
          err.println(msg);
        }
      }
    }
@@ -247,7 +260,7 @@
  public static void main(String[] args)
  {
    int retCode = mainCompare(args);
    int retCode = mainCompare(args, true, System.out, System.err);
    if(retCode != 0)
    {
@@ -266,6 +279,50 @@
  public static int mainCompare(String[] args)
  {
    return mainCompare(args, true, System.out, System.err);
  }
  /**
   * Parses the provided command-line arguments and uses that information to
   * run the ldapcompare tool.
   *
   * @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 The error code.
   */
  public static int mainCompare(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);
    }
    LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions();
    LDAPCompareOptions compareOptions = new LDAPCompareOptions();
    LDAPConnection connection = null;
@@ -363,7 +420,7 @@
      showUsage = new BooleanArgument("showUsage", 'H', "help",
                                    MSGID_DESCRIPTION_SHOWUSAGE);
      argParser.addArgument(showUsage);
      argParser.setUsageArgument(showUsage);
      argParser.setUsageArgument(showUsage, out);
      controlStr = new StringArgument("controls", 'J', "controls", false,
                false, true,
                "{controloid[:criticality[:value|::b64value|:<fileurl]]}",
@@ -406,7 +463,7 @@
      int    msgID   = MSGID_ENCPW_CANNOT_INITIALIZE_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      System.err.println(message);
      err.println(message);
      return 1;
    }
@@ -420,8 +477,8 @@
      int    msgID   = MSGID_ENCPW_ERROR_PARSING_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      System.err.println(message);
      System.err.println(argParser.getUsage());
      err.println(message);
      err.println(argParser.getUsage());
      return 1;
    }
@@ -433,7 +490,7 @@
    if(bindPassword.isPresent() && bindPasswordFile.isPresent())
    {
      System.err.println("ERROR: Both -w and -j flags specified. " +
      err.println("ERROR: Both -w and -j flags specified. " +
                          "Please specify one.");
      return 1;
    }
@@ -442,7 +499,7 @@
    if(attrAndDNStrings.isEmpty())
    {
      System.err.println("No Attributes specified for comparison");
      err.println("No Attributes specified for comparison");
      return 1;
    }
@@ -459,8 +516,8 @@
    int idx = attributeString.indexOf(":");
    if(idx == -1)
    {
      System.err.println("Invalid attribute string:" + attributeString);
      System.err.println("Attribute string must be in one of the " +
      err.println("Invalid attribute string:" + attributeString);
      err.println("Attribute string must be in one of the " +
      "following forms: attribute:value, attribute::base64value, " +
      "attribute:<fileURL" );
      return 1;
@@ -505,7 +562,7 @@
    } catch (ArgumentException ae)
    {
      assert debugException(CLASS_NAME, "main", ae);
      System.err.println(ae.getMessage());
      err.println(ae.getMessage());
      return 1;
    }
@@ -515,14 +572,14 @@
      if(versionNumber != 2 && versionNumber != 3)
      {
        int msgID = MSGID_DESCRIPTION_INVALID_VERSION;
        System.err.println(getMessage(msgID, versionNumber));
        err.println(getMessage(msgID, versionNumber));
        return 1;
      }
      connectionOptions.setVersionNumber(versionNumber);
    } catch(ArgumentException ae)
    {
      assert debugException(CLASS_NAME, "main", ae);
      System.err.println(ae.getMessage());
      err.println(ae.getMessage());
      return 1;
    }
@@ -535,14 +592,13 @@
      // read the password from the stdin.
      try
      {
        System.out.print(getMessage(MSGID_LDAPAUTH_PASSWORD_PROMPT,
                                    bindDNValue));
        out.print(getMessage(MSGID_LDAPAUTH_PASSWORD_PROMPT, bindDNValue));
        char[] pwChars = PasswordReader.readPassword();
        bindPasswordValue = new String(pwChars);
      } catch(Exception ex)
      {
        assert debugException(CLASS_NAME, "main", ex);
        System.err.println(ex.getMessage());
        err.println(ex.getMessage());
        return 1;
      }
    } else if(bindPasswordValue == null)
@@ -566,8 +622,8 @@
      LDAPControl ctrl = LDAPToolUtils.getControl(ctrlString);
      if(ctrl == null)
      {
        System.err.println("Invalid control specified:" + ctrlString);
        System.out.println(argParser.getUsage());
        err.println("Invalid control specified:" + ctrlString);
        err.println(argParser.getUsage());
        return 1;
      }
      compareOptions.getControls().add(ctrl);
@@ -588,7 +644,7 @@
      }
      catch (LDAPException le)
      {
        System.err.println(getMessage(MSGID_LDAP_ASSERTION_INVALID_FILTER,
        err.println(getMessage(MSGID_LDAP_ASSERTION_INVALID_FILTER,
                                      le.getMessage()));
        return 1;
      }
@@ -626,13 +682,13 @@
    {
      if(!connectionOptions.useSSL() && !connectionOptions.useStartTLS())
      {
        System.err.println("SASL External requires either SSL or StartTLS " +
        err.println("SASL External requires either SSL or StartTLS " +
                           "options to be requested.");
        return 1;
      }
      if(keyStorePathValue == null)
      {
        System.err.println("SASL External requires a path to the SSL " +
        err.println("SASL External requires a path to the SSL " +
                           "client certificate keystore.");
        return 1;
      }
@@ -640,9 +696,11 @@
    try
    {
      if (initializeServer)
      {
      // Bootstrap and initialize directory data structures.
      DirectoryServer.bootstrapClient();
      }
      // Connect to the specified host with the supplied userDN and password.
      SSLConnectionFactory sslConnectionFactory = null;
@@ -657,11 +715,11 @@
      AtomicInteger nextMessageID = new AtomicInteger(1);
      connection = new LDAPConnection(hostNameValue, portNumber,
                                      connectionOptions);
                                      connectionOptions, out, err);
      connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID);
      LDAPCompare ldapCompare = new LDAPCompare(nextMessageID);
      LDAPCompare ldapCompare = new LDAPCompare(nextMessageID, out, err);
      if(fileNameValue == null && dnStrings.isEmpty())
      {
        // Read from stdin.
@@ -682,19 +740,19 @@
    } catch(LDAPException le)
    {
      assert debugException(CLASS_NAME, "main", le);
      System.err.println(le.getMessage());
      err.println(le.getMessage());
      int code = le.getResultCode();
      return code;
    } catch(LDAPConnectionException lce)
    {
        assert debugException(CLASS_NAME, "main", lce);
        System.err.println(lce.getMessage());
        err.println(lce.getMessage());
        int code = lce.getErrorCode();
        return code;
    } catch(Exception e)
    {
      assert debugException(CLASS_NAME, "main", e);
      System.err.println(e.getMessage());
      err.println(e.getMessage());
      return 1;
    } finally
    {
opends/src/server/org/opends/server/tools/LDAPConnection.java
@@ -26,6 +26,7 @@
 */
package org.opends.server.tools;
import java.io.PrintStream;
import java.net.ConnectException;
import java.net.Socket;
import java.net.UnknownHostException;
@@ -79,6 +80,9 @@
  private ASN1Reader asn1Reader;
  private int versionNumber = 3;
  private PrintStream out;
  private PrintStream err;
  /**
   * Constructor for the LDAPConnection object.
   *
@@ -89,10 +93,28 @@
   */
  public LDAPConnection(String host, int port, LDAPConnectionOptions options)
  {
    this(host, port, options, System.out, System.err);
  }
  /**
   * Constructor for the LDAPConnection object.
   *
   * @param   host    The hostname to send the request to.
   * @param   port    The port number on which the directory server is accepting
   *                  requests.
   * @param  options  The set of options for this connection.
   * @param  out      The print stream to use for standard output.
   * @param  err      The print stream to use for standard error.
   */
  public LDAPConnection(String host, int port, LDAPConnectionOptions options,
                        PrintStream out, PrintStream err)
  {
    this.hostName = host;
    this.portNumber = port;
    this.connectionOptions = options;
    this.versionNumber = options.getVersionNumber();
    this.out = out;
    this.err = err;
  }
  /**
@@ -263,7 +285,7 @@
      }
      if(result != null)
      {
        System.out.println(result);
        out.println(result);
      }
      for (LDAPControl c : responseControls)
@@ -275,14 +297,14 @@
          {
            int    msgID   = MSGID_BIND_AUTHZID_RETURNED;
            String message = getMessage(msgID, controlValue.stringValue());
            System.out.println(message);
            out.println(message);
          }
        }
        else if (c.getOID().equals(OID_NS_PASSWORD_EXPIRED))
        {
          int    msgID   = MSGID_BIND_PASSWORD_EXPIRED;
          String message = getMessage(msgID);
          System.out.println(message);
          out.println(message);
        }
        else if (c.getOID().equals(OID_NS_PASSWORD_EXPIRING))
        {
@@ -295,7 +317,7 @@
          int    msgID   = MSGID_BIND_PASSWORD_EXPIRING;
          String message = getMessage(msgID, timeString);
          System.out.println(message);
          out.println(message);
        }
        else if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
        {
@@ -311,17 +333,17 @@
              case PASSWORD_EXPIRED:
                int    msgID   = MSGID_BIND_PASSWORD_EXPIRED;
                String message = getMessage(msgID);
                System.out.println(message);
                out.println(message);
                break;
              case ACCOUNT_LOCKED:
                msgID   = MSGID_BIND_ACCOUNT_LOCKED;
                message = getMessage(msgID);
                System.out.println(message);
                out.println(message);
                break;
              case CHANGE_AFTER_RESET:
                msgID   = MSGID_BIND_MUST_CHANGE_PASSWORD;
                message = getMessage(msgID);
                System.out.println(message);
                out.println(message);
                break;
            }
          }
@@ -338,12 +360,12 @@
                int    msgID   = MSGID_BIND_PASSWORD_EXPIRING;
                String message = getMessage(msgID, timeString);
                System.out.println(message);
                out.println(message);
                break;
              case GRACE_LOGINS_REMAINING:
                msgID   = MSGID_BIND_GRACE_LOGINS_REMAINING;
                message = getMessage(msgID, pwPolicyControl.getWarningValue());
                System.out.println(message);
                out.println(message);
                break;
            }
          }
opends/src/server/org/opends/server/tools/LDAPDelete.java
@@ -30,6 +30,8 @@
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -46,6 +48,7 @@
import org.opends.server.protocols.ldap.LDAPException;
import org.opends.server.protocols.ldap.LDAPMessage;
import org.opends.server.protocols.ldap.ProtocolOp;
import org.opends.server.types.NullOutputStream;
import org.opends.server.util.PasswordReader;
import org.opends.server.util.args.ArgumentException;
import org.opends.server.util.args.ArgumentParser;
@@ -77,16 +80,27 @@
  // The message ID counter to use for requests.
  private AtomicInteger nextMessageID;
  // The print stream to use for standard error.
  private PrintStream err;
  // The print stream to use for standard output.
  private PrintStream out;
  /**
   * Constructor for the LDAPDelete object.
   *
   * @param  nextMessageID  The next message ID to use for requests.
   * @param  out            The print stream to use for standard output.
   * @param  err            The print stream to use for standard error.
   */
  public LDAPDelete(AtomicInteger nextMessageID)
  public LDAPDelete(AtomicInteger nextMessageID, PrintStream out,
                    PrintStream err)
  {
    this.nextMessageID = nextMessageID;
    this.out           = out;
    this.err           = err;
  }
  /**
@@ -162,7 +176,7 @@
    protocolOp = new DeleteRequestProtocolOp(asn1OctetStr);
    int msgID = MSGID_PROCESSING_OPERATION;
    System.out.println(getMessage(msgID, "DELETE", asn1OctetStr));
    out.println(getMessage(msgID, "DELETE", asn1OctetStr));
    if(!deleteOptions.showOperations())
    {
      LDAPMessage message = new LDAPMessage(nextMessageID.getAndIncrement(),
@@ -185,7 +199,7 @@
        {
          msgID = MSGID_OPERATION_FAILED;
          String msg = getMessage(msgID, "DELETE", line, ae.getMessage());
          System.err.println(msg);
          err.println(msg);
          return;
        }
      }
@@ -206,12 +220,12 @@
        {
          msgID = MSGID_OPERATION_FAILED;
          String msg = getMessage(msgID, "DELETE", line, errorMessage);
          System.err.println(msg);
          err.println(msg);
        } else
        {
          msgID = MSGID_OPERATION_SUCCESSFUL;
          String msg = getMessage(msgID, "DELETE", line);
          System.out.println(msg);
          out.println(msg);
        }
      }
    }
@@ -225,7 +239,7 @@
  public static void main(String[] args)
  {
    int retCode = mainDelete(args);
    int retCode = mainDelete(args, true, System.out, System.err);
    if(retCode != 0)
    {
@@ -244,6 +258,50 @@
  public static int mainDelete(String[] args)
  {
    return mainDelete(args, true, System.out, System.err);
  }
  /**
   * Parses the provided command-line arguments and uses that information to
   * run the ldapdelete tool.
   *
   * @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 The error code.
   */
  public static int mainDelete(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);
    }
    LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions();
    LDAPDeleteOptions deleteOptions = new LDAPDeleteOptions();
    LDAPConnection connection = null;
@@ -335,7 +393,7 @@
      showUsage = new BooleanArgument("showUsage", 'H', "help",
                                      MSGID_DESCRIPTION_SHOWUSAGE);
      argParser.addArgument(showUsage);
      argParser.setUsageArgument(showUsage);
      argParser.setUsageArgument(showUsage, out);
      controlStr = new StringArgument("controls", 'J', "controls", false, false,
           true, "{controloid[:criticality[:value|::b64value|:<fileurl]]}",
           null, null, MSGID_DESCRIPTION_CONTROLS);
@@ -372,7 +430,7 @@
      int    msgID   = MSGID_ENCPW_CANNOT_INITIALIZE_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      System.err.println(message);
      err.println(message);
      return 1;
    }
@@ -386,21 +444,21 @@
      int    msgID   = MSGID_ENCPW_ERROR_PARSING_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      System.err.println(message);
      System.err.println(argParser.getUsage());
      err.println(message);
      err.println(argParser.getUsage());
      return 1;
    }
    // If we should just display usage information, then print it and exit.
    if (showUsage.isPresent())
    {
      System.out.println(argParser.getUsage());
      out.println(argParser.getUsage());
      return 0;
    }
    if(bindPassword.isPresent() && bindPasswordFile.isPresent())
    {
      System.err.println("ERROR: Both -w and -j flags specified. " +
      err.println("ERROR: Both -w and -j flags specified. " +
                         "Please specify one.");
      return 1;
    }
@@ -413,7 +471,7 @@
    } catch(ArgumentException ae)
    {
      assert debugException(CLASS_NAME, "main", ae);
      System.err.println(ae.getMessage());
      err.println(ae.getMessage());
      return 1;
    }
@@ -423,14 +481,14 @@
      if(versionNumber != 2 && versionNumber != 3)
      {
        int msgID = MSGID_DESCRIPTION_INVALID_VERSION;
        System.err.println(getMessage(msgID, versionNumber));
        err.println(getMessage(msgID, versionNumber));
        return 1;
      }
      connectionOptions.setVersionNumber(versionNumber);
    } catch(ArgumentException ae)
    {
      assert debugException(CLASS_NAME, "main", ae);
      System.err.println(ae.getMessage());
      err.println(ae.getMessage());
      return 1;
    }
@@ -442,14 +500,13 @@
      // read the password from the stdin.
      try
      {
        System.out.print(getMessage(MSGID_LDAPAUTH_PASSWORD_PROMPT,
                                    bindDNValue));
        out.print(getMessage(MSGID_LDAPAUTH_PASSWORD_PROMPT, bindDNValue));
        char[] pwChars = PasswordReader.readPassword();
        bindPasswordValue = new String(pwChars);
      } catch(Exception ex)
      {
        assert debugException(CLASS_NAME, "main", ex);
        System.err.println(ex.getMessage());
        err.println(ex.getMessage());
        return 1;
      }
    } else if(bindPasswordValue == null)
@@ -474,8 +531,8 @@
      LDAPControl ctrl = LDAPToolUtils.getControl(ctrlString);
      if(ctrl == null)
      {
        System.err.println("Invalid control specified:" + ctrlString);
        System.out.println(argParser.getUsage());
        err.println("Invalid control specified:" + ctrlString);
        err.println(argParser.getUsage());
        return 1;
      }
      deleteOptions.getControls().add(ctrl);
@@ -524,13 +581,13 @@
    {
      if(!connectionOptions.useSSL() && !connectionOptions.useStartTLS())
      {
        System.err.println("SASL External requires either SSL or StartTLS " +
        err.println("SASL External requires either SSL or StartTLS " +
                           "options to be requested.");
        return 1;
      }
      if(keyStorePathValue == null)
      {
        System.err.println("SASL External requires a path to the SSL " +
        err.println("SASL External requires a path to the SSL " +
                           "client certificate keystore.");
        return 1;
      }
@@ -538,9 +595,11 @@
    try
    {
      if (initializeServer)
      {
      // Bootstrap and initialize directory data structures.
      DirectoryServer.bootstrapClient();
      }
      // Connect to the specified host with the supplied userDN and password.
      SSLConnectionFactory sslConnectionFactory = null;
@@ -555,10 +614,10 @@
      AtomicInteger nextMessageID = new AtomicInteger(1);
      connection = new LDAPConnection(hostNameValue, portNumber,
                                      connectionOptions);
                                      connectionOptions, out, err);
      connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID);
      LDAPDelete ldapDelete = new LDAPDelete(nextMessageID);
      LDAPDelete ldapDelete = new LDAPDelete(nextMessageID, out, err);
      if(fileNameValue == null && dnStrings.isEmpty())
      {
        // Read from stdin.
@@ -578,19 +637,19 @@
    } catch(LDAPException le)
    {
      assert debugException(CLASS_NAME, "main", le);
      System.err.println(le.getMessage());
      err.println(le.getMessage());
      int code = le.getResultCode();
      return code;
    } catch(LDAPConnectionException lce)
    {
      assert debugException(CLASS_NAME, "main", lce);
      System.err.println(lce.getMessage());
      err.println(lce.getMessage());
      int code = lce.getErrorCode();
      return code;
    } catch(Exception e)
    {
      assert debugException(CLASS_NAME, "main", e);
      System.err.println(e.getMessage());
      err.println(e.getMessage());
      return 1;
    } finally
    {
opends/src/server/org/opends/server/tools/LDAPModify.java
@@ -29,6 +29,8 @@
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -58,6 +60,7 @@
import org.opends.server.protocols.ldap.ProtocolOp;
import org.opends.server.types.Attribute;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.NullOutputStream;
import org.opends.server.util.AddChangeRecordEntry;
import org.opends.server.util.ChangeRecordEntry;
import org.opends.server.util.LDIFException;
@@ -94,6 +97,12 @@
  // The message ID counter to use for requests.
  private AtomicInteger nextMessageID;
  // The print stream to use for standard error.
  private PrintStream err;
  // The print stream to use for standard output.
  private PrintStream out;
  // The LDIF file name.
  private String fileName = null;
@@ -103,8 +112,11 @@
   * @param  fileName       The name of the file containing the LDIF data to use
   *                        for the modifications.
   * @param  nextMessageID  The message ID counter to use for requests.
   * @param  out            The print stream to use for standard output.
   * @param  err            The print stream to use for standard error.
   */
  public LDAPModify(String fileName, AtomicInteger nextMessageID)
  public LDAPModify(String fileName, AtomicInteger nextMessageID,
                    PrintStream out, PrintStream err)
  {
    if(fileName == null)
    {
@@ -115,6 +127,8 @@
    }
    this.nextMessageID = nextMessageID;
    this.out           = out;
    this.err           = err;
  }
@@ -181,7 +195,7 @@
          int    msgID   = MSGID_LDIF_FILE_INVALID_LDIF_ENTRY;
          String message = getMessage(msgID, le.getLineNumber(), fileName,
                                      String.valueOf(le));
          System.err.println(message);
          err.println(message);
          continue;
        }
      } catch (Exception e)
@@ -206,7 +220,7 @@
        {
          int    msgID   = MSGID_LDIF_FILE_READ_ERROR;
          String message = getMessage(msgID, fileName, String.valueOf(e));
          System.err.println(message);
          err.println(message);
          continue;
        }
      }
@@ -246,13 +260,13 @@
          }
          protocolOp = new AddRequestProtocolOp(asn1OctetStr, attributes);
          msgID = MSGID_PROCESSING_OPERATION;
          System.out.println(getMessage(msgID, operationType, asn1OctetStr));
          out.println(getMessage(msgID, operationType, asn1OctetStr));
          break;
        case DELETE:
          operationType = "DELETE";
          protocolOp = new DeleteRequestProtocolOp(asn1OctetStr);
          msgID = MSGID_PROCESSING_OPERATION;
          System.out.println(getMessage(msgID, operationType, asn1OctetStr));
          out.println(getMessage(msgID, operationType, asn1OctetStr));
          break;
        case MODIFY:
          operationType = "MODIFY";
@@ -261,7 +275,7 @@
            new ArrayList<LDAPModification>(modEntry.getModifications());
          protocolOp = new ModifyRequestProtocolOp(asn1OctetStr, mods);
          msgID = MSGID_PROCESSING_OPERATION;
          System.out.println(getMessage(msgID, operationType, asn1OctetStr));
          out.println(getMessage(msgID, operationType, asn1OctetStr));
          break;
        case MODIFY_DN:
          operationType = "MODIFY DN";
@@ -281,7 +295,7 @@
                 modDNEntry.deleteOldRDN());
          }
          msgID = MSGID_PROCESSING_OPERATION;
          System.out.println(getMessage(msgID, operationType, asn1OctetStr));
          out.println(getMessage(msgID, operationType, asn1OctetStr));
          break;
        default:
          break;
@@ -304,7 +318,7 @@
        {
          assert debugException(CLASS_NAME, "readAndExecute", ae);
          msgID = MSGID_OPERATION_FAILED;
          System.err.println(getMessage(msgID, operationType, asn1OctetStr,
          err.println(getMessage(msgID, operationType, asn1OctetStr,
                                        ae.getMessage()));
          if(!modifyOptions.continueOnError())
          {
@@ -365,22 +379,22 @@
            throw new LDAPException(resultCode, msgID, msg);
          } else
          {
            System.err.println(msg);
            err.println(msg);
          }
        } else
        {
          msgID = MSGID_OPERATION_SUCCESSFUL;
          String msg = getMessage(msgID, operationType, asn1OctetStr);
          System.out.println(msg);
          out.println(msg);
          if (errorMessage != null)
          {
            System.out.println(errorMessage);
            out.println(errorMessage);
          }
          if (referralURLs != null)
          {
            System.out.println(referralURLs);
            out.println(referralURLs);
          }
        }
@@ -394,7 +408,7 @@
            if (controlValue == null)
            {
              msgID = MSGID_LDAPMODIFY_PREREAD_NO_VALUE;
              System.err.println(getMessage(msgID));
              err.println(getMessage(msgID));
              continue;
            }
@@ -409,20 +423,20 @@
            catch (ASN1Exception ae)
            {
              msgID = MSGID_LDAPMODIFY_PREREAD_CANNOT_DECODE_VALUE;
              System.err.println(getMessage(msgID, ae.getMessage()));
              err.println(getMessage(msgID, ae.getMessage()));
              continue;
            }
            catch (LDAPException le)
            {
              msgID = MSGID_LDAPMODIFY_PREREAD_CANNOT_DECODE_VALUE;
              System.err.println(getMessage(msgID, le.getMessage()));
              err.println(getMessage(msgID, le.getMessage()));
              continue;
            }
            StringBuilder buffer = new StringBuilder();
            searchEntry.toLDIF(buffer, 78);
            System.out.println(getMessage(MSGID_LDAPMODIFY_PREREAD_ENTRY));
            System.out.println(buffer);
            out.println(getMessage(MSGID_LDAPMODIFY_PREREAD_ENTRY));
            out.println(buffer);
          }
          else if (oid.equals(OID_LDAP_READENTRY_POSTREAD))
          {
@@ -430,7 +444,7 @@
            if (controlValue == null)
            {
              msgID = MSGID_LDAPMODIFY_POSTREAD_NO_VALUE;
              System.err.println(getMessage(msgID));
              err.println(getMessage(msgID));
              continue;
            }
@@ -445,20 +459,20 @@
            catch (ASN1Exception ae)
            {
              msgID = MSGID_LDAPMODIFY_POSTREAD_CANNOT_DECODE_VALUE;
              System.err.println(getMessage(msgID, ae.getMessage()));
              err.println(getMessage(msgID, ae.getMessage()));
              continue;
            }
            catch (LDAPException le)
            {
              msgID = MSGID_LDAPMODIFY_POSTREAD_CANNOT_DECODE_VALUE;
              System.err.println(getMessage(msgID, le.getMessage()));
              err.println(getMessage(msgID, le.getMessage()));
              continue;
            }
            StringBuilder buffer = new StringBuilder();
            searchEntry.toLDIF(buffer, 78);
            System.out.println(getMessage(MSGID_LDAPMODIFY_POSTREAD_ENTRY));
            System.out.println(buffer);
            out.println(getMessage(MSGID_LDAPMODIFY_POSTREAD_ENTRY));
            out.println(buffer);
          }
        }
      }
@@ -474,7 +488,7 @@
  public static void main(String[] args)
  {
    int retCode = mainModify(args);
    int retCode = mainModify(args, true, System.out, System.err);
    if(retCode != 0)
    {
@@ -494,6 +508,51 @@
  public static int mainModify(String[] args)
  {
    return mainModify(args, true, System.out, System.err);
  }
  /**
   * Parses the provided command-line arguments and uses that information to
   * run the ldapmodify tool.
   *
   * @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 The error code.
   */
  public static int mainModify(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);
    }
    LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions();
    LDAPModifyOptions modifyOptions = new LDAPModifyOptions();
    LDAPConnection connection = null;
@@ -597,7 +656,7 @@
      showUsage = new BooleanArgument("showUsage", 'H', "help",
                                    MSGID_DESCRIPTION_SHOWUSAGE);
      argParser.addArgument(showUsage);
      argParser.setUsageArgument(showUsage);
      argParser.setUsageArgument(showUsage, out);
      controlStr = new StringArgument("controls", 'J', "controls", false,
                false, true,
                "{controloid[:criticality[:value|::b64value|:<fileurl]]}",
@@ -654,7 +713,7 @@
      int    msgID   = MSGID_ENCPW_CANNOT_INITIALIZE_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      System.err.println(message);
      err.println(message);
      return 1;
    }
@@ -668,8 +727,8 @@
      int    msgID   = MSGID_ENCPW_ERROR_PARSING_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      System.err.println(message);
      System.err.println(argParser.getUsage());
      err.println(message);
      err.println(argParser.getUsage());
      return 1;
    }
@@ -681,7 +740,7 @@
    if(bindPassword.isPresent() && bindPasswordFile.isPresent())
    {
      System.err.println("ERROR: Both -w and -j flags specified. " +
      err.println("ERROR: Both -w and -j flags specified. " +
                         "Please specify one.");
      return 1;
    }
@@ -694,7 +753,7 @@
    } catch(ArgumentException ae)
    {
      assert debugException(CLASS_NAME, "main", ae);
      System.err.println(ae.getMessage());
      err.println(ae.getMessage());
      return 1;
    }
@@ -704,14 +763,14 @@
      if(versionNumber != 2 && versionNumber != 3)
      {
        int msgID = MSGID_DESCRIPTION_INVALID_VERSION;
        System.err.println(getMessage(msgID, versionNumber));
        err.println(getMessage(msgID, versionNumber));
        return 1;
      }
      connectionOptions.setVersionNumber(versionNumber);
    } catch(ArgumentException ae)
    {
      assert debugException(CLASS_NAME, "main", ae);
      System.err.println(ae.getMessage());
      err.println(ae.getMessage());
      return 1;
    }
@@ -723,14 +782,13 @@
      // read the password from the stdin.
      try
      {
        System.out.print(getMessage(MSGID_LDAPAUTH_PASSWORD_PROMPT,
                                    bindDNValue));
        out.print(getMessage(MSGID_LDAPAUTH_PASSWORD_PROMPT, bindDNValue));
        char[] pwChars = PasswordReader.readPassword();
        bindPasswordValue = new String(pwChars);
      } catch(Exception ex)
      {
        assert debugException(CLASS_NAME, "main", ex);
        System.err.println(ex.getMessage());
        err.println(ex.getMessage());
        return 1;
      }
    } else if(bindPasswordValue == null)
@@ -755,8 +813,8 @@
      LDAPControl ctrl = LDAPToolUtils.getControl(ctrlString);
      if(ctrl == null)
      {
        System.err.println("Invalid control specified:" + ctrlString);
        System.out.println(argParser.getUsage());
        err.println("Invalid control specified:" + ctrlString);
        err.println(argParser.getUsage());
        return 1;
      }
      modifyOptions.getControls().add(ctrl);
@@ -787,7 +845,7 @@
      }
      catch (LDAPException le)
      {
        System.err.println(getMessage(MSGID_LDAP_ASSERTION_INVALID_FILTER,
        err.println(getMessage(MSGID_LDAP_ASSERTION_INVALID_FILTER,
                                      le.getMessage()));
        return 1;
      }
@@ -862,13 +920,13 @@
    {
      if(!connectionOptions.useSSL() && !connectionOptions.useStartTLS())
      {
        System.err.println("SASL External requires either SSL or StartTLS " +
        err.println("SASL External requires either SSL or StartTLS " +
                           "options to be requested.");
        return 1;
      }
      if(keyStorePathValue == null)
      {
        System.err.println("SASL External requires a path to the SSL " +
        err.println("SASL External requires a path to the SSL " +
                           "client certificate keystore.");
        return 1;
      }
@@ -876,8 +934,11 @@
    try
    {
      if (initializeServer)
      {
      // Bootstrap and initialize directory data structures.
      DirectoryServer.bootstrapClient();
      }
      // Connect to the specified host with the supplied userDN and password.
      SSLConnectionFactory sslConnectionFactory = null;
@@ -892,10 +953,11 @@
      AtomicInteger nextMessageID = new AtomicInteger(1);
      connection = new LDAPConnection(hostNameValue, portNumber,
                                      connectionOptions);
                                      connectionOptions, out, err);
      connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID);
      LDAPModify ldapModify = new LDAPModify(fileNameValue, nextMessageID);
      LDAPModify ldapModify = new LDAPModify(fileNameValue, nextMessageID,
                                             out, err);
      InputStream is = System.in;
      if(fileNameValue != null)
      {
@@ -905,19 +967,19 @@
    } catch(LDAPException le)
    {
      assert debugException(CLASS_NAME, "main", le);
      System.err.println(le.getMessage());
      err.println(le.getMessage());
      int code = le.getResultCode();
      return code;
    } catch(LDAPConnectionException lce)
    {
      assert debugException(CLASS_NAME, "main", lce);
      System.err.println(lce.getMessage());
      err.println(lce.getMessage());
      int code = lce.getErrorCode();
      return code;
    } catch(Exception e)
    {
      assert debugException(CLASS_NAME, "main", e);
      System.err.println(e.getMessage());
      err.println(e.getMessage());
      return 1;
    } finally
    {
opends/src/server/org/opends/server/tools/LDAPSearch.java
@@ -29,6 +29,8 @@
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
@@ -65,6 +67,7 @@
import org.opends.server.protocols.ldap.SearchResultEntryProtocolOp;
import org.opends.server.protocols.ldap.SearchResultReferenceProtocolOp;
import org.opends.server.types.DN;
import org.opends.server.types.NullOutputStream;
import static org.opends.server.loggers.Debug.*;
import static org.opends.server.messages.MessageHandler.*;
@@ -93,16 +96,27 @@
  // The message ID counter to use for requests.
  private AtomicInteger nextMessageID;
  // The print stream to use for standard error.
  private PrintStream err;
  // The print stream to use for standard output.
  private PrintStream out;
  /**
   * Constructor for the LDAPSearch object.
   *
   * @param  nextMessageID  The message ID counter to use for requests.
   * @param  out            The print stream to use for standard output.
   * @param  err            The print stream to use for standard error.
   */
  public LDAPSearch(AtomicInteger nextMessageID)
  public LDAPSearch(AtomicInteger nextMessageID, PrintStream out,
                    PrintStream err)
  {
    this.nextMessageID = nextMessageID;
    this.out           = out;
    this.err           = err;
  }
@@ -172,12 +186,12 @@
                    EntryChangeNotificationControl ecn =
                         EntryChangeNotificationControl.decodeControl(
                              c.getControl());
                    System.out.println("# Persistent Search Change Type:  " +
                    out.println("# Persistent Search Change Type:  " +
                                       ecn.getChangeType().toString());
                    DN previousDN = ecn.getPreviousDN();
                    if (previousDN != null)
                    {
                      System.out.println("# Persistent Search Previous DN:  " +
                      out.println("# Persistent Search Previous DN:  " +
                                         previousDN.toString());
                    }
                  } catch (Exception e) {}
@@ -189,49 +203,49 @@
                    AccountUsableResponseControl acrc =
                         AccountUsableResponseControl.decodeControl(
                              c.getControl());
                    System.out.println("# Account Usable Response Control");
                    out.println("# Account Usable Response Control");
                    if (acrc.isUsable())
                    {
                      System.out.println("#   Account is usable");
                      out.println("#   Account is usable");
                      if (acrc.getSecondsBeforeExpiration() > 0)
                      {
                        int    timeToExp    = acrc.getSecondsBeforeExpiration();
                        String timeToExpStr = secondsToTimeString(timeToExp);
                        System.out.println("#   Time until expiration:  " +
                        out.println("#   Time until expiration:  " +
                                           timeToExpStr);
                      }
                    }
                    else
                    {
                      System.out.println("#   Account is not usable");
                      out.println("#   Account is not usable");
                      if (acrc.isInactive())
                      {
                        System.out.println("#   Account is inactive");
                        out.println("#   Account is inactive");
                      }
                      if (acrc.isReset())
                      {
                        System.out.println("#   Password has been reset");
                        out.println("#   Password has been reset");
                      }
                      if (acrc.isExpired())
                      {
                        System.out.println("#   Password is expired");
                        out.println("#   Password is expired");
                        if (acrc.getRemainingGraceLogins() > 0)
                        {
                          System.out.println("#   Grace logins remaining:  " +
                          out.println("#   Grace logins remaining:  " +
                                             acrc.getRemainingGraceLogins());
                        }
                      }
                      if (acrc.isLocked())
                      {
                        System.out.println("#   Account is locked");
                        out.println("#   Account is locked");
                        if (acrc.getSecondsBeforeUnlock() > 0)
                        {
                          int timeToUnlock = acrc.getSecondsBeforeUnlock();
                          String timeToUnlockStr =
                                      secondsToTimeString(timeToUnlock);
                          System.out.println("#   Time until automatic " +
                                             "unlock:  " + timeToUnlockStr);
                          out.println("#   Time until automatic unlock:  " +
                                      timeToUnlockStr);
                        }
                      }
                    }
@@ -243,13 +257,13 @@
                   responseMessage.getSearchResultEntryProtocolOp();
              StringBuilder sb = new StringBuilder();
              toLDIF(searchEntryOp, sb, wrapColumn, typesOnly);
              System.out.println(sb.toString());
              out.println(sb.toString());
              break;
            case OP_TYPE_SEARCH_RESULT_REFERENCE:
              SearchResultReferenceProtocolOp searchRefOp =
                   responseMessage.getSearchResultReferenceProtocolOp();
              System.out.println(searchRefOp.toString());
              out.println(searchRefOp.toString());
              break;
            case OP_TYPE_SEARCH_RESULT_DONE:
@@ -262,7 +276,7 @@
              // FIXME - throw exception?
              int msgID = MSGID_SEARCH_OPERATION_INVALID_PROTOCOL;
              String msg = getMessage(msgID, opType);
              System.err.println(msg);
              err.println(msg);
              break;
          }
@@ -277,8 +291,8 @@
          }
          else if (errorMessage != null)
          {
            System.out.println();
            System.out.println(errorMessage);
            out.println();
            out.println(errorMessage);
          }
        } while(opType != OP_TYPE_SEARCH_RESULT_DONE);
@@ -430,7 +444,7 @@
  public static void main(String[] args)
  {
    int retCode = mainSearch(args);
    int retCode = mainSearch(args, true, System.out, System.err);
    if(retCode != 0)
    {
@@ -449,6 +463,49 @@
  public static int mainSearch(String[] args)
  {
    return mainSearch(args, true, System.out, System.err);
  }
  /**
   * Parses the provided command-line arguments and uses that information to
   * run the ldapsearch tool.
   *
   * @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 The error code.
   */
  public static int mainSearch(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);
    }
    LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions();
    LDAPSearchOptions searchOptions = new LDAPSearchOptions();
    LDAPConnection connection = null;
@@ -572,7 +629,7 @@
      showUsage = new BooleanArgument("showUsage", 'H', "help",
                                    MSGID_DESCRIPTION_SHOWUSAGE);
      argParser.addArgument(showUsage);
      argParser.setUsageArgument(showUsage);
      argParser.setUsageArgument(showUsage, out);
      controlStr = new StringArgument("controls", 'J', "controls", false,
                false, true,
                "{controloid[:criticality[:value|::b64value|:<fileurl]]}",
@@ -647,7 +704,7 @@
      int    msgID   = MSGID_ENCPW_CANNOT_INITIALIZE_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      System.err.println(message);
      err.println(message);
      return 1;
    }
@@ -661,8 +718,8 @@
      int    msgID   = MSGID_ENCPW_ERROR_PARSING_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      System.err.println(message);
      System.err.println(argParser.getUsage());
      err.println(message);
      err.println(argParser.getUsage());
      return 1;
    }
@@ -683,7 +740,7 @@
      } catch(LDAPException le)
      {
        assert debugException(CLASS_NAME, "main", le);
        System.err.println(le.getMessage());
        err.println(le.getMessage());
        return 1;
      }
      // The rest are attributes
@@ -696,7 +753,7 @@
    if(bindPassword.isPresent() && bindPasswordFile.isPresent())
    {
      System.err.println("ERROR: Both -w and -j flags specified. " +
      err.println("ERROR: Both -w and -j flags specified. " +
                          "Please specify one.");
      return 1;
    }
@@ -709,7 +766,7 @@
    } catch(ArgumentException ae)
    {
      assert debugException(CLASS_NAME, "main", ae);
      System.err.println(ae.getMessage());
      err.println(ae.getMessage());
      return 1;
    }
@@ -720,14 +777,14 @@
      if(versionNumber != 2 && versionNumber != 3)
      {
        int msgID = MSGID_DESCRIPTION_INVALID_VERSION;
        System.err.println(getMessage(msgID, versionNumber));
        err.println(getMessage(msgID, versionNumber));
        return 1;
      }
      connectionOptions.setVersionNumber(versionNumber);
    } catch(ArgumentException ae)
    {
      assert debugException(CLASS_NAME, "main", ae);
      System.err.println(ae.getMessage());
      err.println(ae.getMessage());
      return 1;
    }
@@ -748,14 +805,13 @@
      // read the password from the stdin.
      try
      {
        System.out.print(getMessage(MSGID_LDAPAUTH_PASSWORD_PROMPT,
                                    bindDNValue));
        out.print(getMessage(MSGID_LDAPAUTH_PASSWORD_PROMPT, bindDNValue));
        char[] pwChars = PasswordReader.readPassword();
        bindPasswordValue = new String(pwChars);
      } catch(Exception ex)
      {
        assert debugException(CLASS_NAME, "main", ex);
        System.err.println(ex.getMessage());
        err.println(ex.getMessage());
        return 1;
      }
    } else if(bindPasswordValue == null)
@@ -780,7 +836,7 @@
      searchOptions.setSizeLimit(sizeLimit.getIntValue());
    } catch(ArgumentException ex1)
    {
      System.err.println(ex1.getMessage());
      err.println(ex1.getMessage());
      return 1;
    }
    boolean val = searchOptions.setSearchScope(searchScope.getValue());
@@ -800,8 +856,8 @@
      LDAPControl ctrl = LDAPToolUtils.getControl(ctrlString);
      if(ctrl == null)
      {
        System.err.println("Invalid control specified:" + ctrlString);
        System.out.println(argParser.getUsage());
        err.println("Invalid control specified:" + ctrlString);
        err.println(argParser.getUsage());
        return 1;
      }
      searchOptions.getControls().add(ctrl);
@@ -831,7 +887,7 @@
      {
        int    msgID   = MSGID_PSEARCH_MISSING_DESCRIPTOR;
        String message = getMessage(msgID);
        System.err.println(message);
        err.println(message);
        return 1;
      }
      else
@@ -841,7 +897,7 @@
        {
          int    msgID   = MSGID_PSEARCH_DOESNT_START_WITH_PS;
          String message = getMessage(msgID, String.valueOf(infoString));
          System.err.println(message);
          err.println(message);
          return 1;
        }
      }
@@ -880,7 +936,7 @@
          {
            int    msgID   = MSGID_PSEARCH_INVALID_CHANGE_TYPE;
            String message = getMessage(msgID, String.valueOf(token));
            System.err.println(message);
            err.println(message);
            return 1;
          }
        }
@@ -910,7 +966,7 @@
        {
          int    msgID   = MSGID_PSEARCH_INVALID_CHANGESONLY;
          String message = getMessage(msgID, String.valueOf(token));
          System.err.println(message);
          err.println(message);
          return 1;
        }
      }
@@ -931,7 +987,7 @@
        {
          int    msgID   = MSGID_PSEARCH_INVALID_RETURN_ECS;
          String message = getMessage(msgID, String.valueOf(token));
          System.err.println(message);
          err.println(message);
          return 1;
        }
      }
@@ -958,7 +1014,7 @@
      }
      catch (LDAPException le)
      {
        System.err.println(getMessage(MSGID_LDAP_ASSERTION_INVALID_FILTER,
        err.println(getMessage(MSGID_LDAP_ASSERTION_INVALID_FILTER,
                                      le.getMessage()));
        return 1;
      }
@@ -978,7 +1034,7 @@
        }
        catch (LDAPException le)
        {
          System.err.println(getMessage(MSGID_LDAP_MATCHEDVALUES_INVALID_FILTER,
          err.println(getMessage(MSGID_LDAP_MATCHEDVALUES_INVALID_FILTER,
                                        le.getMessage()));
          return 1;
        }
@@ -1019,13 +1075,13 @@
    {
      if(!connectionOptions.useSSL() && !connectionOptions.useStartTLS())
      {
        System.err.println("SASL External requires either SSL or StartTLS " +
        err.println("SASL External requires either SSL or StartTLS " +
                           "options to be requested.");
        return 1;
      }
      if(keyStorePathValue == null)
      {
        System.err.println("SASL External requires a path to the SSL " +
        err.println("SASL External requires a path to the SSL " +
                           "client certificate keystore.");
        return 1;
      }
@@ -1053,7 +1109,7 @@
      } catch(Exception e)
      {
        assert debugException(CLASS_NAME, "main", e);
        System.err.println(e.getMessage());
        err.println(e.getMessage());
        return 1;
      }
      finally
@@ -1072,8 +1128,8 @@
    if(filters.isEmpty())
    {
      int msgid = MSGID_SEARCH_NO_FILTERS;
      System.err.println(getMessage(msgid));
      System.err.println(argParser.getUsage());
      err.println(getMessage(msgid));
      err.println(argParser.getUsage());
      return 1;
    }
@@ -1085,8 +1141,11 @@
    try
    {
      if (initializeServer)
      {
      // Bootstrap and initialize directory data structures.
      DirectoryServer.bootstrapClient();
      }
      // Connect to the specified host with the supplied userDN and password.
      SSLConnectionFactory sslConnectionFactory = null;
@@ -1101,29 +1160,29 @@
      AtomicInteger nextMessageID = new AtomicInteger(1);
      connection = new LDAPConnection(hostNameValue, portNumber,
                                      connectionOptions);
                                      connectionOptions, out, err);
      connection.connectToHost(bindDNValue, bindPasswordValue, nextMessageID);
      LDAPSearch ldapSearch = new LDAPSearch(nextMessageID);
      LDAPSearch ldapSearch = new LDAPSearch(nextMessageID, out, err);
      ldapSearch.executeSearch(connection, baseDNValue, filters, attributes,
                               searchOptions, wrapColumn);
    } catch(LDAPException le)
    {
      assert debugException(CLASS_NAME, "main", le);
      System.err.println(le.getMessage());
      err.println(le.getMessage());
      int code = le.getResultCode();
      return code;
    } catch(LDAPConnectionException lce)
    {
        assert debugException(CLASS_NAME, "main", lce);
        System.err.println(lce.getMessage());
        err.println(lce.getMessage());
        int code = lce.getErrorCode();
        return code;
    } catch(Exception e)
    {
      assert debugException(CLASS_NAME, "main", e);
      System.err.println(e.getMessage());
      err.println(e.getMessage());
      return 1;
    } finally
    {
opends/src/server/org/opends/server/tools/StopDS.java
@@ -29,6 +29,8 @@
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
@@ -54,6 +56,7 @@
import org.opends.server.protocols.ldap.LDAPResultCode;
import org.opends.server.tasks.ShutdownTask;
import org.opends.server.types.Control;
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;
@@ -90,7 +93,7 @@
   */
  public static void main(String[] args)
  {
    int result = stopDS(args);
    int result = stopDS(args, System.out, System.err);
    if (result != LDAPResultCode.SUCCESS)
    {
@@ -112,6 +115,49 @@
   */
  public static int stopDS(String[] args)
  {
    return stopDS(args, System.out, System.err);
  }
  /**
   * Parses the provided set of command-line arguments and attempts to contact
   * the Directory Server in order to send it the shutdown request.
   *
   * @param  args       The command-line arguments provided to this program.
   * @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  An integer value that indicates whether the shutdown request was
   *          accepted by the Directory Server.  A nonzero value should be
   *          interpreted as a failure of some kind.
   */
  public static int stopDS(String[] args, 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 all the arguments that may be used with this program.
    ArgumentParser    argParser = new ArgumentParser(CLASS_NAME, false);
    BooleanArgument   restart;
@@ -240,14 +286,14 @@
      showUsage = new BooleanArgument("showusage", 'H', "help",
                                      MSGID_STOPDS_DESCRIPTION_SHOWUSAGE);
      argParser.addArgument(showUsage);
      argParser.setUsageArgument(showUsage);
      argParser.setUsageArgument(showUsage, out);
    }
    catch (ArgumentException ae)
    {
      int    msgID   = MSGID_STOPDS_CANNOT_INITIALIZE_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      System.err.println(message);
      err.println(message);
      return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR;
    }
@@ -262,8 +308,8 @@
      int    msgID   = MSGID_STOPDS_ERROR_PARSING_ARGS;
      String message = getMessage(msgID, ae.getMessage());
      System.err.println(message);
      System.err.println(argParser.getUsage());
      err.println(message);
      err.println(argParser.getUsage());
      return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR;
    }
@@ -283,7 +329,7 @@
      int    msgID   = MSGID_STOPDS_MUTUALLY_EXCLUSIVE_ARGUMENTS;
      String message = getMessage(msgID, bindPW.getLongIdentifier(),
                                  bindPWFile.getLongIdentifier());
      System.err.println(message);
      err.println(message);
      return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR;
    }
@@ -295,7 +341,7 @@
      int    msgID   = MSGID_STOPDS_MUTUALLY_EXCLUSIVE_ARGUMENTS;
      String message = getMessage(msgID, keyStorePW.getLongIdentifier(),
                                  keyStorePWFile.getLongIdentifier());
      System.err.println(message);
      err.println(message);
      return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR;
    }
@@ -307,7 +353,7 @@
      int    msgID   = MSGID_STOPDS_MUTUALLY_EXCLUSIVE_ARGUMENTS;
      String message = getMessage(msgID, trustStorePW.getLongIdentifier(),
                                  trustStorePWFile.getLongIdentifier());
      System.err.println(message);
      err.println(message);
      return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR;
    }
@@ -332,7 +378,7 @@
        {
          int    msgID   = MSGID_STOPDS_CANNOT_DECODE_STOP_TIME;
          String message = getMessage(msgID);
          System.err.println(message);
          err.println(message);
          return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR;
        }
      }
@@ -350,7 +396,7 @@
        {
          int    msgID   = MSGID_STOPDS_CANNOT_DECODE_STOP_TIME;
          String message = getMessage(msgID);
          System.err.println(message);
          err.println(message);
          return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR;
        }
      }
@@ -373,7 +419,7 @@
        int    msgID   = MSGID_STOPDS_MUTUALLY_EXCLUSIVE_ARGUMENTS;
        String message = getMessage(msgID, useSSL.getLongIdentifier(),
                                    useStartTLS.getLongIdentifier());
        System.err.println(message);
        err.println(message);
        return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR;
      }
      else
@@ -405,7 +451,7 @@
      {
        int    msgID   = MSGID_STOPDS_CANNOT_INITIALIZE_SSL;
        String message = getMessage(msgID, sce.getMessage());
        System.err.println(message);
        err.println(message);
        return LDAPResultCode.CLIENT_SIDE_LOCAL_ERROR;
      }
    }
@@ -425,7 +471,7 @@
        {
          int    msgID   = MSGID_STOPDS_CANNOT_PARSE_SASL_OPTION;
          String message = getMessage(msgID, s);
          System.err.println(message);
          err.println(message);
          return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR;
        }
        else
@@ -448,7 +494,7 @@
      {
        int    msgID   = MSGID_STOPDS_NO_SASL_MECHANISM;
        String message = getMessage(msgID);
        System.err.println(message);
        err.println(message);
        return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR;
      }
@@ -467,7 +513,7 @@
    try
    {
      connection = new LDAPConnection(host.getValue(), port.getIntValue(),
                                      connectionOptions);
                                      connectionOptions, out, err);
      connection.connectToHost(bindDN.getValue(), bindPW.getValue(),
                               nextMessageID);
    }
@@ -476,14 +522,14 @@
      int    msgID   = MSGID_STOPDS_CANNOT_DETERMINE_PORT;
      String message = getMessage(msgID, port.getLongIdentifier(),
                                  ae.getMessage());
      System.err.println(message);
      err.println(message);
      return LDAPResultCode.CLIENT_SIDE_PARAM_ERROR;
    }
    catch (LDAPConnectionException lce)
    {
      int    msgID   = MSGID_STOPDS_CANNOT_CONNECT;
      String message = getMessage(msgID, lce.getMessage());
      System.err.println(message);
      err.println(message);
      return LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR;
    }
@@ -567,7 +613,7 @@
      {
        int    msgID   = MSGID_STOPDS_UNEXPECTED_CONNECTION_CLOSURE;
        String message = getMessage(msgID);
        System.err.println(message);
        err.println(message);
        return LDAPResultCode.CLIENT_SIDE_SERVER_DOWN;
      }
@@ -577,21 +623,21 @@
    {
      int    msgID   = MSGID_STOPDS_IO_ERROR;
      String message = getMessage(msgID, String.valueOf(ioe));
      System.err.println(message);
      err.println(message);
      return LDAPResultCode.CLIENT_SIDE_SERVER_DOWN;
    }
    catch (ASN1Exception ae)
    {
      int    msgID   = MSGID_STOPDS_DECODE_ERROR;
      String message = getMessage(msgID, ae.getMessage());
      System.err.println(message);
      err.println(message);
      return LDAPResultCode.CLIENT_SIDE_DECODING_ERROR;
    }
    catch (LDAPException le)
    {
      int    msgID   = MSGID_STOPDS_DECODE_ERROR;
      String message = getMessage(msgID, le.getMessage());
      System.err.println(message);
      err.println(message);
      return LDAPResultCode.CLIENT_SIDE_DECODING_ERROR;
    }
@@ -613,7 +659,7 @@
          String message = extendedResponse.getErrorMessage();
          if (message != null)
          {
            System.err.println(message);
            err.println(message);
          }
          return extendedResponse.getResultCode();
@@ -623,7 +669,7 @@
      int    msgID   = MSGID_STOPDS_INVALID_RESPONSE_TYPE;
      String message = getMessage(msgID, responseMessage.getProtocolOpName());
      System.err.println(message);
      err.println(message);
      return LDAPResultCode.CLIENT_SIDE_LOCAL_ERROR;
    }
@@ -633,7 +679,7 @@
    String errorMessage = addResponse.getErrorMessage();
    if (errorMessage != null)
    {
      System.err.println(errorMessage);
      err.println(errorMessage);
    }
    return addResponse.getResultCode();
opends/src/server/org/opends/server/types/NullOutputStream.java
New file
@@ -0,0 +1,152 @@
/*
 * 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.types;
import java.io.OutputStream;
import java.io.PrintStream;
/**
 * This class defines a custom output stream that simply discards any
 * data written to it.
 */
public class NullOutputStream
       extends OutputStream
{
  /**
   * The singleton instance for this class.
   */
  private static final NullOutputStream instance =
       new NullOutputStream();
  /**
   * The singleton print stream tied to the null output stream.
   */
  private static final PrintStream printStream =
       new PrintStream(instance);
  /**
   * Retrieves an instance of this null output stream.
   *
   * @return  An instance of this null output stream.
   */
  public static NullOutputStream instance()
  {
    return instance;
  }
  /**
   * Retrieves a print stream using this null output stream.
   *
   * @return  A print stream using this null output stream.
   */
  public static PrintStream printStream()
  {
    return printStream;
  }
  /**
   * Creates a new instance of this null output stream.
   */
  private NullOutputStream()
  {
    // No implementation is required.
  }
  /**
   * Closes the output stream.  This has no effect.
   */
  public void close()
  {
    // No implementation is required.
  }
  /**
   * Flushes the output stream.  This has no effect.
   */
  public void flush()
  {
    // No implementation is required.
  }
  /**
   * Writes the provided data to this output stream.  This has no
   * effect.
   *
   * @param  b  The byte array containing the data to be written.
   */
  public void write(byte[] b)
  {
    // No implementation is required.
  }
  /**
   * Writes the provided data to this output stream.  This has no
   * effect.
   *
   * @param  b    The byte array containing the data to be written.
   * @param  off  The offset at which the real data begins.
   * @param  len  The number of bytes to be written.
   */
  public void write(byte[] b, int off, int len)
  {
    // No implementation is required.
  }
  /**
   * Writes the provided byte to this output stream.  This has no
   * effect.
   *
   * @param  b  The byte to be written.
   */
  public void write(int b)
  {
    // No implementation is required.
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java
@@ -41,6 +41,7 @@
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.ldap.LDAPFilter;
import org.opends.server.tools.LDAPSearch;
import org.opends.server.types.AuthenticationInfo;
import org.opends.server.types.ByteString;
import org.opends.server.types.DN;
@@ -413,6 +414,34 @@
  /**
   * Ensures that SASL PLAIN authentication works over LDAP as well as via the
   * internal protocol.  The authentication will be performed as the root user.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testSASLPlainOverLDAP()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=dn:cn=Directory Manager",
      "-w", "password",
      "-b", "",
      "-s", "base",
      "(objectClass=*)",
      "1.1"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, null), 0);
  }
  /**
   * Retrieves sets of invalid credentials that will not succeed when using
   * SASL PLAIN.
   *