From 940c033c4446ed6e09ebe45be25e2cf85c9321be Mon Sep 17 00:00:00 2001
From: Ludovic Poitou <ludovic.poitou@forgerock.com>
Date: Mon, 18 Oct 2010 19:41:47 +0000
Subject: [PATCH] Update from OpenDS sdk by Bo Li: Added unmodifiable and copyOf request factories. Added authrate performance utility.

---
 opendj-sdk/sdk/src/org/opends/sdk/requests/AddRequestImpl.java                                |   19 
 opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyRequestImpl.java                             |   21 
 opendj-sdk/sdk/src/org/opends/sdk/requests/PlainSASLBindRequestImpl.java                      |   23 
 opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractBindRequest.java                           |   18 
 opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnectionFactoryImpl.java                     |   10 
 opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ConnectionFactoryProvider.java                    |  432 ++--
 opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractRequestImpl.java                           |   18 
 opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequestImpl.java                   |   51 
 opendj-sdk/sdk/src/org/opends/sdk/requests/DeleteRequestImpl.java                             |   20 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiablePlainSASLBindRequestImpl.java          |   83 
 opendj-sdk/sdk/src/org/opends/sdk/requests/GenericExtendedRequestImpl.java                    |   22 
 opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/ConnectionFactoryTestCase.java      |    3 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableSearchRequestImpl.java                 |  132 +
 opendj-sdk/sdk/resource/bin/authrate                                                          |   37 
 opendj-sdk/sdk/src/org/opends/sdk/LDAPOptions.java                                            |   43 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableCRAMMD5SASLBindRequestImpl.java        |   71 
 opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyDNRequestImpl.java                           |   23 
 opendj-sdk/sdk/src/org/opends/sdk/requests/Requests.java                                      |  785 ++++++++
 opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPModify.java                                   |   11 
 opendj-sdk/sdk/src/com/sun/opends/sdk/tools/PerformanceRunner.java                            |   66 
 opendj-sdk/sdk/src/org/opends/sdk/requests/PlainSASLBindRequest.java                          |   11 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableCancelExtendedRequestImpl.java         |   53 
 opendj-sdk/sdk/src/org/opends/sdk/requests/CancelExtendedRequestImpl.java                     |   18 
 opendj-sdk/sdk/src/org/opends/sdk/requests/PasswordModifyExtendedRequest.java                 |   36 
 opendj-sdk/sdk/src/org/opends/sdk/requests/AbandonRequestImpl.java                            |   19 
 opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequest.java                   |    8 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableSimpleBindRequestImpl.java             |   65 
 opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPPasswordModify.java                           |    9 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableCompareRequestImpl.java                |   95 +
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableDigestMD5SASLBindRequestImpl.java      |  165 +
 opendj-sdk/sdk/src/org/opends/sdk/requests/AnonymousSASLBindRequest.java                      |    8 
 opendj-sdk/sdk/src/com/sun/opends/sdk/tools/AuthRate.java                                     |  735 ++++++++
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableGenericBindRequestImpl.java            |   61 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnbindRequestImpl.java                             |   19 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableStartTLSExtendedRequestImpl.java       |   71 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableDeleteRequestImpl.java                 |   63 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableModifyRequestImpl.java                 |   85 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableGenericExtendedRequestImpl.java        |   54 
 opendj-sdk/sdk/src/org/opends/sdk/requests/PasswordModifyExtendedRequestImpl.java             |   21 
 opendj-sdk/sdk/src/org/opends/sdk/requests/GSSAPISASLBindRequest.java                         |    6 
 opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractExtendedRequest.java                       |   19 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAnonymousSASLBindRequestImpl.java      |   23 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableWhoAmIExtendedRequestImpl.java         |   19 
 opendj-sdk/sdk/src/org/opends/sdk/requests/WhoAmIExtendedRequestImpl.java                     |   18 
 opendj-sdk/sdk/src/org/opends/sdk/requests/ExternalSASLBindRequest.java                       |    5 
 opendj-sdk/sdk/src/org/opends/sdk/requests/CompareRequestImpl.java                            |   22 
 opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableExtendedRequest.java           |   68 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableExternalSASLBindRequestImpl.java       |   53 
 opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java                                |   36 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiablePasswordModifyExtendedRequestImpl.java |   96 +
 opendj-sdk/sdk/src/org/opends/sdk/requests/GenericBindRequestImpl.java                        |   24 
 opendj-sdk/sdk/resource/bin/authrate.bat                                                      |   33 
 opendj-sdk/sdk/src/org/opends/sdk/requests/SearchRequestImpl.java                             |   32 
 opendj-sdk/sdk/src/org/opends/sdk/requests/DigestMD5SASLBindRequestImpl.java                  |   34 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableModifyDNRequestImpl.java               |  103 +
 opendj-sdk/sdk/src/org/opends/sdk/requests/AnonymousSASLBindRequestImpl.java                  |   20 
 opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequest.java                       |   31 
 opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPCompare.java                                  |   11 
 opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableSASLBindRequest.java           |   22 
 opendj-sdk/sdk/src/org/opends/sdk/requests/ExternalSASLBindRequestImpl.java                   |   21 
 opendj-sdk/sdk/src/com/sun/opends/sdk/tools/SearchRate.java                                   |   33 
 opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ModRate.java                                      |   31 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAddRequestImpl.java                    |  201 ++
 opendj-sdk/sdk/src/org/opends/sdk/requests/CRAMMD5SASLBindRequest.java                        |    8 
 /dev/null                                                                                     |  439 ----
 opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractSASLBindRequest.java                       |   17 
 opendj-sdk/sdk/src/org/opends/sdk/requests/CRAMMD5SASLBindRequestImpl.java                    |   22 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableUnbindRequestImpl.java                 |   16 
 opendj-sdk/sdk/src/org/opends/sdk/requests/GSSAPISASLBindRequestImpl.java                     |   37 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableGSSAPISASLBindRequestImpl.java         |  175 +
 opendj-sdk/sdk/src/com/sun/opends/sdk/messages/messages.properties                            |   16 
 opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPSearch.java                                   |   11 
 opendj-sdk/sdk/src/org/opends/sdk/requests/SimpleBindRequestImpl.java                         |   21 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAbandonRequestImpl.java                |   27 
 opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractaUnmodifiableBindRequest.java              |   58 
 75 files changed, 4,435 insertions(+), 857 deletions(-)

diff --git a/opendj-sdk/sdk/examples/org/opends/sdk/examples/DummyServer.java b/opendj-sdk/sdk/examples/org/opends/sdk/examples/DummyServer.java
deleted file mode 100644
index 8c924bc..0000000
--- a/opendj-sdk/sdk/examples/org/opends/sdk/examples/DummyServer.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * 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
- *
- *
- *      Copyright 2010 Sun Microsystems, Inc.
- */
-
-package org.opends.sdk.examples;
-
-
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.security.KeyStore;
-
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-
-import org.opends.sdk.*;
-import org.opends.sdk.requests.*;
-import org.opends.sdk.responses.*;
-
-
-
-/**
- * A simple dummy server that just returns one entry.
- */
-public class DummyServer implements
-    ServerConnectionFactory<LDAPClientContext, Integer>
-{
-
-  private static final class DummyServerConnection implements
-      ServerConnection<Integer>
-  {
-    private final LDAPClientContext clientContext;
-
-
-
-    private DummyServerConnection(final LDAPClientContext clientContext)
-    {
-      this.clientContext = clientContext;
-    }
-
-
-
-    @Override
-    public void handleAbandon(final Integer context,
-        final AbandonRequest request) throws UnsupportedOperationException
-    {
-    }
-
-
-
-    @Override
-    public void handleAdd(final Integer context, final AddRequest request,
-        final ResultHandler<? super Result> handler,
-        final IntermediateResponseHandler intermediateResponseHandler)
-        throws UnsupportedOperationException
-    {
-    }
-
-
-
-    @Override
-    public void handleBind(final Integer context, final int version,
-        final BindRequest request,
-        final ResultHandler<? super BindResult> resultHandler,
-        final IntermediateResponseHandler intermediateResponseHandler)
-        throws UnsupportedOperationException
-    {
-      resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS));
-    }
-
-
-
-    @Override
-    public void handleCompare(final Integer context,
-        final CompareRequest request,
-        final ResultHandler<? super CompareResult> resultHandler,
-        final IntermediateResponseHandler intermediateResponseHandler)
-        throws UnsupportedOperationException
-    {
-    }
-
-
-
-    @Override
-    public void handleConnectionClosed(final Integer context,
-        final UnbindRequest request)
-    {
-      System.out.println(request);
-    }
-
-
-
-    @Override
-    public void handleConnectionException(final Throwable error)
-    {
-      System.out.println(error);
-    }
-
-
-
-    @Override
-    public void handleDelete(final Integer context,
-        final DeleteRequest request,
-        final ResultHandler<? super Result> handler,
-        final IntermediateResponseHandler intermediateResponseHandler)
-        throws UnsupportedOperationException
-    {
-    }
-
-
-
-    @Override
-    public <R extends ExtendedResult> void handleExtendedRequest(
-        final Integer context, final ExtendedRequest<R> request,
-        final ResultHandler<? super R> resultHandler,
-        final IntermediateResponseHandler intermediateResponseHandler)
-        throws UnsupportedOperationException
-    {
-      if (request.getOID().equals(StartTLSExtendedRequest.OID))
-      {
-        final R result = request.getResultDecoder().adaptExtendedErrorResult(
-            ResultCode.SUCCESS, "", "");
-        resultHandler.handleResult(result);
-        clientContext.startTLS(sslContext, null, null, false, false);
-      }
-    }
-
-
-
-    @Override
-    public void handleModify(final Integer context,
-        final ModifyRequest request,
-        final ResultHandler<? super Result> resultHandler,
-        final IntermediateResponseHandler intermediateResponseHandler)
-        throws UnsupportedOperationException
-    {
-    }
-
-
-
-    @Override
-    public void handleModifyDN(final Integer context,
-        final ModifyDNRequest request,
-        final ResultHandler<? super Result> resultHandler,
-        final IntermediateResponseHandler intermediateResponseHandler)
-        throws UnsupportedOperationException
-    {
-    }
-
-
-
-    @Override
-    public void handleSearch(final Integer context,
-        final SearchRequest request,
-        final ResultHandler<? super Result> resultHandler,
-        final SearchResultHandler searchResulthandler,
-        final IntermediateResponseHandler intermediateResponseHandler)
-        throws UnsupportedOperationException
-    {
-      searchResulthandler.handleEntry(ENTRY);
-      resultHandler.handleResult(RESULT);
-    }
-  }
-
-
-
-  private static final SearchResultEntry ENTRY = Responses
-      .newSearchResultEntry(
-          "dn: uid=user.6901,ou=People,dc=example,dc=com",
-          "objectClass: person",
-          "objectClass: inetorgperson",
-          "objectClass: organizationalperson",
-          "objectClass: top",
-          "cn: Romy Ledet",
-          "description: This is the description for Romy Ledet.",
-          "employeeNumber: 6901",
-          "givenName: Romy",
-          "homePhone: ,1 060 737 0385",
-          "initials: RRL",
-          "l: Hampton Roads",
-          "mail: user.6901@example.com",
-          "mobile: ,1 101 041 2007",
-          "pager: ,1 508 271 7836",
-          "postalAddress: Romy Ledet$08019 Dogwood Street$Hampton Roads, MD  55656",
-          "postalCode: 55656", "sn: Ledet", "st: MD",
-          "street: 08019 Dogwood Street", "telephoneNumber: ,1 361 352 6603",
-          "uid: user.6901",
-          "userPassword: {SSHA}CIieVowKJtlbNMzaVK8cluycDU20b,YXYYszFA==");
-  private static final BindResult RESULT = Responses
-      .newBindResult(ResultCode.SUCCESS);
-
-  private static SSLContext sslContext;
-
-
-
-  /**
-   * Dummy LDAP server implementation.
-   *
-   * @param args
-   *          Command line arguments (ignored).
-   * @throws Exception
-   *           If an error occurred.
-   */
-  public static void main(final String[] args) throws Exception
-  {
-    KeyManagerFactory kmf;
-    KeyStore ks;
-    final char[] storepass = "newpass".toCharArray();
-    final char[] keypass = "wshr.ut".toCharArray();
-    final String storename = "newstore";
-
-    sslContext = SSLContext.getInstance("TLS");
-    kmf = KeyManagerFactory.getInstance("SunX509");
-    final FileInputStream fin = new FileInputStream(storename);
-    ks = KeyStore.getInstance("JKS");
-    ks.load(fin, storepass);
-
-    kmf.init(ks, keypass);
-    sslContext.init(kmf.getKeyManagers(), null, null);
-    final LDAPListenerOptions options = new LDAPListenerOptions()
-        .setBacklog(4096);
-
-    LDAPListener listener = null;
-    try
-    {
-      listener = new LDAPListener(11389, new DummyServer(), options);
-      System.out.println("Press any key to stop the server...");
-      System.in.read();
-    }
-    catch (final IOException e)
-    {
-      System.out.println("Error listening to port 11389");
-      e.printStackTrace();
-    }
-    finally
-    {
-      if (listener != null)
-      {
-        listener.close();
-      }
-    }
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public ServerConnection<Integer> accept(final LDAPClientContext context)
-  {
-    System.out.println("Connection from: " + context.getPeerAddress());
-    return new DummyServerConnection(context);
-  }
-}
diff --git a/opendj-sdk/sdk/resource/bin/authrate b/opendj-sdk/sdk/resource/bin/authrate
new file mode 100644
index 0000000..a21440f
--- /dev/null
+++ b/opendj-sdk/sdk/resource/bin/authrate
@@ -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
+#
+#
+#      Copyright 2010 Sun Microsystems, Inc.
+
+
+# This script may be used to measure auth performance.
+OPENDS_INVOKE_CLASS="com.sun.opends.sdk.tools.AuthRate"
+export OPENDS_INVOKE_CLASS
+
+SCRIPT_NAME="authrate"
+export SCRIPT_NAME
+
+SCRIPT_DIR=`dirname "${0}"`
+"${SCRIPT_DIR}/../lib/_client-script.sh" "${@}"
diff --git a/opendj-sdk/sdk/resource/bin/authrate.bat b/opendj-sdk/sdk/resource/bin/authrate.bat
new file mode 100644
index 0000000..c8d5ffa
--- /dev/null
+++ b/opendj-sdk/sdk/resource/bin/authrate.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      Copyright 2010 Sun Microsystems, Inc.
+
+setlocal
+
+set OPENDS_INVOKE_CLASS="com.sun.opends.sdk.tools.AuthRate"
+set SCRIPT_NAME=authrate
+for %%i in (%~sf0) do call "%%~dPsi\..\lib\_client-script.bat" %*
+
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java
index dbe9ed3..79a1eb9 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package com.sun.opends.sdk.ldap;
@@ -35,6 +35,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.net.ssl.SSLContext;
@@ -77,7 +78,8 @@
 
   private final AtomicInteger nextMsgID = new AtomicInteger(1);
 
-  private boolean bindOrStartTLSInProgress = false;
+  private final AtomicBoolean bindOrStartTLSInProgress =
+      new AtomicBoolean(false);
 
   private final ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>> pendingRequests =
     new ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>>();
@@ -122,7 +124,7 @@
         return new CompletedFutureResult<Void>(
             ErrorResultException.wrap(connectionInvalidReason), messageID);
       }
-      if (bindOrStartTLSInProgress)
+      if (bindOrStartTLSInProgress.get())
       {
         final Result errorResult = Responses.newResult(
             ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
@@ -193,7 +195,7 @@
         future.adaptErrorResult(connectionInvalidReason);
         return future;
       }
-      if (bindOrStartTLSInProgress)
+      if (bindOrStartTLSInProgress.get())
       {
         future.setResultOrError(Responses
             .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
@@ -289,7 +291,7 @@
         future.adaptErrorResult(connectionInvalidReason);
         return future;
       }
-      if (bindOrStartTLSInProgress)
+      if (!bindOrStartTLSInProgress.compareAndSet(false, true))
       {
         future.setResultOrError(Responses.newBindResult(
             ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
@@ -305,7 +307,6 @@
       }
 
       pendingRequests.put(messageID, future);
-      bindOrStartTLSInProgress = true;
     }
 
     try
@@ -379,7 +380,7 @@
         future.adaptErrorResult(connectionInvalidReason);
         return future;
       }
-      if (bindOrStartTLSInProgress)
+      if (bindOrStartTLSInProgress.get())
       {
         future.setResultOrError(Responses.newCompareResult(
             ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
@@ -437,7 +438,7 @@
         future.adaptErrorResult(connectionInvalidReason);
         return future;
       }
-      if (bindOrStartTLSInProgress)
+      if (bindOrStartTLSInProgress.get())
       {
         future.setResultOrError(Responses
             .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
@@ -496,7 +497,7 @@
         future.adaptErrorResult(connectionInvalidReason);
         return future;
       }
-      if (bindOrStartTLSInProgress)
+      if (!bindOrStartTLSInProgress.compareAndSet(false, true))
       {
         future.setResultOrError(request.getResultDecoder()
             .newExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "",
@@ -518,7 +519,6 @@
               .newExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "",
                   "This connection is already TLS enabled"));
         }
-        bindOrStartTLSInProgress = true;
       }
       pendingRequests.put(messageID, future);
     }
@@ -591,7 +591,7 @@
         future.adaptErrorResult(connectionInvalidReason);
         return future;
       }
-      if (bindOrStartTLSInProgress)
+      if (bindOrStartTLSInProgress.get())
       {
         future.setResultOrError(Responses
             .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
@@ -649,7 +649,7 @@
         future.adaptErrorResult(connectionInvalidReason);
         return future;
       }
-      if (bindOrStartTLSInProgress)
+      if (bindOrStartTLSInProgress.get())
       {
         future.setResultOrError(Responses
             .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
@@ -719,7 +719,7 @@
         future.adaptErrorResult(connectionInvalidReason);
         return future;
       }
-      if (bindOrStartTLSInProgress)
+      if (bindOrStartTLSInProgress.get())
       {
         future.setResultOrError(Responses
             .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
@@ -996,13 +996,13 @@
 
   void setBindOrStartTLSInProgress(final boolean state)
   {
-    bindOrStartTLSInProgress = state;
+    bindOrStartTLSInProgress.set(state);
   }
 
 
 
   synchronized void startTLS(final SSLContext sslContext,
-      final String[] protocols, final String[] cipherSuites,
+      final List<String> protocols, final List<String> cipherSuites,
       final CompletionHandler<SSLEngine> completionHandler) throws IOException
   {
     if (isTLSEnabled())
@@ -1015,8 +1015,10 @@
 
     sslEngineConfigurator = new SSLEngineConfigurator(sslContext, true, false,
         false);
-    sslEngineConfigurator.setEnabledProtocols(protocols);
-    sslEngineConfigurator.setEnabledCipherSuites(cipherSuites);
+    sslEngineConfigurator.setEnabledProtocols(protocols.isEmpty() ?
+        null : protocols.toArray(new String[protocols.size()]));
+    sslEngineConfigurator.setEnabledCipherSuites(cipherSuites.isEmpty() ?
+        null : cipherSuites.toArray(new String[cipherSuites.size()]));
     sslFilter = new SSLFilter(null, sslEngineConfigurator);
     installFilter(sslFilter);
     sslFilter.handshake(connection, completionHandler);
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnectionFactoryImpl.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnectionFactoryImpl.java
index 9b9c24f..6610745 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnectionFactoryImpl.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnectionFactoryImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package com.sun.opends.sdk.ldap;
@@ -126,8 +126,12 @@
           {
             final StartTLSExtendedRequest startTLS = Requests
                 .newStartTLSExtendedRequest(options.getSSLContext());
-            startTLS.setEnabledCipherSuites(options.getEnabledCipherSuites());
-            startTLS.setEnabledProtocols(options.getEnabledProtocols());
+            startTLS.addEnabledCipherSuite(
+                options.getEnabledCipherSuites().toArray(
+                    new String[options.getEnabledCipherSuites().size()]));
+            startTLS.addEnabledProtocol(
+                options.getEnabledProtocols().toArray(
+                    new String[options.getEnabledProtocols().size()]));
             return connection.extendedRequest(startTLS, handler);
           }
 
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/messages/messages.properties b/opendj-sdk/sdk/src/com/sun/opends/sdk/messages/messages.properties
index 6b0a3a1..1c85685 100755
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/messages/messages.properties
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/messages/messages.properties
@@ -1,3 +1,4 @@
+#
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
@@ -20,7 +21,9 @@
 #
 # CDDL HEADER END
 #
-#      Copyright 2009 Sun Microsystems, Inc.
+#
+#      Copyright 2010 Sun Microsystems, Inc.
+#
 
 
 
@@ -5852,5 +5855,16 @@
   modify throughput and response time of a directory service using \
   user-defined modifications
 INFO_MODRATE_TOOL_DESCRIPTION_TARGETDN=Target entry DN format string
+INFO_AUTHRATE_TOOL_DESCRIPTION=This utility can be used to measure \
+  bind throughput and response time of a directory service using \
+  user-defined bind or search-then-bind operations. Format strings may be \
+  used in the bind DN option as well as the authid and authzid SASL bind \
+  options. A search operation may be used to retrieve the bind DN by \
+  specifying the base DN and a filter. The retrieved entry DN will be appended \
+  as the last argument in the argument list when evaluating format strings. \
+  For example, to measure simple bind performance using the retrieved user \
+  DN as the bind DN: authrate -D '%2$s' -p password -b "dc=example,dc=com" \
+  -g 'rand(0,10000)' '(user=user.%1$d)'
+
 
 
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/AuthRate.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/AuthRate.java
new file mode 100644
index 0000000..7965437
--- /dev/null
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/AuthRate.java
@@ -0,0 +1,735 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+import com.sun.opends.sdk.util.RecursiveFutureResult;
+import org.opends.sdk.*;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.BindResult;
+import org.opends.sdk.responses.SearchResultEntry;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.messages.Messages.ERR_ERROR_PARSING_ARGS;
+import static com.sun.opends.sdk.tools.ToolConstants.*;
+import static com.sun.opends.sdk.tools.ToolConstants.OPTION_LONG_BASEDN;
+import static com.sun.opends.sdk.tools.ToolConstants.OPTION_SHORT_BASEDN;
+import static com.sun.opends.sdk.tools.Utils.filterExitCode;
+
+/**
+ * A load generation tool that can be used to load a Directory Server with
+ * Bind requests using one or more LDAP connections.
+ */
+public final class AuthRate extends ConsoleApplication
+{
+  private final class BindPerformanceRunner extends PerformanceRunner
+  {
+    private final AtomicLong searchWaitRecentTime = new AtomicLong();
+    private final AtomicInteger invalidCredRecentCount = new AtomicInteger();
+
+    private final class BindStatsThread extends StatsThread
+    {
+      private final String[] extraColumn;
+
+
+
+      private BindStatsThread()
+      {
+        super(new String[] { "bind time %" });
+        extraColumn = new String[1];
+      }
+
+
+
+      @Override
+      String[] getAdditionalColumns()
+      {
+        invalidCredRecentCount.set(0);
+        final long searchWaitTime = searchWaitRecentTime.getAndSet(0);
+        extraColumn[0] = String.format("%.1f",
+            ((float)(waitTime - searchWaitTime) / waitTime) * 100.0);
+        return extraColumn;
+      }
+    }
+
+    private final class BindUpdateStatsResultHandler
+        extends UpdateStatsResultHandler<BindResult>
+    {
+      private BindUpdateStatsResultHandler(long eTime) {
+        super(eTime);
+      }
+
+      @Override
+      public void handleErrorResult(ErrorResultException error) {
+        if(error.getResult().getResultCode() != ResultCode.INVALID_CREDENTIALS)
+        {
+          super.handleErrorResult(error);
+        }
+        else
+        {
+          failedRecentCount.getAndIncrement();
+          invalidCredRecentCount.getAndIncrement();
+        }
+      }
+    }
+
+    private final class BindWorkerThread extends WorkerThread
+    {
+      private SearchRequest sr;
+      private BindRequest br;
+
+      private Object[] data;
+
+
+
+      private BindWorkerThread(final AsynchronousConnection connection,
+          final ConnectionFactory connectionFactory)
+      {
+        super(connection, connectionFactory);
+      }
+
+
+
+      @Override
+      public FutureResult<?> performOperation(
+          final AsynchronousConnection connection,
+          final DataSource[] dataSources, final long startTime)
+      {
+        if (dataSources != null)
+        {
+          data = DataSource.generateData(dataSources, data);
+          if(data.length == dataSources.length)
+          {
+            Object[] newData = new Object[data.length + 1];
+            System.arraycopy(data, 0, newData, 0, data.length);
+            data = newData;
+          }
+        }
+        if(filter != null && baseDN != null)
+        {
+          if (sr == null)
+          {
+            if (dataSources == null)
+            {
+              sr = Requests.newSearchRequest(baseDN, scope, filter, attributes);
+            }
+            else
+            {
+              sr = Requests.newSearchRequest(String.format(baseDN, data), scope,
+                  String.format(filter, data), attributes);
+            }
+            sr.setDereferenceAliasesPolicy(dereferencesAliasesPolicy);
+          }
+          else if (dataSources != null)
+          {
+            sr.setFilter(String.format(filter, data));
+            sr.setName(String.format(baseDN, data));
+          }
+
+          RecursiveFutureResult<SearchResultEntry, BindResult> future =
+              new RecursiveFutureResult<SearchResultEntry, BindResult>(
+                  new BindUpdateStatsResultHandler(startTime))
+              {
+                @Override
+                protected FutureResult<? extends BindResult> chainResult(
+                    SearchResultEntry innerResult,
+                    ResultHandler<? super BindResult> resultHandler)
+                    throws ErrorResultException
+                {
+                  searchWaitRecentTime.getAndAdd(System.nanoTime() - startTime);
+                  if(data == null)
+                  {
+                    data = new Object[1];
+                  }
+                  data[data.length-1] = innerResult.getName().toString();
+                  return performBind(connection, data, resultHandler);
+                }
+              };
+          connection.searchSingleEntry(sr, future);
+          return future;
+        }
+        else
+        {
+          return performBind(connection, data,
+              new UpdateStatsResultHandler<BindResult>(startTime));
+        }
+      }
+
+      private FutureResult<BindResult> performBind(
+          final AsynchronousConnection connection,
+          final Object[] data,
+          final ResultHandler<? super BindResult> handler)
+      {
+        if(bindRequest instanceof SimpleBindRequest)
+        {
+          SimpleBindRequest o = (SimpleBindRequest)bindRequest;
+          if(br == null)
+          {
+            br = Requests.copyOfSimpleBindRequest(o);
+          }
+
+          SimpleBindRequest sbr = (SimpleBindRequest)br;
+          if (data != null && o.getName() != null)
+          {
+            sbr.setName(String.format(o.getName(), data));
+          }
+          if(successRecentCount.get() * ((float)invalidCredPercent/100) >
+              invalidCredRecentCount.get())
+          {
+            sbr.setPassword("invalid-password");
+          }
+          else
+          {
+            sbr.setPassword(o.getPassword());
+          }
+        }
+        else if(bindRequest instanceof DigestMD5SASLBindRequest)
+        {
+          DigestMD5SASLBindRequest o = (DigestMD5SASLBindRequest)bindRequest;
+          if(br == null)
+          {
+            br = Requests.copyOfDigestMD5SASLBindRequest(o);
+          }
+
+          DigestMD5SASLBindRequest sbr = (DigestMD5SASLBindRequest)br;
+          if (data != null)
+          {
+            if(o.getAuthenticationID() != null)
+            {
+              sbr.setAuthenticationID(
+                  String.format(o.getAuthenticationID(), data));
+            }
+            if(o.getAuthorizationID() != null)
+            {
+              sbr.setAuthorizationID(
+                  String.format(o.getAuthorizationID(), data));
+            }
+          }
+          if(successRecentCount.get() * ((float)invalidCredPercent/100) >
+              invalidCredRecentCount.get())
+          {
+            sbr.setPassword("invalid-password");
+          }
+          else
+          {
+            sbr.setPassword(o.getPassword());
+          }
+        }
+        else if(bindRequest instanceof CRAMMD5SASLBindRequest)
+        {
+          CRAMMD5SASLBindRequest o = (CRAMMD5SASLBindRequest)bindRequest;
+          if(br == null)
+          {
+            br = Requests.copyOfCRAMMD5SASLBindRequest(o);
+          }
+
+          CRAMMD5SASLBindRequest sbr = (CRAMMD5SASLBindRequest)br;
+          if (data != null && o.getAuthenticationID() != null)
+          {
+            sbr.setAuthenticationID(
+                String.format(o.getAuthenticationID(), data));
+          }
+          if(successRecentCount.get() * ((float)invalidCredPercent/100) >
+              invalidCredRecentCount.get())
+          {
+            sbr.setPassword("invalid-password");
+          }
+          else
+          {
+            sbr.setPassword(o.getPassword());
+          }
+        }
+        else if(bindRequest instanceof GSSAPISASLBindRequest)
+        {
+          GSSAPISASLBindRequest o = (GSSAPISASLBindRequest)bindRequest;
+          if(br == null)
+          {
+            br = Requests.copyOfGSSAPISASLBindRequest(o);
+          }
+
+          GSSAPISASLBindRequest sbr = (GSSAPISASLBindRequest)br;
+          if (data != null)
+          {
+            if(o.getAuthenticationID() != null)
+            {
+              sbr.setAuthenticationID(
+                  String.format(o.getAuthenticationID(), data));
+            }
+            if(o.getAuthorizationID() != null)
+            {
+              sbr.setAuthorizationID(
+                  String.format(o.getAuthorizationID(), data));
+            }
+          }
+          if(successRecentCount.get() * ((float)invalidCredPercent/100) >
+              invalidCredRecentCount.get())
+          {
+            sbr.setPassword("invalid-password");
+          }
+          else
+          {
+            sbr.setPassword(o.getPassword());
+          }
+        }
+        else if(bindRequest instanceof ExternalSASLBindRequest)
+        {
+          ExternalSASLBindRequest o = (ExternalSASLBindRequest)bindRequest;
+          if(br == null)
+          {
+            br = Requests.copyOfExternalSASLBindRequest(o);
+          }
+
+          ExternalSASLBindRequest sbr = (ExternalSASLBindRequest)br;
+          if (data != null && o.getAuthorizationID() != null)
+          {
+            sbr.setAuthorizationID(String.format(o.getAuthorizationID(), data));
+          }
+        }
+        else if(bindRequest instanceof PlainSASLBindRequest)
+        {
+          PlainSASLBindRequest o = (PlainSASLBindRequest)bindRequest;
+          if(br == null)
+          {
+            br = Requests.copyOfPlainSASLBindRequest(o);
+          }
+
+          PlainSASLBindRequest sbr = (PlainSASLBindRequest)br;
+          if (data != null)
+          {
+            if(o.getAuthenticationID() != null)
+            {
+              sbr.setAuthenticationID(
+                  String.format(o.getAuthenticationID(), data));
+            }
+            if(o.getAuthorizationID() != null)
+            {
+              sbr.setAuthorizationID(
+                  String.format(o.getAuthorizationID(), data));
+            }
+          }
+          if(successRecentCount.get() * ((float)invalidCredPercent/100) >
+              invalidCredRecentCount.get())
+          {
+            sbr.setPassword("invalid-password");
+          }
+          else
+          {
+            sbr.setPassword(o.getPassword());
+          }
+        }
+
+        return connection.bind(br, handler);
+      }
+    }
+
+
+
+    private String filter;
+
+    private String baseDN;
+
+    private SearchScope scope;
+
+    private DereferenceAliasesPolicy dereferencesAliasesPolicy;
+
+    private String[] attributes;
+
+    private BindRequest bindRequest;
+
+    private int invalidCredPercent;
+
+
+
+    private BindPerformanceRunner(final ArgumentParser argParser,
+        final ConsoleApplication app) throws ArgumentException
+    {
+      super(argParser, app, true, true, true);
+    }
+
+
+
+    @Override
+    StatsThread newStatsThread()
+    {
+      if(filter != null && baseDN != null)
+      {
+        return new BindStatsThread();
+      }
+      return new StatsThread(new String[0]);
+    }
+
+
+
+    @Override
+    WorkerThread newWorkerThread(final AsynchronousConnection connection,
+        final ConnectionFactory connectionFactory)
+    {
+      return new BindWorkerThread(connection, connectionFactory);
+    }
+  }
+  /**
+   * The main method for SearchRate tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   */
+
+  public static void main(final String[] args)
+  {
+    final int retCode = mainSearchRate(args, System.in, System.out, System.err);
+    System.exit(filterExitCode(retCode));
+  }
+
+
+
+  /**
+   * 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.
+   * @return The error code.
+   */
+
+  static int mainSearchRate(final String[] args)
+  {
+    return mainSearchRate(args, System.in, 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 inStream
+   *          The input stream to use for standard input, or <CODE>null</CODE>
+   *          if standard input is not needed.
+   * @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.
+   */
+
+  static int mainSearchRate(final String[] args, final InputStream inStream,
+      final OutputStream outStream, final OutputStream errStream)
+
+  {
+    return new AuthRate(inStream, outStream, errStream).run(args);
+  }
+
+
+
+  private BooleanArgument verbose;
+
+
+
+
+  private AuthRate(final InputStream in, final OutputStream out,
+      final OutputStream err)
+  {
+    super(in, out, err);
+
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested advanced mode.
+   *
+   * @return Returns <code>true</code> if the user has requested advanced mode.
+   */
+  @Override
+  public boolean isAdvancedMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested interactive behavior.
+   *
+   * @return Returns <code>true</code> if the user has requested interactive
+   *         behavior.
+   */
+  @Override
+  public boolean isInteractive()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not this console application is running in its
+   * menu-driven mode. This can be used to dictate whether output should go to
+   * the error stream or not. In addition, it may also dictate whether or not
+   * sub-menus should display a cancel option as well as a quit option.
+   *
+   * @return Returns <code>true</code> if this console application is running in
+   *         its menu-driven mode.
+   */
+  @Override
+  public boolean isMenuDrivenMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested quiet output.
+   *
+   * @return Returns <code>true</code> if the user has requested quiet output.
+   */
+  @Override
+  public boolean isQuiet()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested script-friendly output.
+   *
+   * @return Returns <code>true</code> if the user has requested script-friendly
+   *         output.
+   */
+  @Override
+  public boolean isScriptFriendly()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested verbose output.
+   *
+   * @return Returns <code>true</code> if the user has requested verbose output.
+   */
+  @Override
+  public boolean isVerbose()
+  {
+    return verbose.isPresent();
+  }
+
+
+
+  private int run(final String[] args)
+  {
+    // Create the command-line argument parser for use with this
+    // program.
+    final LocalizableMessage toolDescription =
+        INFO_AUTHRATE_TOOL_DESCRIPTION.get();
+    final ArgumentParser argParser = new ArgumentParser(AuthRate.class
+        .getName(), toolDescription, false, true, 0, 0,
+        "[filter format string] [attributes ...]");
+
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
+    BindPerformanceRunner runner;
+
+    StringArgument baseDN;
+    MultiChoiceArgument<SearchScope> searchScope;
+    MultiChoiceArgument<DereferenceAliasesPolicy> dereferencePolicy;
+    BooleanArgument showUsage;
+    StringArgument propertiesFileArgument;
+    BooleanArgument noPropertiesFileArgument;
+    IntegerArgument invalidCredPercent;
+
+    try
+    {
+      if(System.getProperty("org.opends.sdk.ldap.transport.linger") == null)
+      {
+        System.setProperty("org.opends.sdk.ldap.transport.linger", "0");
+      }
+      connectionFactoryProvider =
+          new ConnectionFactoryProvider(argParser, this);
+      runner = new BindPerformanceRunner(argParser, this);
+
+      propertiesFileArgument = new StringArgument("propertiesFilePath", null,
+          OPTION_LONG_PROP_FILE_PATH, false, false, true,
+          INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_PROP_FILE_PATH.get());
+      argParser.addArgument(propertiesFileArgument);
+      argParser.setFilePropertiesArgument(propertiesFileArgument);
+
+      noPropertiesFileArgument = new BooleanArgument(
+          "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE,
+          INFO_DESCRIPTION_NO_PROP_FILE.get());
+      argParser.addArgument(noPropertiesFileArgument);
+      argParser.setNoPropertiesFileArgument(noPropertiesFileArgument);
+
+      showUsage = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
+          OPTION_LONG_HELP, INFO_DESCRIPTION_SHOWUSAGE.get());
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage, getOutputStream());
+
+      baseDN = new StringArgument("baseDN", OPTION_SHORT_BASEDN,
+          OPTION_LONG_BASEDN, false, false, true, INFO_BASEDN_PLACEHOLDER.get(),
+          null, null, INFO_SEARCHRATE_TOOL_DESCRIPTION_BASEDN.get());
+      baseDN.setPropertyName(OPTION_LONG_BASEDN);
+      argParser.addArgument(baseDN);
+
+      searchScope = new MultiChoiceArgument<SearchScope>("searchScope", 's',
+          "searchScope", false, true, INFO_SEARCH_SCOPE_PLACEHOLDER.get(),
+          SearchScope.values(), false, INFO_SEARCH_DESCRIPTION_SEARCH_SCOPE
+              .get());
+      searchScope.setPropertyName("searchScope");
+      searchScope.setDefaultValue(SearchScope.WHOLE_SUBTREE);
+      argParser.addArgument(searchScope);
+
+      dereferencePolicy = new MultiChoiceArgument<DereferenceAliasesPolicy>(
+          "derefpolicy", 'a', "dereferencePolicy", false, true,
+          INFO_DEREFERENCE_POLICE_PLACEHOLDER.get(), DereferenceAliasesPolicy
+              .values(), false, INFO_SEARCH_DESCRIPTION_DEREFERENCE_POLICY
+              .get());
+      dereferencePolicy.setPropertyName("dereferencePolicy");
+      dereferencePolicy.setDefaultValue(DereferenceAliasesPolicy.NEVER);
+      argParser.addArgument(dereferencePolicy);
+
+      invalidCredPercent = new IntegerArgument("invalidPassword", 'I',
+        "invalidPassword", false, false, true, LocalizableMessage
+            .raw("{invalidPassword}"), 0, null, true, 0, true, 100,
+        LocalizableMessage
+            .raw("Percent of bind operations with simulated " +
+            "invalid password"));
+      invalidCredPercent.setPropertyName("invalidPassword");
+      argParser.addArgument(invalidCredPercent);
+
+      verbose = new BooleanArgument("verbose", 'v', "verbose",
+          INFO_DESCRIPTION_VERBOSE.get());
+      verbose.setPropertyName("verbose");
+      argParser.addArgument(verbose);
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_CANNOT_INITIALIZE_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Parse the command-line arguments provided to this program.
+    try
+    {
+      argParser.parseArguments(args);
+      connectionFactory =
+          connectionFactoryProvider.getConnectionFactory();
+      runner.validate();
+
+      runner.bindRequest = connectionFactoryProvider.getBindRequest();
+      if(runner.bindRequest == null)
+      {
+        throw new ArgumentException(LocalizableMessage.raw(
+            "Authentication information must be provided to use this tool"));
+      }
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ae
+          .getMessage());
+      println(message);
+      println(argParser.getUsageMessage());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // If we should just display usage or version information,
+    // then print it and exit.
+    if (argParser.usageOrVersionDisplayed())
+    {
+      return 0;
+    }
+
+    final List<String> attributes = new LinkedList<String>();
+    final ArrayList<String> filterAndAttributeStrings = argParser
+        .getTrailingArguments();
+    if (filterAndAttributeStrings.size() > 0)
+    {
+      // the list of trailing arguments should be structured as follow:
+      // the first trailing argument is
+      // considered the filter, the other as attributes.
+      runner.filter = filterAndAttributeStrings.remove(0);
+      // The rest are attributes
+      for (final String s : filterAndAttributeStrings)
+      {
+        attributes.add(s);
+      }
+    }
+    runner.attributes = attributes.toArray(new String[attributes.size()]);
+    runner.baseDN = baseDN.getValue();
+    try
+    {
+      runner.scope = searchScope.getTypedValue();
+      runner.dereferencesAliasesPolicy = dereferencePolicy.getTypedValue();
+      runner.invalidCredPercent = invalidCredPercent.getIntValue();
+    }
+    catch (final ArgumentException ex1)
+    {
+      println(ex1.getMessageObject());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Try it out to make sure the format string and data sources
+    // match.
+    final Object[] data = DataSource.generateData(runner.getDataSources(),
+        null);
+    try
+    {
+      if(runner.baseDN != null && runner.filter != null)
+      {
+        String.format(runner.filter, data);
+        String.format(runner.baseDN, data);
+      }
+    }
+    catch (final Exception ex1)
+    {
+      println(LocalizableMessage.raw("Error formatting filter or base DN: "
+          + ex1.toString()));
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    return runner.run(connectionFactory);
+  }
+}
+
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ArgumentParserConnectionFactory.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ConnectionFactoryProvider.java
similarity index 67%
rename from opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ArgumentParserConnectionFactory.java
rename to opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ConnectionFactoryProvider.java
index 48b7a78..34324e6 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ArgumentParserConnectionFactory.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ConnectionFactoryProvider.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package com.sun.opends.sdk.tools;
@@ -56,8 +56,7 @@
 /**
  * A connection factory designed for use with command line tools.
  */
-final class ArgumentParserConnectionFactory extends AbstractConnectionFactory
-    implements ConnectionFactory
+final class ConnectionFactoryProvider
 {
   /**
    * End Of Line.
@@ -68,7 +67,7 @@
    * The Logger.
    */
   static final Logger LOG = Logger
-      .getLogger(ArgumentParserConnectionFactory.class.getName());
+      .getLogger(ConnectionFactoryProvider.class.getName());
 
   /**
    * The 'hostName' global argument.
@@ -167,13 +166,15 @@
 
   private ConnectionFactory connFactory;
 
+  private ConnectionFactory authenticatedConnFactory;
+
   private BindRequest bindRequest = null;
 
   private final ConsoleApplication app;
 
 
 
-  public ArgumentParserConnectionFactory(final ArgumentParser argumentParser,
+  public ConnectionFactoryProvider(final ArgumentParser argumentParser,
       final ConsoleApplication app) throws ArgumentException
   {
     this(argumentParser, app, "cn=Directory Manager", 389, false);
@@ -181,7 +182,7 @@
 
 
 
-  public ArgumentParserConnectionFactory(final ArgumentParser argumentParser,
+  public ConnectionFactoryProvider(final ArgumentParser argumentParser,
       final ConsoleApplication app, final String defaultBindDN,
       final int defaultPort, final boolean alwaysSSL) throws ArgumentException
   {
@@ -326,165 +327,158 @@
   }
 
 
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
-      final ResultHandler<? super AsynchronousConnection> handler)
+  public ConnectionFactory getConnectionFactory() throws ArgumentException
   {
-    return connFactory.getAsynchronousConnection(handler);
-  }
-
-
-
-  public void validate() throws ArgumentException
-  {
-    port = portArg.getIntValue();
-
-    // Couldn't have at the same time bindPassword and bindPasswordFile
-    if (bindPasswordArg.isPresent() && bindPasswordFileArg.isPresent())
+    if(connFactory == null)
     {
-      final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
-          bindPasswordArg.getLongIdentifier(), bindPasswordFileArg
-              .getLongIdentifier());
-      throw new ArgumentException(message);
-    }
+      port = portArg.getIntValue();
 
-    // Couldn't have at the same time trustAll and
-    // trustStore related arg
-    if (trustAllArg.isPresent() && trustStorePathArg.isPresent())
-    {
-      final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
-          trustAllArg.getLongIdentifier(), trustStorePathArg
-              .getLongIdentifier());
-      throw new ArgumentException(message);
-    }
-    if (trustAllArg.isPresent() && trustStorePasswordArg.isPresent())
-    {
-      final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
-          trustAllArg.getLongIdentifier(), trustStorePasswordArg
-              .getLongIdentifier());
-      throw new ArgumentException(message);
-    }
-    if (trustAllArg.isPresent() && trustStorePasswordFileArg.isPresent())
-    {
-      final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
-          trustAllArg.getLongIdentifier(), trustStorePasswordFileArg
-              .getLongIdentifier());
-      throw new ArgumentException(message);
-    }
-
-    // Couldn't have at the same time trustStorePasswordArg and
-    // trustStorePasswordFileArg
-    if (trustStorePasswordArg.isPresent()
-        && trustStorePasswordFileArg.isPresent())
-    {
-      final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
-          trustStorePasswordArg.getLongIdentifier(), trustStorePasswordFileArg
-              .getLongIdentifier());
-      throw new ArgumentException(message);
-    }
-
-    if (trustStorePathArg.isPresent())
-    {
-      // Check that the path exists and is readable
-      final String value = trustStorePathArg.getValue();
-      if (!canRead(trustStorePathArg.getValue()))
+      // Couldn't have at the same time bindPassword and bindPasswordFile
+      if (bindPasswordArg.isPresent() && bindPasswordFileArg.isPresent())
       {
-        final LocalizableMessage message = ERR_CANNOT_READ_TRUSTSTORE
-            .get(value);
+        final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
+            bindPasswordArg.getLongIdentifier(), bindPasswordFileArg
+                .getLongIdentifier());
         throw new ArgumentException(message);
       }
-    }
 
-    if (keyStorePathArg.isPresent())
-    {
-      // Check that the path exists and is readable
-      final String value = keyStorePathArg.getValue();
-      if (!canRead(trustStorePathArg.getValue()))
+      // Couldn't have at the same time trustAll and
+      // trustStore related arg
+      if (trustAllArg.isPresent() && trustStorePathArg.isPresent())
       {
-        final LocalizableMessage message = ERR_CANNOT_READ_KEYSTORE.get(value);
+        final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
+            trustAllArg.getLongIdentifier(), trustStorePathArg
+                .getLongIdentifier());
         throw new ArgumentException(message);
       }
-    }
-
-    // Couldn't have at the same time startTLSArg and
-    // useSSLArg
-    if (useStartTLSArg.isPresent() && useSSLArg.isPresent())
-    {
-      final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
-          useStartTLSArg.getLongIdentifier(), useSSLArg.getLongIdentifier());
-      throw new ArgumentException(message);
-    }
-
-    try
-    {
-      if (useSSLArg.isPresent() || useStartTLSArg.isPresent())
+      if (trustAllArg.isPresent() && trustStorePasswordArg.isPresent())
       {
-        String clientAlias;
-        if (certNicknameArg.isPresent())
+        final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
+            trustAllArg.getLongIdentifier(), trustStorePasswordArg
+                .getLongIdentifier());
+        throw new ArgumentException(message);
+      }
+      if (trustAllArg.isPresent() && trustStorePasswordFileArg.isPresent())
+      {
+        final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
+            trustAllArg.getLongIdentifier(), trustStorePasswordFileArg
+                .getLongIdentifier());
+        throw new ArgumentException(message);
+      }
+
+      // Couldn't have at the same time trustStorePasswordArg and
+      // trustStorePasswordFileArg
+      if (trustStorePasswordArg.isPresent()
+          && trustStorePasswordFileArg.isPresent())
+      {
+        final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
+            trustStorePasswordArg.getLongIdentifier(), trustStorePasswordFileArg
+                .getLongIdentifier());
+        throw new ArgumentException(message);
+      }
+
+      if (trustStorePathArg.isPresent())
+      {
+        // Check that the path exists and is readable
+        final String value = trustStorePathArg.getValue();
+        if (!canRead(trustStorePathArg.getValue()))
         {
-          clientAlias = certNicknameArg.getValue();
+          final LocalizableMessage message = ERR_CANNOT_READ_TRUSTSTORE
+              .get(value);
+          throw new ArgumentException(message);
         }
-        else
+      }
+
+      if (keyStorePathArg.isPresent())
+      {
+        // Check that the path exists and is readable
+        final String value = keyStorePathArg.getValue();
+        if (!canRead(trustStorePathArg.getValue()))
         {
-          clientAlias = null;
+          final LocalizableMessage message =
+              ERR_CANNOT_READ_KEYSTORE.get(value);
+          throw new ArgumentException(message);
         }
+      }
 
-        if (sslContext == null)
+      // Couldn't have at the same time startTLSArg and
+      // useSSLArg
+      if (useStartTLSArg.isPresent() && useSSLArg.isPresent())
+      {
+        final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
+            useStartTLSArg.getLongIdentifier(), useSSLArg.getLongIdentifier());
+        throw new ArgumentException(message);
+      }
+
+      try
+      {
+        if (useSSLArg.isPresent() || useStartTLSArg.isPresent())
         {
-          final TrustManager trustManager = getTrustManager();
-
-          X509KeyManager keyManager = null;
-          final X509KeyManager akm = getKeyManager(keyStorePathArg.getValue());
-
-          if (akm != null && clientAlias != null)
+          String clientAlias;
+          if (certNicknameArg.isPresent())
           {
-            keyManager = KeyManagers.useSingleCertificate(clientAlias, akm);
+            clientAlias = certNicknameArg.getValue();
+          }
+          else
+          {
+            clientAlias = null;
           }
 
-          sslContext = new SSLContextBuilder().setTrustManager(trustManager)
-              .setKeyManager(keyManager).getSSLContext();
+          if (sslContext == null)
+          {
+            final TrustManager trustManager = getTrustManager();
+
+            X509KeyManager keyManager = null;
+            final X509KeyManager akm =
+                getKeyManager(keyStorePathArg.getValue());
+
+            if (akm != null && clientAlias != null)
+            {
+              keyManager = KeyManagers.useSingleCertificate(clientAlias, akm);
+            }
+
+            sslContext = new SSLContextBuilder().setTrustManager(trustManager)
+                .setKeyManager(keyManager).getSSLContext();
+          }
         }
       }
-    }
-    catch (final Exception e)
-    {
-      throw new ArgumentException(ERR_LDAP_CONN_CANNOT_INITIALIZE_SSL.get(e
-          .toString()), e);
-    }
+      catch (final Exception e)
+      {
+        throw new ArgumentException(ERR_LDAP_CONN_CANNOT_INITIALIZE_SSL.get(e
+            .toString()), e);
+      }
 
-    if (sslContext != null)
-    {
-      final LDAPOptions options = new LDAPOptions().setSSLContext(sslContext)
-          .setUseStartTLS(useStartTLSArg.isPresent());
-      connFactory = new LDAPConnectionFactory(hostNameArg.getValue(), port,
-          options);
+      if (sslContext != null)
+      {
+        final LDAPOptions options = new LDAPOptions().setSSLContext(sslContext)
+            .setUseStartTLS(useStartTLSArg.isPresent());
+        connFactory = new LDAPConnectionFactory(hostNameArg.getValue(), port,
+            options);
+      }
+      else
+      {
+        connFactory = new LDAPConnectionFactory(hostNameArg.getValue(), port);
+      }
     }
-    else
-    {
-      connFactory = new LDAPConnectionFactory(hostNameArg.getValue(), port);
-    }
-
-    try
-    {
-      bindRequest = getBindRequest();
-    }
-    catch (final CLIException e)
-    {
-      throw new ArgumentException(LocalizableMessage
-          .raw("Error reading input: " + e.toString()));
-    }
-    if (bindRequest != null)
-    {
-      connFactory = new AuthenticatedConnectionFactory(connFactory, bindRequest)
-          .setRebindAllowed(true);
-    }
+    return connFactory;
   }
 
-
+  public ConnectionFactory getAuthenticatedConnectionFactory()
+      throws ArgumentException
+  {
+    if(authenticatedConnFactory == null)
+    {
+      authenticatedConnFactory = getConnectionFactory();
+      BindRequest bindRequest = getBindRequest();
+      if(bindRequest != null)
+      {
+        authenticatedConnFactory =
+            Connections.newAuthenticatedConnectionFactory(
+                authenticatedConnFactory, bindRequest);
+      }
+    }
+    return authenticatedConnFactory;
+  }
 
   /**
    * Returns <CODE>true</CODE> if we can read on the provided path and
@@ -505,8 +499,7 @@
 
 
 
-  private String getAuthID(final String mech) throws CLIException,
-      ArgumentException
+  private String getAuthID(final String mech) throws ArgumentException
   {
     String value = null;
     for (final String s : saslOptionArg.getValues())
@@ -523,9 +516,14 @@
     }
     if (value == null && app.isInteractive())
     {
-      value = app.readInput(LocalizableMessage.raw("Authentication ID:"),
-          bindNameArg.getDefaultValue() == null ? null : "dn: "
-              + bindNameArg.getDefaultValue());
+      try {
+        value = app.readInput(LocalizableMessage.raw("Authentication ID:"),
+            bindNameArg.getDefaultValue() == null ? null : "dn: "
+                + bindNameArg.getDefaultValue());
+      } catch (CLIException e) {
+        throw new ArgumentException(
+            LocalizableMessage.raw("Unable to read authentication ID"), e);
+      }
     }
     if (value == null)
     {
@@ -538,7 +536,7 @@
 
 
 
-  private String getAuthzID() throws CLIException, ArgumentException
+  private String getAuthzID() throws ArgumentException
   {
     String value = null;
     for (final String s : saslOptionArg.getValues())
@@ -554,7 +552,7 @@
 
 
 
-  private String getBindName() throws CLIException
+  private String getBindName() throws ArgumentException
   {
     String value = "";
     if (bindNameArg.isPresent())
@@ -563,8 +561,13 @@
     }
     else if (app.isInteractive())
     {
-      value = app.readInput(LocalizableMessage.raw("Bind name:"), bindNameArg
-          .getDefaultValue() == null ? value : bindNameArg.getDefaultValue());
+      try {
+        value = app.readInput(LocalizableMessage.raw("Bind name:"), bindNameArg
+            .getDefaultValue() == null ? value : bindNameArg.getDefaultValue());
+      } catch (CLIException e) {
+        throw new ArgumentException(
+            LocalizableMessage.raw("Unable to read bind name"), e);
+      }
     }
 
     return value;
@@ -572,74 +575,79 @@
 
 
 
-  private BindRequest getBindRequest() throws CLIException, ArgumentException
+  public BindRequest getBindRequest() throws ArgumentException
   {
-    String mech = null;
-    for (final String s : saslOptionArg.getValues())
+    if(bindRequest == null)
     {
-      if (s.startsWith(SASL_PROPERTY_MECH))
+      String mech = null;
+      for (final String s : saslOptionArg.getValues())
       {
-        mech = parseSASLOptionValue(s);
-        break;
+        if (s.startsWith(SASL_PROPERTY_MECH))
+        {
+          mech = parseSASLOptionValue(s);
+          break;
+        }
       }
-    }
 
-    if (mech == null)
-    {
-      if (bindNameArg.isPresent() || bindPasswordFileArg.isPresent()
-          || bindPasswordArg.isPresent())
+      if (mech == null)
       {
-        return Requests.newSimpleBindRequest(getBindName(), getPassword());
+        if (bindNameArg.isPresent() || bindPasswordFileArg.isPresent()
+            || bindPasswordArg.isPresent())
+        {
+          bindRequest =
+              Requests.newSimpleBindRequest(getBindName(), getPassword());
+        }
       }
-      return null;
-    }
-
-    if (mech.equals(DigestMD5SASLBindRequest.SASL_MECHANISM_NAME))
-    {
-      return Requests.newDigestMD5SASLBindRequest(
-          getAuthID(DigestMD5SASLBindRequest.SASL_MECHANISM_NAME),
-          ByteString.valueOf(getPassword())).setAuthorizationID(getAuthzID())
-          .setRealm(getRealm());
-    }
-    if (mech.equals(CRAMMD5SASLBindRequest.SASL_MECHANISM_NAME))
-    {
-      return Requests.newCRAMMD5SASLBindRequest(
-          getAuthID(CRAMMD5SASLBindRequest.SASL_MECHANISM_NAME), ByteString
-              .valueOf(getPassword()));
-    }
-    if (mech.equals(GSSAPISASLBindRequest.SASL_MECHANISM_NAME))
-    {
-      return Requests.newGSSAPISASLBindRequest(
-          getAuthID(GSSAPISASLBindRequest.SASL_MECHANISM_NAME),
-          ByteString.valueOf(getPassword())).setKDCAddress(getKDC()).setRealm(
-          getRealm()).setAuthorizationID(getAuthzID());
-    }
-    if (mech.equals(ExternalSASLBindRequest.SASL_MECHANISM_NAME))
-    {
-      if (sslContext == null)
+      else if (mech.equals(DigestMD5SASLBindRequest.SASL_MECHANISM_NAME))
       {
-        final LocalizableMessage message = ERR_TOOL_SASLEXTERNAL_NEEDS_SSL_OR_TLS
-            .get();
-        throw new ArgumentException(message);
+        bindRequest = Requests.newDigestMD5SASLBindRequest(
+            getAuthID(DigestMD5SASLBindRequest.SASL_MECHANISM_NAME),
+            ByteString.valueOf(getPassword())).setAuthorizationID(getAuthzID())
+            .setRealm(getRealm());
       }
-      if (!keyStorePathArg.isPresent() && getKeyStore() == null)
+      else if (mech.equals(CRAMMD5SASLBindRequest.SASL_MECHANISM_NAME))
       {
-        final LocalizableMessage message = ERR_TOOL_SASLEXTERNAL_NEEDS_KEYSTORE
-            .get();
-        throw new ArgumentException(message);
+        bindRequest = Requests.newCRAMMD5SASLBindRequest(
+            getAuthID(CRAMMD5SASLBindRequest.SASL_MECHANISM_NAME), ByteString
+                .valueOf(getPassword()));
       }
-      return Requests.newExternalSASLBindRequest().setAuthorizationID(
-          getAuthzID());
+      else if (mech.equals(GSSAPISASLBindRequest.SASL_MECHANISM_NAME))
+      {
+        bindRequest = Requests.newGSSAPISASLBindRequest(
+            getAuthID(GSSAPISASLBindRequest.SASL_MECHANISM_NAME),
+            ByteString.valueOf(getPassword())).setKDCAddress(getKDC()).setRealm(
+            getRealm()).setAuthorizationID(getAuthzID());
+      }
+      else if (mech.equals(ExternalSASLBindRequest.SASL_MECHANISM_NAME))
+      {
+        if (sslContext == null)
+        {
+          final LocalizableMessage message =
+              ERR_TOOL_SASLEXTERNAL_NEEDS_SSL_OR_TLS.get();
+          throw new ArgumentException(message);
+        }
+        if (!keyStorePathArg.isPresent() && getKeyStore() == null)
+        {
+          final LocalizableMessage message =
+              ERR_TOOL_SASLEXTERNAL_NEEDS_KEYSTORE.get();
+          throw new ArgumentException(message);
+        }
+        bindRequest = Requests.newExternalSASLBindRequest().setAuthorizationID(
+            getAuthzID());
+      }
+      else if (mech.equals(PlainSASLBindRequest.SASL_MECHANISM_NAME))
+      {
+        bindRequest = Requests.newPlainSASLBindRequest(
+            getAuthID(PlainSASLBindRequest.SASL_MECHANISM_NAME),
+            ByteString.valueOf(getPassword())).setAuthorizationID(getAuthzID());
+      }
+      else
+      {
+        throw new ArgumentException(ERR_LDAPAUTH_UNSUPPORTED_SASL_MECHANISM
+            .get(mech));
+      }
     }
-    if (mech.equals(PlainSASLBindRequest.SASL_MECHANISM_NAME))
-    {
-      return Requests.newPlainSASLBindRequest(
-          getAuthID(PlainSASLBindRequest.SASL_MECHANISM_NAME),
-          ByteString.valueOf(getPassword())).setAuthorizationID(getAuthzID());
-    }
-
-    throw new ArgumentException(ERR_LDAPAUTH_UNSUPPORTED_SASL_MECHANISM
-        .get(mech));
+    return bindRequest;
   }
 
 
@@ -654,7 +662,7 @@
 
 
 
-  private String getKDC() throws ArgumentException, CLIException
+  private String getKDC() throws ArgumentException
   {
     String value = null;
     for (final String s : saslOptionArg.getValues())
@@ -760,7 +768,7 @@
    * @return The password stored into the specified file on by the command line
    *         argument, or null it if not specified.
    */
-  private String getPassword() throws CLIException
+  private String getPassword() throws ArgumentException
   {
     String value = "";
     if (bindPasswordArg.isPresent())
@@ -773,7 +781,15 @@
     }
     if (value.length() == 0 && app.isInteractive())
     {
-      value = app.readLineOfInput(LocalizableMessage.raw("Bind Password:"));
+      try
+      {
+        value = app.readLineOfInput(LocalizableMessage.raw("Bind Password:"));
+      }
+      catch(CLIException e)
+      {
+        throw new ArgumentException(
+            LocalizableMessage.raw("Unable to read password"), e);
+      }
     }
 
     return value;
@@ -781,7 +797,7 @@
 
 
 
-  private String getRealm() throws ArgumentException, CLIException
+  private String getRealm() throws ArgumentException
   {
     String value = null;
     for (final String s : saslOptionArg.getValues())
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPCompare.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPCompare.java
index 380462e..a861219 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPCompare.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPCompare.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package com.sun.opends.sdk.tools;
@@ -277,7 +277,8 @@
     final ArgumentParser argParser = new ArgumentParser(LDAPCompare.class
         .getName(), toolDescription, false, true, 1, 0,
         "attribute:value [DN ...]");
-    ArgumentParserConnectionFactory connectionFactory;
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
 
     BooleanArgument continueOnError;
     BooleanArgument noop;
@@ -293,7 +294,8 @@
 
     try
     {
-      connectionFactory = new ArgumentParserConnectionFactory(argParser, this);
+      connectionFactoryProvider =
+          new ConnectionFactoryProvider(argParser, this);
       propertiesFileArgument = new StringArgument("propertiesFilePath", null,
           OPTION_LONG_PROP_FILE_PATH, false, false, true,
           INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
@@ -379,7 +381,8 @@
     try
     {
       argParser.parseArguments(args);
-      connectionFactory.validate();
+      connectionFactory =
+          connectionFactoryProvider.getAuthenticatedConnectionFactory();
     }
     catch (final ArgumentException ae)
     {
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPModify.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPModify.java
index c62ad71..aa9d4e1 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPModify.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPModify.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package com.sun.opends.sdk.tools;
@@ -473,7 +473,8 @@
         .get();
     final ArgumentParser argParser = new ArgumentParser(LDAPModify.class
         .getName(), toolDescription, false);
-    ArgumentParserConnectionFactory connectionFactory;
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
 
     BooleanArgument continueOnError;
     // TODO: Remove this due to new LDIF reader api?
@@ -493,7 +494,8 @@
 
     try
     {
-      connectionFactory = new ArgumentParserConnectionFactory(argParser, this);
+      connectionFactoryProvider =
+          new ConnectionFactoryProvider(argParser, this);
       propertiesFileArgument = new StringArgument("propertiesFilePath", null,
           OPTION_LONG_PROP_FILE_PATH, false, false, true,
           INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
@@ -597,7 +599,8 @@
     try
     {
       argParser.parseArguments(args);
-      connectionFactory.validate();
+      connectionFactory =
+          connectionFactoryProvider.getAuthenticatedConnectionFactory();
     }
     catch (final ArgumentException ae)
     {
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPPasswordModify.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPPasswordModify.java
index fb209df..d87d5b7 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPPasswordModify.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPPasswordModify.java
@@ -225,7 +225,8 @@
         .get();
     final ArgumentParser argParser = new ArgumentParser(
         LDAPPasswordModify.class.getName(), toolDescription, false);
-    ArgumentParserConnectionFactory connectionFactory;
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
 
     FileBasedArgument currentPWFile;
     FileBasedArgument newPWFile;
@@ -240,7 +241,8 @@
 
     try
     {
-      connectionFactory = new ArgumentParserConnectionFactory(argParser, this);
+      connectionFactoryProvider =
+          new ConnectionFactoryProvider(argParser, this);
       propertiesFileArgument = new StringArgument("propertiesFilePath", null,
           OPTION_LONG_PROP_FILE_PATH, false, false, true,
           INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
@@ -319,7 +321,8 @@
     try
     {
       argParser.parseArguments(args);
-      connectionFactory.validate();
+      connectionFactory =
+          connectionFactoryProvider.getAuthenticatedConnectionFactory();
     }
     catch (final ArgumentException ae)
     {
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPSearch.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPSearch.java
index d8a8316..5c5daa5 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPSearch.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPSearch.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package com.sun.opends.sdk.tools;
@@ -400,7 +400,8 @@
     final ArgumentParser argParser = new ArgumentParser(LDAPSearch.class
         .getName(), toolDescription, false, true, 0, 0,
         "[filter] [attributes ...]");
-    ArgumentParserConnectionFactory connectionFactory;
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
 
     BooleanArgument countEntries;
     BooleanArgument dontWrap;
@@ -425,7 +426,8 @@
     IntegerArgument sizeLimit;
     try
     {
-      connectionFactory = new ArgumentParserConnectionFactory(argParser, this);
+      connectionFactoryProvider =
+          new ConnectionFactoryProvider(argParser, this);
       final StringArgument propertiesFileArgument = new StringArgument(
           "propertiesFilePath", null, OPTION_LONG_PROP_FILE_PATH, false, false,
           true, INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
@@ -607,7 +609,8 @@
     try
     {
       argParser.parseArguments(args);
-      connectionFactory.validate();
+      connectionFactory =
+          connectionFactoryProvider.getAuthenticatedConnectionFactory();
     }
     catch (final ArgumentException ae)
     {
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ModRate.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ModRate.java
index 488fedb..8ad7a38 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ModRate.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ModRate.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package com.sun.opends.sdk.tools;
@@ -51,8 +51,7 @@
 {
   private static final class ModifyPerformanceRunner extends PerformanceRunner
   {
-    private final class ModifyWorkerThread extends
-        WorkerThread<ResultHandler<Result>>
+    private final class ModifyWorkerThread extends WorkerThread
     {
       private ModifyRequest mr;
       private Object[] data;
@@ -68,24 +67,17 @@
 
 
       @Override
-      public ResultHandler<Result> getHandler(final long startTime)
-      {
-        return new UpdateStatsResultHandler<Result>(startTime);
-      }
-
-
-
-      @Override
       public FutureResult<?> performOperation(
           final AsynchronousConnection connection,
-          final ResultHandler<Result> handler, final DataSource[] dataSources)
+          final DataSource[] dataSources, long startTime)
       {
         if (dataSources != null)
         {
           data = DataSource.generateData(dataSources, data);
         }
         mr = newModifyRequest(data);
-        return connection.modify(mr, handler);
+        return connection.modify(mr,
+            new UpdateStatsResultHandler<Result>(startTime));
       }
 
 
@@ -136,7 +128,7 @@
     private ModifyPerformanceRunner(final ArgumentParser argParser,
         final ConsoleApplication app) throws ArgumentException
     {
-      super(argParser, app);
+      super(argParser, app, false, false, false);
     }
 
 
@@ -150,7 +142,7 @@
 
 
     @Override
-    WorkerThread<?> newWorkerThread(final AsynchronousConnection connection,
+    WorkerThread newWorkerThread(final AsynchronousConnection connection,
         final ConnectionFactory connectionFactory)
     {
       return new ModifyWorkerThread(connection, connectionFactory);
@@ -323,7 +315,8 @@
     final ArgumentParser argParser = new ArgumentParser(
         ModRate.class.getName(), toolDescription, false, true, 1, 0,
         "[(attribute:value format string) ...]");
-    ArgumentParserConnectionFactory connectionFactory;
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
     ModifyPerformanceRunner runner;
 
     BooleanArgument showUsage;
@@ -337,7 +330,8 @@
       {
         System.setProperty("org.opends.sdk.ldap.transport.linger", "0");
       }
-      connectionFactory = new ArgumentParserConnectionFactory(argParser, this);
+      connectionFactoryProvider =
+          new ConnectionFactoryProvider(argParser, this);
       runner = new ModifyPerformanceRunner(argParser, this);
       propertiesFileArgument = new StringArgument("propertiesFilePath", null,
           OPTION_LONG_PROP_FILE_PATH, false, false, true,
@@ -380,7 +374,8 @@
     try
     {
       argParser.parseArguments(args);
-      connectionFactory.validate();
+      connectionFactory =
+          connectionFactoryProvider.getAuthenticatedConnectionFactory();
       runner.validate();
     }
     catch (final ArgumentException ae)
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/PerformanceRunner.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/PerformanceRunner.java
index e03b631..f12b164 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/PerformanceRunner.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/PerformanceRunner.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package com.sun.opends.sdk.tools;
@@ -386,11 +386,8 @@
 
   /**
    * Worker thread base implementation.
-   *
-   * @param <R>
-   *          Type of result handler.
    */
-  abstract class WorkerThread<R extends ResultHandler<?>> extends Thread
+  abstract class WorkerThread extends Thread
   {
     private int count;
 
@@ -410,12 +407,9 @@
 
 
 
-    public abstract R getHandler(long startTime);
-
-
-
     public abstract FutureResult<?> performOperation(
-        AsynchronousConnection connection, R handler, DataSource[] dataSources);
+        AsynchronousConnection connection, DataSource[] dataSources,
+        long startTime);
 
 
 
@@ -424,7 +418,6 @@
     {
       FutureResult<?> future;
       AsynchronousConnection connection;
-      R handler;
 
       final double targetTimeInMS =
         (1.0 / (targetThroughput /
@@ -433,9 +426,6 @@
       long start;
       while (!stopRequested && !(maxIterations > 0 && count >= maxIterations))
       {
-        start = System.nanoTime();
-        handler = getHandler(start);
-
         if (this.connection == null)
         {
           try
@@ -489,7 +479,9 @@
             }
           }
         }
-        future = performOperation(connection, handler, dataSources.get());
+
+        start = System.nanoTime();
+        future = performOperation(connection, dataSources.get(), start);
         operationRecentCount.getAndIncrement();
         count++;
         if (!isAsync)
@@ -732,9 +724,9 @@
 
   private final AtomicInteger operationRecentCount = new AtomicInteger();
 
-  private final AtomicInteger successRecentCount = new AtomicInteger();
+  protected final AtomicInteger successRecentCount = new AtomicInteger();
 
-  private final AtomicInteger failedRecentCount = new AtomicInteger();
+  protected final AtomicInteger failedRecentCount = new AtomicInteger();
 
   private final AtomicLong waitRecentTime = new AtomicLong();
 
@@ -804,7 +796,10 @@
 
 
 
-  PerformanceRunner(final ArgumentParser argParser, final ConsoleApplication app)
+  PerformanceRunner(final ArgumentParser argParser,
+                    final ConsoleApplication app,
+                    boolean neverRebind, boolean neverAsynchronous,
+                    boolean alwaysSingleThreaded)
       throws ArgumentException
   {
     this.app = app;
@@ -813,20 +808,27 @@
         true, 1, false, 0, LocalizableMessage
             .raw("Number of worker threads per connection"));
     numThreadsArgument.setPropertyName("numThreads");
-    argParser.addArgument(numThreadsArgument);
+    if(!alwaysSingleThreaded)
+    {
+      argParser.addArgument(numThreadsArgument);
+    }
+    else
+    {
+      numThreadsArgument.addValue("1");
+    }
 
     numConnectionsArgument = new IntegerArgument("numConnections", 'c',
         "numConnections", false, false, true, LocalizableMessage
             .raw("{numConnections}"), 1, null, true, 1, false, 0,
         LocalizableMessage.raw("Number of connections"));
-    numThreadsArgument.setPropertyName("numConnections");
+    numConnectionsArgument.setPropertyName("numConnections");
     argParser.addArgument(numConnectionsArgument);
 
     maxIterationsArgument = new IntegerArgument("maxIterations", 'm',
         "maxIterations", false, false, true, LocalizableMessage
             .raw("{maxIterations}"), 0, null, LocalizableMessage
             .raw("Max iterations, 0 for unlimited"));
-    numThreadsArgument.setPropertyName("maxIterations");
+    maxIterationsArgument.setPropertyName("maxIterations");
     argParser.addArgument(maxIterationsArgument);
 
     statsIntervalArgument = new IntegerArgument("statInterval", 'i',
@@ -834,7 +836,7 @@
             .raw("{statInterval}"), 5, null, true, 1, false, 0,
         LocalizableMessage
             .raw("Display results each specified number of seconds"));
-    numThreadsArgument.setPropertyName("statInterval");
+    statsIntervalArgument.setPropertyName("statInterval");
     argParser.addArgument(statsIntervalArgument);
 
     targetThroughputArgument = new IntegerArgument("targetThroughput", 'M',
@@ -859,14 +861,24 @@
 
     noRebindArgument = new BooleanArgument("noRebind", 'F', "noRebind",
         LocalizableMessage.raw("Keep connections open and don't rebind"));
-    keepConnectionsOpen.setPropertyName("noRebind");
-    argParser.addArgument(noRebindArgument);
+    noRebindArgument.setPropertyName("noRebind");
+    if(!neverRebind)
+    {
+      argParser.addArgument(noRebindArgument);
+    }
+    else
+    {
+      noRebindArgument.addValue(String.valueOf(true));
+    }
 
     asyncArgument = new BooleanArgument("asynchronous", 'A', "asynchronous",
         LocalizableMessage.raw("Use asynchronous mode and don't " +
             "wait for results before sending the next request"));
-    keepConnectionsOpen.setPropertyName("asynchronous");
-    argParser.addArgument(asyncArgument);
+    asyncArgument.setPropertyName("asynchronous");
+    if(!neverAsynchronous)
+    {
+      argParser.addArgument(asyncArgument);
+    }
 
     arguments = new StringArgument("argument", 'g', "argument", false, true,
         true, LocalizableMessage.raw("{generator function or static string}"),
@@ -962,7 +974,7 @@
 
 
 
-  abstract WorkerThread<?> newWorkerThread(AsynchronousConnection connection,
+  abstract WorkerThread newWorkerThread(AsynchronousConnection connection,
       ConnectionFactory connectionFactory);
 
 
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/SearchRate.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/SearchRate.java
index be6a73a..ddc81ae 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/SearchRate.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/tools/SearchRate.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package com.sun.opends.sdk.tools;
@@ -85,8 +85,6 @@
 
     private final class SearchStatsThread extends StatsThread
     {
-      private long totalEntryCount;
-
       private final String[] extraColumn;
 
 
@@ -103,7 +101,6 @@
       String[] getAdditionalColumns()
       {
         final int entryCount = entryRecentCount.getAndSet(0);
-        totalEntryCount += entryCount;
         if (successCount > 0)
         {
           extraColumn[0] = String.format("%.1f", (double) entryCount
@@ -119,8 +116,7 @@
 
 
 
-    private final class SearchWorkerThread extends
-        WorkerThread<SearchStatsHandler>
+    private final class SearchWorkerThread extends WorkerThread
     {
       private SearchRequest sr;
 
@@ -137,17 +133,9 @@
 
 
       @Override
-      public SearchStatsHandler getHandler(final long startTime)
-      {
-        return new SearchStatsHandler(startTime);
-      }
-
-
-
-      @Override
       public FutureResult<?> performOperation(
           final AsynchronousConnection connection,
-          final SearchStatsHandler handler, final DataSource[] dataSources)
+          final DataSource[] dataSources, final long startTime)
       {
         if (sr == null)
         {
@@ -169,7 +157,7 @@
           sr.setFilter(String.format(filter, data));
           sr.setName(String.format(baseDN, data));
         }
-        return connection.search(sr, handler);
+        return connection.search(sr, new SearchStatsHandler(startTime));
       }
     }
 
@@ -190,7 +178,7 @@
     private SearchPerformanceRunner(final ArgumentParser argParser,
         final ConsoleApplication app) throws ArgumentException
     {
-      super(argParser, app);
+      super(argParser, app, false, false, false);
     }
 
 
@@ -204,7 +192,7 @@
 
 
     @Override
-    WorkerThread<?> newWorkerThread(final AsynchronousConnection connection,
+    WorkerThread newWorkerThread(final AsynchronousConnection connection,
         final ConnectionFactory connectionFactory)
     {
       return new SearchWorkerThread(connection, connectionFactory);
@@ -380,7 +368,8 @@
         .getName(), toolDescription, false, true, 1, 0,
         "[filter format string] [attributes ...]");
 
-    ArgumentParserConnectionFactory connectionFactory;
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
     SearchPerformanceRunner runner;
 
     StringArgument baseDN;
@@ -396,7 +385,8 @@
       {
         System.setProperty("org.opends.sdk.ldap.transport.linger", "0");
       }
-      connectionFactory = new ArgumentParserConnectionFactory(argParser, this);
+      connectionFactoryProvider =
+          new ConnectionFactoryProvider(argParser, this);
       runner = new SearchPerformanceRunner(argParser, this);
 
       propertiesFileArgument = new StringArgument("propertiesFilePath", null,
@@ -457,7 +447,8 @@
     try
     {
       argParser.parseArguments(args);
-      connectionFactory.validate();
+      connectionFactory =
+          connectionFactoryProvider.getAuthenticatedConnectionFactory();
       runner.validate();
     }
     catch (final ArgumentException ae)
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/util/AbstractFutureResult.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/AbstractFutureResult.java
deleted file mode 100644
index 1d478d0..0000000
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/util/AbstractFutureResult.java
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * 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
- *
- *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
- */
-
-package com.sun.opends.sdk.util;
-
-
-
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.locks.AbstractQueuedSynchronizer;
-
-import org.opends.sdk.*;
-import org.opends.sdk.responses.Responses;
-import org.opends.sdk.responses.Result;
-
-
-
-/**
- * This class provides a skeletal implementation of the {@code FutureResult}
- * interface, to minimize the effort required to implement this interface.
- * <p>
- * This {@code FutureResult} implementation provides the following features:
- * <ul>
- * <li>The {@link #get} methods throw {@link ErrorResultException}s instead of
- * the more generic {@code ExecutionException}s.
- * <li>The {@link #get} methods never throw {@code CancellationException} since
- * requests in this SDK can usually be cancelled via other external means (e.g.
- * the {@code Cancel} extended operation) for which there are well defined error
- * results. Therefore cancellation is always signalled by throwing a
- * {@link CancelledResultException} in order to be consistent with other error
- * results.
- * <li>A {@link ResultHandler} can be provided to the constructor. The result
- * handler will be invoked immediately after the result or error is received but
- * before threads blocked on {@link #get} are released. More specifically,
- * result handler invocation <i>happens-before</i> a call to {@link #get}.
- * <b>NOTE:</b> a result handler which attempts to call {@link #get} will
- * deadlock.
- * <li>Sub-classes may choose to implement specific cancellation cleanup by
- * implementing the {@link #handleCancelRequest} method.
- * </ul>
- *
- * @param <M>
- *          The type of result returned by this completion future.
- */
-public abstract class AbstractFutureResult<M> implements FutureResult<M>,
-    ResultHandler<M>
-{
-  @SuppressWarnings("serial")
-  private final class Sync extends AbstractQueuedSynchronizer
-  {
-    // State value representing the initial state before a result has
-    // been received.
-    private static final int WAITING = 0;
-
-    // State value representing that a result has been received and is
-    // being processed.
-    private static final int PENDING = 1;
-
-    // State value representing that the request was cancelled.
-    private static final int CANCELLED = 2;
-
-    // State value representing that the request has failed.
-    private static final int FAIL = 3;
-
-    // State value representing that the request has succeeded.
-    private static final int SUCCESS = 4;
-
-    // These do not need to be volatile since their values are published
-    // by updating the state after they are set and reading the state
-    // immediately before they are read.
-    private ErrorResultException errorResult = null;
-
-    private M result = null;
-
-
-
-    /**
-     * Allow all threads to acquire if future has completed.
-     */
-    @Override
-    protected int tryAcquireShared(final int ignore)
-    {
-      return innerIsDone() ? 1 : -1;
-    }
-
-
-
-    /**
-     * Signal that the future has completed and threads waiting on get() can be
-     * released.
-     */
-    @Override
-    protected boolean tryReleaseShared(final int finalState)
-    {
-      // Ensures that errorResult/result is published.
-      setState(finalState);
-      return true;
-    }
-
-
-
-    boolean innerCancel(final boolean mayInterruptIfRunning)
-    {
-      if (!isCancelable() || !setStatePending())
-      {
-        return false;
-      }
-
-      // Perform implementation defined cancellation.
-      ErrorResultException errorResult = handleCancelRequest(mayInterruptIfRunning);
-      if (errorResult == null)
-      {
-        final Result result = Responses
-            .newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED);
-        errorResult = ErrorResultException.wrap(result);
-      }
-      this.errorResult = errorResult;
-
-      try
-      {
-        // Invoke error result completion handler.
-        if (handler != null)
-        {
-          handler.handleErrorResult(errorResult);
-        }
-      }
-      finally
-      {
-        releaseShared(CANCELLED); // Publishes errorResult.
-      }
-
-      return true;
-    }
-
-
-
-    M innerGet() throws ErrorResultException, InterruptedException
-    {
-      acquireSharedInterruptibly(0);
-      return get0();
-    }
-
-
-
-    M innerGet(final long nanosTimeout) throws ErrorResultException,
-        TimeoutException, InterruptedException
-    {
-      if (!tryAcquireSharedNanos(0, nanosTimeout))
-      {
-        throw new TimeoutException();
-      }
-      else
-      {
-        return get0();
-      }
-    }
-
-
-
-    boolean innerIsCancelled()
-    {
-      return getState() == CANCELLED;
-    }
-
-
-
-    boolean innerIsDone()
-    {
-      return getState() > 1;
-    }
-
-
-
-    void innerSetErrorResult(final ErrorResultException errorResult)
-    {
-      if (setStatePending())
-      {
-        this.errorResult = errorResult;
-
-        try
-        {
-          // Invoke error result completion handler.
-          if (handler != null)
-          {
-            handler.handleErrorResult(errorResult);
-          }
-        }
-        finally
-        {
-          releaseShared(FAIL); // Publishes errorResult.
-        }
-      }
-    }
-
-
-
-    void innerSetResult(final M result)
-    {
-      if (setStatePending())
-      {
-        this.result = result;
-
-        try
-        {
-          // Invoke result completion handler.
-          if (handler != null)
-          {
-            handler.handleResult(result);
-          }
-        }
-        finally
-        {
-          releaseShared(SUCCESS); // Publishes result.
-        }
-      }
-    }
-
-
-
-    private M get0() throws ErrorResultException
-    {
-      if (errorResult != null)
-      {
-        // State must be FAILED or CANCELLED.
-        throw errorResult;
-      }
-      else
-      {
-        // State must be SUCCESS.
-        return result;
-      }
-    }
-
-
-
-    private boolean setStatePending()
-    {
-      for (;;)
-      {
-        final int s = getState();
-        if (s != WAITING)
-        {
-          return false;
-        }
-        if (compareAndSetState(s, PENDING))
-        {
-          return true;
-        }
-      }
-    }
-  }
-
-
-
-  private final Sync sync = new Sync();
-
-  private final ResultHandler<? super M> handler;
-
-
-
-  /**
-   * Creates a new abstract future result with the provided result handler.
-   *
-   * @param handler
-   *          A result handler which will be forwarded the result or error when
-   *          it arrives.
-   */
-  protected AbstractFutureResult(final ResultHandler<? super M> handler)
-  {
-    this.handler = handler;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public final boolean cancel(final boolean mayInterruptIfRunning)
-  {
-    return sync.innerCancel(mayInterruptIfRunning);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public final M get() throws ErrorResultException, InterruptedException
-  {
-    return sync.innerGet();
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public final M get(final long timeout, final TimeUnit unit)
-      throws ErrorResultException, TimeoutException, InterruptedException
-  {
-    return sync.innerGet(unit.toNanos(timeout));
-  }
-
-
-
-  /**
-   * Sets the error result associated with this future. If ({@code isDone() ==
-   * true}) then the error result will be ignored, otherwise the result handler
-   * will be invoked if one was provided and, on return, any threads waiting on
-   * {@link #get} will be released and the provided error result will be thrown.
-   *
-   * @param errorResult
-   *          The error result.
-   */
-  public final void handleErrorResult(final ErrorResultException errorResult)
-  {
-    sync.innerSetErrorResult(errorResult);
-  }
-
-
-
-  /**
-   * Sets the result associated with this future. If ({@code isDone() == true})
-   * then the result will be ignored, otherwise the result handler will be
-   * invoked if one was provided and, on return, any threads waiting on
-   * {@link #get} will be released and the provided result will be returned.
-   *
-   * @param result
-   *          The result.
-   */
-  public final void handleResult(final M result)
-  {
-    sync.innerSetResult(result);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public final boolean isCancelled()
-  {
-    return sync.innerIsCancelled();
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public final boolean isDone()
-  {
-    return sync.innerIsDone();
-  }
-
-
-
-  /**
-   * Invoked when {@link #cancel} is called and {@code isDone() == false} and
-   * immediately before any threads waiting on {@link #get} are released.
-   * Implementations may choose to return a custom error result if needed or
-   * return {@code null} if the following default error result is acceptable:
-   *
-   * <pre>
-   * Result result = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED);
-   * </pre>
-   *
-   * In addition, implementations may perform other cleanup, for example, by
-   * issuing an LDAP abandon request. The default implementation is to do
-   * nothing.
-   *
-   * @param mayInterruptIfRunning
-   *          {@code true} if the thread executing executing the response
-   *          handler should be interrupted; otherwise, in-progress response
-   *          handlers are allowed to complete.
-   * @return The custom error result, or {@code null} if the default is
-   *         acceptable.
-   */
-  protected ErrorResultException handleCancelRequest(
-      final boolean mayInterruptIfRunning)
-  {
-    // Do nothing by default.
-    return null;
-  }
-
-
-
-  /**
-   * Indicates whether this future result can be canceled.
-   *
-   * @return {@code true} if this future result is cancelable or {@code false}
-   *         otherwise.
-   */
-  protected boolean isCancelable()
-  {
-    // Return true by default.
-    return true;
-  }
-
-
-
-  /**
-   * Appends a string representation of this future's state to the provided
-   * builder.
-   *
-   * @param sb
-   *          The string builder.
-   */
-  protected void toString(final StringBuilder sb)
-  {
-    sb.append(" state = ");
-    sb.append(sync);
-  }
-
-}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/LDAPOptions.java b/opendj-sdk/sdk/src/org/opends/sdk/LDAPOptions.java
index f58cbfa..6e5a5d7 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/LDAPOptions.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/LDAPOptions.java
@@ -22,13 +22,14 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk;
 
 
 
+import java.util.*;
 import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.SSLContext;
@@ -53,12 +54,12 @@
   /**
    * The list of cipher suite
    */
-  private String[] enabledCipherSuites = null;
+  private List<String> enabledCipherSuites = new LinkedList<String>();
 
   /**
    * the list of protocols
    */
-  private String[] enabledProtocols = null;
+  private List<String> enabledProtocols = new LinkedList<String>();
 
 
 
@@ -90,8 +91,8 @@
     this.timeoutInMillis = options.timeoutInMillis;
     this.useStartTLS = options.useStartTLS;
     this.decodeOptions = new DecodeOptions(options.decodeOptions);
-    this.enabledCipherSuites = options.enabledCipherSuites;
-    this.enabledProtocols = options.enabledProtocols;
+    this.enabledCipherSuites.addAll(options.getEnabledCipherSuites());
+    this.enabledProtocols.addAll(options.getEnabledProtocols());
   }
 
 
@@ -237,7 +238,7 @@
   }
 
   /**
-   * Set the protocol versions enabled for secure connections with the
+   * Adds the protocol versions enabled for secure connections with the
    * Directory Server.
    *
    * The protocols must be supported by the SSLContext specified in
@@ -245,18 +246,20 @@
    * this method, only the protocols listed in the protocols parameter are
    * enabled for use.
    *
-   * @param protocols Names of all the protocols to enable or {@code null} to
-   *                  use the default protocols.
+   * @param protocols Names of all the protocols to enable.
    * @return A reference to this LDAP connection options.
    */
-  public final LDAPOptions setEnabledProtocols(String[] protocols)
+  public final LDAPOptions addEnabledProtocol(String... protocols)
   {
-    this.enabledProtocols = protocols;
+    for (final String protocol : protocols)
+    {
+      this.enabledProtocols.add(Validator.ensureNotNull(protocol));
+    }
     return this;
   }
 
   /**
-   * Set the cipher suites enabled for secure connections with the
+   * Adds the cipher suites enabled for secure connections with the
    * Directory Server.
    *
    * The suites must be supported by the SSLContext specified in
@@ -264,13 +267,15 @@
    * this method, only the suites listed in the protocols parameter are
    * enabled for use.
    *
-   * @param suites Names of all the suites to enable or {@code null} to
-   *                  use the default cipher suites.
+   * @param suites Names of all the suites to enable.
    * @return A reference to this LDAP connection options.
    */
-  public final LDAPOptions setEnabledCipherSuites(String[] suites)
+  public final LDAPOptions addEnabledCipherSuite(String... suites)
   {
-    this.enabledCipherSuites = suites;
+    for (final String suite : suites)
+    {
+      this.enabledCipherSuites.add(Validator.ensureNotNull(suite));
+    }
     return this;
   }
 
@@ -278,10 +283,10 @@
    * Returns the names of the protocol versions which are currently enabled
    * for secure connections with the Directory Server.
    *
-   * @return an array of protocols or {@code null} if the default protocols
+   * @return an array of protocols or empty set if the default protocols
    * are to be used.
    */
-  public final String[] getEnabledProtocols()
+  public final List<String> getEnabledProtocols()
   {
     return this.enabledProtocols;
   }
@@ -290,10 +295,10 @@
    * Returns the names of the protocol versions which are currently enabled
    * for secure connections with the Directory Server.
    *
-   * @return an array of protocols or {@code null} if the default protocols
+   * @return an array of protocols or empty set if the default protocols
    * are to be used.
    */
-  public final  String[] getEnabledCipherSuites()
+  public final List<String> getEnabledCipherSuites()
   {
     return this.enabledCipherSuites;
   }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbandonRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbandonRequestImpl.java
index b09275d..66c44ec 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbandonRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbandonRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -53,6 +53,23 @@
 
 
 
+  /**
+   * Creates a new abandon request that is an exact copy of the provided
+   * request.
+   *
+   * @param abandonRequest
+   *          The abandon request to be copied.
+   * @throws NullPointerException
+   *           If {@code abandonRequest} was {@code null} .
+   */
+  AbandonRequestImpl(final AbandonRequest abandonRequest)
+  {
+    super(abandonRequest);
+    this.requestID = abandonRequest.getRequestID();
+  }
+
+
+
   public int getRequestID()
   {
     return requestID;
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractBindRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractBindRequest.java
index c27281b..ef9b856 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractBindRequest.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractBindRequest.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -51,6 +51,22 @@
 
 
   /**
+   * Creates a new abstract bind request that is an exact copy of the provided
+   * request.
+   *
+   * @param bindRequest
+   *          The bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code bindRequest} was {@code null} .
+   */
+  protected AbstractBindRequest(BindRequest bindRequest)
+  {
+    super(bindRequest);
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   public abstract String getName();
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractExtendedRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractExtendedRequest.java
index 80f8dc8..280d646 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractExtendedRequest.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractExtendedRequest.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -62,6 +62,23 @@
 
 
   /**
+   * Creates a new extended request that is an exact copy of the provided
+   * request.
+   *
+   * @param extendedRequest
+   *          The extended request to be copied.
+   * @throws NullPointerException
+   *           If {@code extendedRequest} was {@code null} .
+   */
+  protected AbstractExtendedRequest(ExtendedRequest extendedRequest)
+      throws NullPointerException
+  {
+    super(extendedRequest);
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   public abstract String getOID();
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractRequestImpl.java
index c4ca148..e614f8d 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -64,6 +64,22 @@
 
 
   /**
+   * Creates a new abstract request that is an exact copy of the provided
+   * request.
+   *
+   * @param request
+   *          The request to be copied.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  AbstractRequestImpl(Request request) throws NullPointerException
+  {
+    Validator.ensureNotNull(request);
+    controls.addAll(request.getControls());
+  }
+
+
+  /**
    * {@inheritDoc}
    */
   public final R addControl(final Control control) throws NullPointerException
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractSASLBindRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractSASLBindRequest.java
index 6ecec66..f054b70 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractSASLBindRequest.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractSASLBindRequest.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -43,6 +43,21 @@
 abstract class AbstractSASLBindRequest<R extends SASLBindRequest> extends
     AbstractBindRequest<R> implements SASLBindRequest
 {
+
+  AbstractSASLBindRequest()
+  {
+
+  }
+
+
+
+  AbstractSASLBindRequest(SASLBindRequest saslBindRequest)
+  {
+    super(saslBindRequest);
+  }
+
+
+
   public final byte getAuthenticationType()
   {
     return TYPE_AUTHENTICATION_SASL;
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableExtendedRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableExtendedRequest.java
new file mode 100644
index 0000000..94445d4
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableExtendedRequest.java
@@ -0,0 +1,68 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.ExtendedResultDecoder;
+
+/**
+ * An abstract unmodifiable Extended request which can be used as the basis for
+ * implementing new unmodifiable Extended operations.
+ *
+ * @param <R>
+ *          The type of extended request.
+ * @param <S>
+ *          The type of result.
+ */
+abstract class
+    AbstractUnmodifiableExtendedRequest<R extends ExtendedRequest<S>,
+                                        S extends ExtendedResult>
+    extends AbstractUnmodifiableRequest<R>
+    implements ExtendedRequest<S>
+{
+  AbstractUnmodifiableExtendedRequest(R impl) {
+    super(impl);
+  }
+
+  public final String getOID() {
+    return impl.getOID();
+  }
+
+  public final ExtendedResultDecoder<S> getResultDecoder() {
+    return impl.getResultDecoder();
+  }
+
+  public final ByteString getValue() {
+    return impl.getValue();
+  }
+
+  public final boolean hasValue() {
+    return impl.hasValue();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequest.java
similarity index 91%
rename from opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequestImpl.java
rename to opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequest.java
index a3ecd70..3bba75c 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequest.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -45,11 +45,11 @@
  * @param <R>
  *          The type of request.
  */
-abstract class AbstractUnmodifiableRequestImpl<R extends Request> implements
+abstract class AbstractUnmodifiableRequest<R extends Request> implements
     Request
 {
 
-  private final R impl;
+  protected final R impl;
 
 
 
@@ -59,7 +59,7 @@
    * @param impl
    *          The underlying request implementation to be made unmodifiable.
    */
-  AbstractUnmodifiableRequestImpl(final R impl)
+  AbstractUnmodifiableRequest(final R impl)
   {
     this.impl = impl;
   }
diff --git a/opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableSASLBindRequest.java
similarity index 63%
copy from opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java
copy to opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableSASLBindRequest.java
index e85f12d..56f9945 100644
--- a/opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableSASLBindRequest.java
@@ -25,10 +25,26 @@
  *      Copyright 2010 Sun Microsystems, Inc.
  */
 
+package org.opends.sdk.requests;
+
 /**
- * Examples which use the OpenDS LDAP SDK.
+ * An abstract unmodifiable SASL Bind request which can be used as the basis for
+ * implementing new unmodifiable SASL authentication methods.
+ *
+ * @param <R>
+ *          The type of SASL Bind request.
  */
-package org.opends.sdk.examples;
+abstract class AbstractUnmodifiableSASLBindRequest
+    <R extends SASLBindRequest> extends
+    AbstractUnmodifiableBindRequest<R> implements SASLBindRequest
+{
 
+  AbstractUnmodifiableSASLBindRequest(R impl) {
+    super(impl);
+  }
 
-
+  @Override
+  public String getSASLMechanism() {
+    return impl.getSASLMechanism();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractaUnmodifiableBindRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractaUnmodifiableBindRequest.java
new file mode 100644
index 0000000..b512a3a
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractaUnmodifiableBindRequest.java
@@ -0,0 +1,58 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ErrorResultException;
+
+/**
+ * An abstract unmodifiable Bind request which can be used as the basis for
+ * implementing new unmodifiable authentication methods.
+ *
+ * @param <R>
+ *          The type of Bind request.
+ */
+abstract class AbstractUnmodifiableBindRequest<R extends BindRequest> extends
+    AbstractUnmodifiableRequest<R> implements BindRequest {
+
+  AbstractUnmodifiableBindRequest(R impl) {
+    super(impl);
+  }
+
+  public BindClient createBindClient(String serverName)
+      throws ErrorResultException {
+    return impl.createBindClient(serverName);
+  }
+
+  public byte getAuthenticationType() {
+    return impl.getAuthenticationType();
+  }
+
+  public String getName() {
+    return impl.getName();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/AddRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AddRequestImpl.java
index ce037cd..a0436b8 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/AddRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AddRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -66,6 +66,23 @@
 
 
   /**
+   * Creates a new add request that is an exact copy of the provided
+   * request.
+   *
+   * @param addRequest
+   *          The add request to be copied.
+   * @throws NullPointerException
+   *           If {@code addRequest} was {@code null} .
+   */
+  AddRequestImpl(final AddRequest addRequest) throws NullPointerException
+  {
+    super(addRequest);
+    this.entry = new LinkedHashMapEntry(addRequest);
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   public <R, P> R accept(final ChangeRecordVisitor<R, P> v, final P p)
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/AnonymousSASLBindRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AnonymousSASLBindRequest.java
index 5cc54a6..122ae18 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/AnonymousSASLBindRequest.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AnonymousSASLBindRequest.java
@@ -33,6 +33,7 @@
 
 import org.opends.sdk.DecodeException;
 import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.ErrorResultException;
 import org.opends.sdk.controls.Control;
 import org.opends.sdk.controls.ControlDecoder;
 
@@ -78,7 +79,7 @@
   /**
    * {@inheritDoc}
    */
-  BindClient createBindClient(String serverName);
+  BindClient createBindClient(String serverName) throws ErrorResultException;
 
 
 
@@ -143,9 +144,12 @@
    *          The trace information, which has no semantic value, and can be
    *          used by administrators in order to identify the user.
    * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this anonymous SASL request does not permit the trace
+   *           information to be set.
    * @throws NullPointerException
    *           If {@code traceString} was {@code null}.
    */
   AnonymousSASLBindRequest setTraceString(String traceString)
-      throws NullPointerException;
+      throws UnsupportedOperationException, NullPointerException;
 }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/AnonymousSASLBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AnonymousSASLBindRequestImpl.java
index 42dabc1..913e226 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/AnonymousSASLBindRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AnonymousSASLBindRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -68,6 +68,24 @@
 
 
   /**
+   * Creates a new anonymous SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param anonymousSASLBindRequest
+   *          The anonymous SASL bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code anonymousSASLBindRequest} was {@code null} .
+   */
+  AnonymousSASLBindRequestImpl(
+      final AnonymousSASLBindRequest anonymousSASLBindRequest)
+  {
+    super(anonymousSASLBindRequest);
+    this.traceString = anonymousSASLBindRequest.getTraceString();
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   public BindClient createBindClient(final String serverName)
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/CRAMMD5SASLBindRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/CRAMMD5SASLBindRequest.java
index fdd63c3..8136b3c 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/CRAMMD5SASLBindRequest.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/CRAMMD5SASLBindRequest.java
@@ -150,7 +150,10 @@
    *
    * @param authenticationID
    *          The authentication ID of the user.
-   * @return This bind request.
+   * @return This bind request
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the authentication ID to be
+   *           set..
    * @throws LocalizedIllegalArgumentException
    *           If {@code authenticationID} was non-empty and did not contain a
    *           valid authorization ID type.
@@ -158,7 +161,8 @@
    *           If {@code authenticationID} was {@code null}.
    */
   CRAMMD5SASLBindRequest setAuthenticationID(String authenticationID)
-      throws LocalizedIllegalArgumentException, NullPointerException;
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException,
+      NullPointerException;
 
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/CRAMMD5SASLBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/CRAMMD5SASLBindRequestImpl.java
index b959191..dfdc74c 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/CRAMMD5SASLBindRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/CRAMMD5SASLBindRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -167,6 +167,26 @@
 
 
   /**
+   * Creates a new CRAM MD5 SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param cramMD5SASLBindRequest
+   *          The CRAM MD5 SASL bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code cramMD5SASLBindRequest} was {@code null} .
+   */
+  CRAMMD5SASLBindRequestImpl(
+      final CRAMMD5SASLBindRequest cramMD5SASLBindRequest)
+      throws NullPointerException
+  {
+    super(cramMD5SASLBindRequest);
+    this.authenticationID = cramMD5SASLBindRequest.getAuthenticationID();
+    this.password = cramMD5SASLBindRequest.getPassword();
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   public BindClient createBindClient(final String serverName)
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/CancelExtendedRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/CancelExtendedRequestImpl.java
index 51e89f2..11cbd15 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/CancelExtendedRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/CancelExtendedRequestImpl.java
@@ -133,6 +133,24 @@
 
 
   /**
+   * Creates a new cancel extended request that is an exact copy of the provided
+   * request.
+   *
+   * @param cancelExtendedRequest
+   *          The cancel extended request to be copied.
+   * @throws NullPointerException
+   *           If {@code cancelExtendedRequest} was {@code null} .
+   */
+  CancelExtendedRequestImpl(final CancelExtendedRequest cancelExtendedRequest)
+      throws NullPointerException
+  {
+    super(cancelExtendedRequest);
+    this.requestID = cancelExtendedRequest.getRequestID();
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   public int getRequestID()
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/CompareRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/CompareRequestImpl.java
index 95f1ed9..d9bb0b2 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/CompareRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/CompareRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -79,6 +79,26 @@
 
 
   /**
+   * Creates a new compare request that is an exact copy of the provided
+   * request.
+   *
+   * @param compareRequest
+   *          The compare request to be copied.
+   * @throws NullPointerException
+   *           If {@code compareRequest} was {@code null} .
+   */
+  CompareRequestImpl(final CompareRequest compareRequest)
+      throws NullPointerException
+  {
+    super(compareRequest);
+    this.name = compareRequest.getName();
+    this.attributeDescription = compareRequest.getAttributeDescription();
+    this.assertionValue = compareRequest.getAssertionValue();
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   public ByteString getAssertionValue()
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/DeleteRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/DeleteRequestImpl.java
index 339a570..11d3842 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/DeleteRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/DeleteRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -63,6 +63,24 @@
 
 
   /**
+   * Creates a new delete request that is an exact copy of the provided
+   * request.
+   *
+   * @param deleteRequest
+   *          The add request to be copied.
+   * @throws NullPointerException
+   *           If {@code addRequest} was {@code null} .
+   */
+  DeleteRequestImpl(final DeleteRequest deleteRequest)
+      throws NullPointerException
+  {
+    super(deleteRequest);
+    this.name = deleteRequest.getName();
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   public <R, P> R accept(final ChangeRecordVisitor<R, P> v, final P p)
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/DigestMD5SASLBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/DigestMD5SASLBindRequestImpl.java
index cce0537..7b08145 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/DigestMD5SASLBindRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/DigestMD5SASLBindRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -317,6 +317,38 @@
 
 
   /**
+   * Creates a new digest MD5 SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param digestMD5SASLBindRequest
+   *          The digest MD5 SASL bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code digestMD5SASLBindRequest} was {@code null} .
+   */
+  DigestMD5SASLBindRequestImpl(
+      final DigestMD5SASLBindRequest digestMD5SASLBindRequest)
+      throws NullPointerException
+  {
+    super(digestMD5SASLBindRequest);
+    this.additionalAuthParams.putAll(
+        digestMD5SASLBindRequest.getAdditionalAuthParams());
+    this.qopValues.addAll(digestMD5SASLBindRequest.getQOPs());
+    this.cipher = digestMD5SASLBindRequest.getCipher();
+
+    this.serverAuth = digestMD5SASLBindRequest.isServerAuth();
+    this.maxReceiveBufferSize =
+        digestMD5SASLBindRequest.getMaxReceiveBufferSize();
+    this.maxSendBufferSize = digestMD5SASLBindRequest.getMaxSendBufferSize();
+
+    this.authenticationID = digestMD5SASLBindRequest.getAuthenticationID();
+    this.authorizationID = digestMD5SASLBindRequest.getAuthorizationID();
+    this.password = digestMD5SASLBindRequest.getPassword();
+    this.realm = digestMD5SASLBindRequest.getRealm();
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   @Override
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/ExternalSASLBindRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/ExternalSASLBindRequest.java
index 436d38c..ab1a2bc 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/ExternalSASLBindRequest.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/ExternalSASLBindRequest.java
@@ -150,11 +150,14 @@
    *          The desired authorization ID of the user, which may be {@code
    *          null}.
    * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this external SASL request does not permit the authorization
+   *           ID to be set.
    * @throws LocalizedIllegalArgumentException
    *           If {@code authorizationID} was non-empty and did not contain a
    *           valid authorization ID type.
    */
   ExternalSASLBindRequest setAuthorizationID(String authorizationID)
-      throws LocalizedIllegalArgumentException;
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException;
 
 }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/ExternalSASLBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/ExternalSASLBindRequestImpl.java
index b6afa0d..361d10a 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/ExternalSASLBindRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/ExternalSASLBindRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -135,6 +135,25 @@
 
 
   /**
+   * Creates a new external SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param externalSASLBindRequest
+   *          The external SASL bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code externalSASLBindRequest} was {@code null} .
+   */
+  ExternalSASLBindRequestImpl(
+      final ExternalSASLBindRequest externalSASLBindRequest)
+      throws NullPointerException
+  {
+    super(externalSASLBindRequest);
+    this.authorizationID = externalSASLBindRequest.getAuthorizationID();
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   public BindClient createBindClient(final String serverName)
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/GSSAPISASLBindRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/GSSAPISASLBindRequest.java
index 814efae..cac8583 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/GSSAPISASLBindRequest.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/GSSAPISASLBindRequest.java
@@ -506,8 +506,12 @@
    * @param subject
    *          The Kerberos subject of the user to be authenticated.
    * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the Kerberos subject to be
+   *           set.
    * @throws NullPointerException
    *           If {@code subject} was {@code null}.
    */
-  GSSAPISASLBindRequest setSubject(Subject subject) throws NullPointerException;
+  GSSAPISASLBindRequest setSubject(Subject subject)
+      throws UnsupportedOperationException, NullPointerException;
 }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/GSSAPISASLBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/GSSAPISASLBindRequestImpl.java
index afee8e3..f5e6ada 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/GSSAPISASLBindRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/GSSAPISASLBindRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -404,6 +404,41 @@
 
 
 
+  /**
+   * Creates a new GSSAPI SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param gssapiSASLBindRequest
+   *          The GSSAPI SASL bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code gssAPISASLBindRequest} was {@code null}.
+   */
+  GSSAPISASLBindRequestImpl(
+      final GSSAPISASLBindRequest gssapiSASLBindRequest)
+      throws NullPointerException
+  {
+    super(gssapiSASLBindRequest);
+    this.subject = gssapiSASLBindRequest.getSubject();
+
+    this.authenticationID = gssapiSASLBindRequest.getAuthenticationID();
+    this.password = gssapiSASLBindRequest.getPassword();
+    this.realm = gssapiSASLBindRequest.getRealm();
+
+    this.kdcAddress = gssapiSASLBindRequest.getKDCAddress();
+
+    this.authorizationID = gssapiSASLBindRequest.getAuthorizationID();
+
+    this.additionalAuthParams.putAll(
+        gssapiSASLBindRequest.getAdditionalAuthParams());
+    this.qopValues.addAll(gssapiSASLBindRequest.getQOPs());
+
+    this.serverAuth = gssapiSASLBindRequest.isServerAuth();
+    this.maxReceiveBufferSize = gssapiSASLBindRequest.getMaxReceiveBufferSize();
+    this.maxSendBufferSize = gssapiSASLBindRequest.getMaxSendBufferSize();
+  }
+
+
+
   GSSAPISASLBindRequestImpl(final Subject subject)
   {
     Validator.ensureNotNull(subject);
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/GenericBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/GenericBindRequestImpl.java
index 952dcc1..88b4936 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/GenericBindRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/GenericBindRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -83,6 +83,28 @@
 
 
 
+  /**
+   * Creates a new generic bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param genericBindRequest
+   *          The generic bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code genericBindRequest} was {@code null} .
+   */
+  GenericBindRequestImpl(
+      final GenericBindRequest genericBindRequest)
+      throws NullPointerException
+  {
+    super(genericBindRequest);
+    this.name = genericBindRequest.getName();
+    this.authenticationType = genericBindRequest.getAuthenticationType();
+    this.authenticationValue = genericBindRequest.getAuthenticationValue();
+    this.bindClient = null; // Create a new bind client each time.
+  }
+
+
+
   public BindClient createBindClient(final String serverName)
       throws ErrorResultException
   {
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/GenericExtendedRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/GenericExtendedRequestImpl.java
index b11f25d..135c4d5 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/GenericExtendedRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/GenericExtendedRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -146,6 +146,26 @@
 
 
   /**
+   * Creates a new generic extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param genericExtendedRequest
+   *          The generic extended request to be copied.
+   * @throws NullPointerException
+   *           If {@code extendedRequest} was {@code null} .
+   */
+  protected GenericExtendedRequestImpl(
+      GenericExtendedRequest genericExtendedRequest)
+      throws NullPointerException
+  {
+    super(genericExtendedRequest);
+    this.requestName = genericExtendedRequest.getOID();
+    this.requestValue = genericExtendedRequest.getValue();
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   @Override
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyDNRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyDNRequestImpl.java
index 4d6ed55..7794f29 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyDNRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyDNRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -75,6 +75,27 @@
 
 
   /**
+   * Creates a new modify DN request that is an exact copy of the provided
+   * request.
+   *
+   * @param modifyDNRequest
+   *          The modify DN request to be copied.
+   * @throws NullPointerException
+   *           If {@code modifyDNRequest} was {@code null} .
+   */
+  ModifyDNRequestImpl(final ModifyDNRequest modifyDNRequest)
+      throws NullPointerException
+  {
+    super(modifyDNRequest);
+    this.name = modifyDNRequest.getName();
+    this.newSuperior = modifyDNRequest.getNewSuperior();
+    this.newRDN = modifyDNRequest.getNewRDN();
+    this.deleteOldRDN = modifyDNRequest.isDeleteOldRDN();
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   public <R, P> R accept(final ChangeRecordVisitor<R, P> v, final P p)
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyRequestImpl.java
index d7fe851..1f07117 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -67,6 +67,25 @@
 
 
   /**
+   * Creates a new modify request that is an exact copy of the provided
+   * request.
+   *
+   * @param modifyRequest
+   *          The modify request to be copied.
+   * @throws NullPointerException
+   *           If {@code modifyRequest} was {@code null} .
+   */
+  ModifyRequestImpl(final ModifyRequest modifyRequest)
+      throws NullPointerException
+  {
+    super(modifyRequest);
+    this.name = modifyRequest.getName();
+    this.changes.addAll(modifyRequest.getModifications());
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   public <R, P> R accept(final ChangeRecordVisitor<R, P> v, final P p)
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/PasswordModifyExtendedRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/PasswordModifyExtendedRequest.java
index 5812d0a..416b0d4 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/PasswordModifyExtendedRequest.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/PasswordModifyExtendedRequest.java
@@ -201,8 +201,12 @@
    *          The desired password for the user, or {@code null} if a new
    *          password should be generated.
    * @return This password modify request.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended request does not permit the new
+   *           password to be set.
    */
-  PasswordModifyExtendedRequest setNewPassword(ByteString newPassword);
+  PasswordModifyExtendedRequest setNewPassword(ByteString newPassword)
+      throws UnsupportedOperationException;
 
 
 
@@ -214,8 +218,12 @@
    *          The desired password for the user, or {@code null} if a new
    *          password should be generated.
    * @return This password modify request.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended request does not permit the new
+   *           password to be set.
    */
-  PasswordModifyExtendedRequest setNewPassword(String newPassword);
+  PasswordModifyExtendedRequest setNewPassword(String newPassword)
+      throws UnsupportedOperationException;
 
 
 
@@ -226,8 +234,12 @@
    *          The current password for the user, or {@code null} if the password
    *          is not known.
    * @return This password modify request.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended request does not permit the old
+   *           password to be set.
    */
-  PasswordModifyExtendedRequest setOldPassword(ByteString oldPassword);
+  PasswordModifyExtendedRequest setOldPassword(ByteString oldPassword)
+      throws UnsupportedOperationException;
 
 
 
@@ -239,8 +251,12 @@
    *          The current password for the user, or {@code null} if the password
    *          is not known.
    * @return This password modify request.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended request does not permit the old
+   *           password to be set.
    */
-  PasswordModifyExtendedRequest setOldPassword(String oldPassword);
+  PasswordModifyExtendedRequest setOldPassword(String oldPassword)
+      throws UnsupportedOperationException;
 
 
 
@@ -253,8 +269,12 @@
    *          {@code null} if the request should be applied to the user
    *          currently associated with the session.
    * @return This password modify request.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended request does not permit the user
+   *           identity to be set.
    */
-  PasswordModifyExtendedRequest setUserIdentity(ByteString userIdentity);
+  PasswordModifyExtendedRequest setUserIdentity(ByteString userIdentity)
+      throws UnsupportedOperationException;
 
 
 
@@ -268,7 +288,11 @@
    *          {@code null} if the request should be applied to the user
    *          currently associated with the session.
    * @return This password modify request.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended request does not permit the user
+   *           identity to be set.
    */
-  PasswordModifyExtendedRequest setUserIdentity(String userIdentity);
+  PasswordModifyExtendedRequest setUserIdentity(String userIdentity)
+      throws UnsupportedOperationException;
 
 }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/PasswordModifyExtendedRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/PasswordModifyExtendedRequestImpl.java
index ee19507..ece2e20 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/PasswordModifyExtendedRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/PasswordModifyExtendedRequestImpl.java
@@ -210,6 +210,27 @@
 
 
   /**
+   * Creates a new password modify extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param passwordModifyExtendedRequest
+   *          The password modify extended request to be copied.
+   * @throws NullPointerException
+   *           If {@code passwordModifyExtendedRequest} was {@code null} .
+   */
+  PasswordModifyExtendedRequestImpl(
+      final PasswordModifyExtendedRequest passwordModifyExtendedRequest)
+      throws NullPointerException
+  {
+    super(passwordModifyExtendedRequest);
+    this.userIdentity = passwordModifyExtendedRequest.getUserIdentity();
+    this.oldPassword = passwordModifyExtendedRequest.getOldPassword();
+    this.newPassword = passwordModifyExtendedRequest.getNewPassword();
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   public ByteString getNewPassword()
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/PlainSASLBindRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/PlainSASLBindRequest.java
index 67aa6f8..fccb0e8 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/PlainSASLBindRequest.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/PlainSASLBindRequest.java
@@ -158,6 +158,9 @@
    * @param authenticationID
    *          The authentication ID of the user.
    * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the authentication ID to be
+   *           set.
    * @throws LocalizedIllegalArgumentException
    *           If {@code authenticationID} was non-empty and did not contain a
    *           valid authorization ID type.
@@ -165,7 +168,8 @@
    *           If {@code authenticationID} was {@code null}.
    */
   PlainSASLBindRequest setAuthenticationID(String authenticationID)
-      throws LocalizedIllegalArgumentException, NullPointerException;
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException,
+      NullPointerException;
 
 
 
@@ -179,12 +183,15 @@
    * @param authorizationID
    *          The authorization ID of the user, which may be {@code null}.
    * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the authorization ID to be
+   *           set.
    * @throws LocalizedIllegalArgumentException
    *           If {@code authorizationID} was non-empty and did not contain a
    *           valid authorization ID type.
    */
   PlainSASLBindRequest setAuthorizationID(String authorizationID)
-      throws LocalizedIllegalArgumentException;
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException;
 
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/PlainSASLBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/PlainSASLBindRequestImpl.java
index 0be59bb..75fb011 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/PlainSASLBindRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/PlainSASLBindRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -153,6 +153,27 @@
 
 
 
+  /**
+   * Creates a new plain SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param plainSASLBindRequest
+   *          The plain SASL bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code plainSASLBindRequest} was {@code null} .
+   */
+  PlainSASLBindRequestImpl(
+      final PlainSASLBindRequest plainSASLBindRequest)
+      throws NullPointerException
+  {
+    super(plainSASLBindRequest);
+    this.authenticationID = plainSASLBindRequest.getAuthenticationID();
+    this.authorizationID = plainSASLBindRequest.getAuthorizationID();
+    this.password = plainSASLBindRequest.getPassword();
+  }
+
+
+
   public BindClient createBindClient(final String serverName)
       throws ErrorResultException
   {
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/Requests.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/Requests.java
index eab61a4..f3963ab 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/Requests.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/Requests.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -50,8 +50,6 @@
  * TODO: update request from persistent search result.
  * <p>
  * TODO: synchronized requests?
- * <p>
- * TODO: copy constructors.
  */
 public final class Requests
 {
@@ -876,6 +874,787 @@
 
 
 
+
+  /**
+   * Creates an unmodifiable abandon request of the provided request.
+   *
+   * @param abandonRequest
+   *          The abandon request to be copied.
+   * @return The new abandon request.
+   * @throws NullPointerException
+   *           If {@code abandonRequest} was {@code null}
+   */
+  public static AbandonRequest unmodifiableAbandonRequest(
+      final AbandonRequest abandonRequest) throws NullPointerException
+  {
+    return new UnmodifiableAbandonRequestImpl(abandonRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable add request of the provided request.
+   *
+   * @param addRequest
+   *          The add request to be copied.
+   * @return The new add request.
+   * @throws NullPointerException
+   *           If {@code addRequest} was {@code null} .
+   */
+  public static AddRequest unmodifiableAddRequest(final AddRequest addRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableAddRequestImpl(addRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable anonymous SASL bind request of the provided request.
+   *
+   * @param anonymousSASLBindRequest
+   *          The anonymous SASL bind request to be copied.
+   * @return The new anonymous SASL bind request.
+   * @throws NullPointerException
+   *           If {@code anonymousSASLBindRequest} was {@code null} .
+   */
+  public static AnonymousSASLBindRequest unmodifiableAnonymousSASLBindRequest(
+      final AnonymousSASLBindRequest anonymousSASLBindRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableAnonymousSASLBindRequestImpl(
+        anonymousSASLBindRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable cancel extended request of the provided request.
+   *
+   * @param cancelExtendedRequest
+   *          The cancel extended request to be copied.
+   * @return The new cancel extended request.
+   * @throws NullPointerException
+   *           If {@code cancelExtendedRequest} was {@code null} .
+   */
+  public static CancelExtendedRequest unmodifiableCancelExtendedRequest(
+      final CancelExtendedRequest cancelExtendedRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableCancelExtendedRequestImpl(cancelExtendedRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable compare request of the provided request.
+   *
+   * @param compareRequest
+   *          The compare request to be copied.
+   * @return The new compare request.
+   * @throws NullPointerException
+   *           If {@code compareRequest} was {@code null} .
+   */
+  public static CompareRequest unmodifiableCompareRequest(
+      final CompareRequest compareRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableCompareRequestImpl(compareRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable CRAM MD5 SASL bind request of the provided request.
+   *
+   * @param cramMD5SASLBindRequest
+   *          The CRAM MD5 SASL bind request to be copied.
+   * @return The new CRAM-MD5 SASL bind request.
+   * @throws NullPointerException
+   *           If {@code authenticationID} or {@code password} was {@code null}.
+   */
+  public static CRAMMD5SASLBindRequest unmodifiableCRAMMD5SASLBindRequest(
+      final CRAMMD5SASLBindRequest cramMD5SASLBindRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableCRAMMD5SASLBindRequestImpl(cramMD5SASLBindRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable delete request of the provided request.
+   *
+   * @param deleteRequest
+   *          The add request to be copied.
+   * @return The new delete request.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public static DeleteRequest unmodifiableDeleteRequest(
+      final DeleteRequest deleteRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableDeleteRequestImpl(deleteRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable digest MD5 SASL bind request of the provided
+   * request.
+   *
+   * @param digestMD5SASLBindRequest
+   *          The digest MD5 SASL bind request to be copied.
+   * @return The new DIGEST-MD5 SASL bind request.
+   * @throws NullPointerException
+   *           If {@code authenticationID} or {@code password} was {@code null}.
+   */
+  public static DigestMD5SASLBindRequest unmodifiableDigestMD5SASLBindRequest(
+      final DigestMD5SASLBindRequest digestMD5SASLBindRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableDigestMD5SASLBindRequestImpl(
+        digestMD5SASLBindRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable external SASL bind request of the provided request.
+   *
+   * @param externalSASLBindRequest
+   *          The external SASL bind request to be copied.
+   * @return The new External SASL bind request.
+   * @throws NullPointerException
+   *           If {@code externalSASLBindRequest} was {@code null} .
+   */
+  public static ExternalSASLBindRequest unmodifiableExternalSASLBindRequest(
+      final ExternalSASLBindRequest externalSASLBindRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableExternalSASLBindRequestImpl(externalSASLBindRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable generic bind request of the provided request.
+   *
+   * @param genericBindRequest
+   *          The generic bind request to be copied.
+   * @return The new generic bind request.
+   * @throws NullPointerException
+   *           If {@code genericBindRequest} was {@code null} .
+   */
+  public static GenericBindRequest unmodifiableGenericBindRequest(
+      final GenericBindRequest genericBindRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableGenericBindRequestImpl(genericBindRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable generic extended request of the provided request.
+   *
+   * @param genericExtendedRequest
+   *          The generic extended request to be copied.
+   * @return The new generic extended request.
+   * @throws NullPointerException
+   *           If {@code extendedRequest} was {@code null} .
+   */
+  public static GenericExtendedRequest unmodifiableGenericExtendedRequest(
+      GenericExtendedRequest genericExtendedRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableGenericExtendedRequestImpl(genericExtendedRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable GSSAPI SASL bind request of the provided request.
+   *
+   * @param gssapiSASLBindRequest
+   *          The GSSAPI SASL bind request to be copied.
+   * @return The new GSSAPI SASL bind request.
+   * @throws NullPointerException
+   *           If {@code gssAPISASLBindRequest} was {@code null}.
+   */
+  public static GSSAPISASLBindRequest unmodifiableGSSAPISASLBindRequest(
+      final GSSAPISASLBindRequest gssapiSASLBindRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableGSSAPISASLBindRequestImpl(gssapiSASLBindRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable modify DN request of the provided request.
+   *
+   * @param modifyDNRequest
+   *          The modify DN request to be copied.
+   * @return The new modify DN request.
+   * @throws NullPointerException
+   *           If {@code modifyDNRequest} was {@code null} .
+   */
+  public static ModifyDNRequest unmodifiableModifyDNRequest(
+      final ModifyDNRequest modifyDNRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableModifyDNRequestImpl(modifyDNRequest);
+  }
+
+
+  /**
+   * Creates an unmodifiable modify request of the provided request.
+   *
+   * @param modifyRequest
+   *          The modify request to be copied.
+   * @return The new modify request.
+   * @throws NullPointerException
+   *           If {@code modifyRequest} was {@code null} .
+   */
+  public static ModifyRequest unmodifiableModifyRequest(
+      final ModifyRequest modifyRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableModifyRequestImpl(modifyRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable password modify extended request of the provided
+   * request.
+   *
+   * @param passwordModifyExtendedRequest
+   *          The password modify extended request to be copied.
+   * @return The new password modify extended request.
+   * @throws NullPointerException
+   *           If {@code passwordModifyExtendedRequest} was {@code null} .
+   */
+  public static PasswordModifyExtendedRequest
+      unmodifiablePasswordModifyExtendedRequest(
+        final PasswordModifyExtendedRequest passwordModifyExtendedRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiablePasswordModifyExtendedRequestImpl(
+        passwordModifyExtendedRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable plain SASL bind request of the provided request.
+   *
+   * @param plainSASLBindRequest
+   *          The plain SASL bind request to be copied.
+   * @return The new Plain SASL bind request.
+   * @throws NullPointerException
+   *           If {@code plainSASLBindRequest} was {@code null} .
+   */
+  public static PlainSASLBindRequest unmodifiablePlainSASLBindRequest(
+      final PlainSASLBindRequest plainSASLBindRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiablePlainSASLBindRequestImpl(plainSASLBindRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable search request of the provided request.
+   *
+   * @param searchRequest
+   *          The search request to be copied.
+   * @return The new search request.
+   * @throws NullPointerException
+   *           If {@code searchRequest} was {@code null} .
+   */
+  public static SearchRequest unmodifiableSearchRequest(
+      final SearchRequest searchRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableSearchRequestImpl(searchRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable simple bind request of the provided request.
+   *
+   * @param simpleBindRequest
+   *          The simple bind request to be copied.
+   * @return The new simple bind request.
+   * @throws NullPointerException
+   *           If {@code simpleBindRequest} was {@code null} .
+   */
+  public static SimpleBindRequest unmodifiableSimpleBindRequest(
+      final SimpleBindRequest simpleBindRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableSimpleBindRequestImpl(simpleBindRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable startTLS extended request of the provided request.
+   *
+   * @param startTLSExtendedRequest
+   *          The startTLS extended request to be copied.
+   * @return The new start TLS extended request.
+   * @throws NullPointerException
+   *           If {@code startTLSExtendedRequest} was {@code null} .
+   */
+  public static StartTLSExtendedRequest unmodifiableStartTLSExtendedRequest(
+      final StartTLSExtendedRequest startTLSExtendedRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableStartTLSExtendedRequestImpl(startTLSExtendedRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable unbind request of the provided request.
+   *
+   * @param unbindRequest
+   *          The unbind request to be copied.
+   * @return The new unbind request.
+   * @throws NullPointerException
+   *           If {@code unbindRequest} was {@code null} .
+   */
+  public static UnbindRequest unmodifiableUnbindRequest(
+      final UnbindRequest unbindRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableUnbindRequestImpl(unbindRequest);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable new Who Am I extended request of the provided
+   * request.
+   *
+   * @param whoAmIExtendedRequest
+   *          The who Am I extended request to be copied.
+   * @return The new Who Am I extended request.
+   * @throws NullPointerException
+   *           If {@code whoAmIExtendedRequest} was {@code null} .
+   */
+  public static WhoAmIExtendedRequest unmodifiableWhoAmIExtendedRequest(
+      final WhoAmIExtendedRequest whoAmIExtendedRequest)
+      throws NullPointerException
+  {
+    return new UnmodifiableWhoAmIExtendedRequestImpl(whoAmIExtendedRequest);
+  }
+
+
+
+
+  /**
+   * Creates a new abandon request that is an exact copy of the provided
+   * request.
+   *
+   * @param abandonRequest
+   *          The abandon request to be copied.
+   * @return The new abandon request.
+   * @throws NullPointerException
+   *           If {@code abandonRequest} was {@code null}
+   */
+  public static AbandonRequest copyOfAbandonRequest(
+      final AbandonRequest abandonRequest) throws NullPointerException
+  {
+    return new AbandonRequestImpl(abandonRequest);
+  }
+
+
+
+  /**
+   * Creates a new add request that is an exact copy of the provided
+   * request.
+   *
+   * @param addRequest
+   *          The add request to be copied.
+   * @return The new add request.
+   * @throws NullPointerException
+   *           If {@code addRequest} was {@code null} .
+   */
+  public static AddRequest copyOfAddRequest(final AddRequest addRequest)
+      throws NullPointerException
+  {
+    return new AddRequestImpl(addRequest);
+  }
+
+
+
+  /**
+   * Creates a new anonymous SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param anonymousSASLBindRequest
+   *          The anonymous SASL bind request to be copied.
+   * @return The new anonymous SASL bind request.
+   * @throws NullPointerException
+   *           If {@code anonymousSASLBindRequest} was {@code null} .
+   */
+  public static AnonymousSASLBindRequest copyOfAnonymousSASLBindRequest(
+      final AnonymousSASLBindRequest anonymousSASLBindRequest)
+      throws NullPointerException
+  {
+    return new AnonymousSASLBindRequestImpl(anonymousSASLBindRequest);
+  }
+
+
+
+  /**
+   * Creates a new cancel extended request that is an exact copy of the provided
+   * request.
+   *
+   * @param cancelExtendedRequest
+   *          The cancel extended request to be copied.
+   * @return The new cancel extended request.
+   * @throws NullPointerException
+   *           If {@code cancelExtendedRequest} was {@code null} .
+   */
+  public static CancelExtendedRequest copyOfCancelExtendedRequest(
+      final CancelExtendedRequest cancelExtendedRequest)
+      throws NullPointerException
+  {
+    return new CancelExtendedRequestImpl(cancelExtendedRequest);
+  }
+
+
+
+  /**
+   * Creates a new compare request that is an exact copy of the provided
+   * request.
+   *
+   * @param compareRequest
+   *          The compare request to be copied.
+   * @return The new compare request.
+   * @throws NullPointerException
+   *           If {@code compareRequest} was {@code null} .
+   */
+  public static CompareRequest copyOfCompareRequest(
+      final CompareRequest compareRequest)
+      throws NullPointerException
+  {
+    return new CompareRequestImpl(compareRequest);
+  }
+
+
+
+  /**
+   * Creates a new CRAM MD5 SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param cramMD5SASLBindRequest
+   *          The CRAM MD5 SASL bind request to be copied.
+   * @return The new CRAM-MD5 SASL bind request.
+   * @throws NullPointerException
+   *           If {@code authenticationID} or {@code password} was {@code null}.
+   */
+  public static CRAMMD5SASLBindRequest copyOfCRAMMD5SASLBindRequest(
+      final CRAMMD5SASLBindRequest cramMD5SASLBindRequest)
+      throws NullPointerException
+  {
+    return new CRAMMD5SASLBindRequestImpl(cramMD5SASLBindRequest);
+  }
+
+
+
+  /**
+   * Creates a new delete request that is an exact copy of the provided
+   * request.
+   *
+   * @param deleteRequest
+   *          The add request to be copied.
+   * @return The new delete request.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public static DeleteRequest copyOfDeleteRequest(
+      final DeleteRequest deleteRequest)
+      throws NullPointerException
+  {
+    return new DeleteRequestImpl(deleteRequest);
+  }
+
+
+
+  /**
+   * Creates a new digest MD5 SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param digestMD5SASLBindRequest
+   *          The digest MD5 SASL bind request to be copied.
+   * @return The new DIGEST-MD5 SASL bind request.
+   * @throws NullPointerException
+   *           If {@code authenticationID} or {@code password} was {@code null}.
+   */
+  public static DigestMD5SASLBindRequest copyOfDigestMD5SASLBindRequest(
+      final DigestMD5SASLBindRequest digestMD5SASLBindRequest)
+      throws NullPointerException
+  {
+    return new DigestMD5SASLBindRequestImpl(digestMD5SASLBindRequest);
+  }
+
+
+
+  /**
+   * Creates a new external SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param externalSASLBindRequest
+   *          The external SASL bind request to be copied.
+   * @return The new External SASL bind request.
+   * @throws NullPointerException
+   *           If {@code externalSASLBindRequest} was {@code null} .
+   */
+  public static ExternalSASLBindRequest copyOfExternalSASLBindRequest(
+      final ExternalSASLBindRequest externalSASLBindRequest)
+      throws NullPointerException
+  {
+    return new ExternalSASLBindRequestImpl(externalSASLBindRequest);
+  }
+
+
+
+  /**
+   * Creates a new generic bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param genericBindRequest
+   *          The generic bind request to be copied.
+   * @return The new generic bind request.
+   * @throws NullPointerException
+   *           If {@code genericBindRequest} was {@code null} .
+   */
+  public static GenericBindRequest copyOfGenericBindRequest(
+      final GenericBindRequest genericBindRequest)
+      throws NullPointerException
+  {
+    return new GenericBindRequestImpl(genericBindRequest);
+  }
+
+
+
+  /**
+   * Creates a new generic extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param genericExtendedRequest
+   *          The generic extended request to be copied.
+   * @return The new generic extended request.
+   * @throws NullPointerException
+   *           If {@code extendedRequest} was {@code null} .
+   */
+  public static GenericExtendedRequest copyOfGenericExtendedRequest(
+      GenericExtendedRequest genericExtendedRequest)
+      throws NullPointerException
+  {
+    return new GenericExtendedRequestImpl(genericExtendedRequest);
+  }
+
+
+
+  /**
+   * Creates a new GSSAPI SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param gssapiSASLBindRequest
+   *          The GSSAPI SASL bind request to be copied.
+   * @return The new GSSAPI SASL bind request.
+   * @throws NullPointerException
+   *           If {@code gssAPISASLBindRequest} was {@code null}.
+   */
+  public static GSSAPISASLBindRequest copyOfGSSAPISASLBindRequest(
+      final GSSAPISASLBindRequest gssapiSASLBindRequest)
+      throws NullPointerException
+  {
+    return new GSSAPISASLBindRequestImpl(gssapiSASLBindRequest);
+  }
+
+
+
+  /**
+   * Creates a new modify DN request that is an exact copy of the provided
+   * request.
+   *
+   * @param modifyDNRequest
+   *          The modify DN request to be copied.
+   * @return The new modify DN request.
+   * @throws NullPointerException
+   *           If {@code modifyDNRequest} was {@code null} .
+   */
+  public static ModifyDNRequest copyOfModifyDNRequest(
+      final ModifyDNRequest modifyDNRequest)
+      throws NullPointerException
+  {
+    return new ModifyDNRequestImpl(modifyDNRequest);
+  }
+
+
+  /**
+   * Creates a new modify request that is an exact copy of the provided
+   * request.
+   *
+   * @param modifyRequest
+   *          The modify request to be copied.
+   * @return The new modify request.
+   * @throws NullPointerException
+   *           If {@code modifyRequest} was {@code null} .
+   */
+  public static ModifyRequest copyOfModifyRequest(
+      final ModifyRequest modifyRequest)
+      throws NullPointerException
+  {
+    return new ModifyRequestImpl(modifyRequest);
+  }
+
+
+
+  /**
+   * Creates a new password modify extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param passwordModifyExtendedRequest
+   *          The password modify extended request to be copied.
+   * @return The new password modify extended request.
+   * @throws NullPointerException
+   *           If {@code passwordModifyExtendedRequest} was {@code null} .
+   */
+  public static PasswordModifyExtendedRequest
+      copyOfPasswordModifyExtendedRequest(
+        final PasswordModifyExtendedRequest passwordModifyExtendedRequest)
+      throws NullPointerException
+  {
+    return new PasswordModifyExtendedRequestImpl(passwordModifyExtendedRequest);
+  }
+
+
+
+  /**
+   * Creates a new plain SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param plainSASLBindRequest
+   *          The plain SASL bind request to be copied.
+   * @return The new Plain SASL bind request.
+   * @throws NullPointerException
+   *           If {@code plainSASLBindRequest} was {@code null} .
+   */
+  public static PlainSASLBindRequest copyOfPlainSASLBindRequest(
+      final PlainSASLBindRequest plainSASLBindRequest)
+      throws NullPointerException
+  {
+    return new PlainSASLBindRequestImpl(plainSASLBindRequest);
+  }
+
+
+
+  /**
+   * Creates a new search request that is an exact copy of the provided
+   * request.
+   *
+   * @param searchRequest
+   *          The search request to be copied.
+   * @return The new search request.
+   * @throws NullPointerException
+   *           If {@code searchRequest} was {@code null} .
+   */
+  public static SearchRequest copyOfSearchRequest(
+      final SearchRequest searchRequest)
+      throws NullPointerException
+  {
+    return new SearchRequestImpl(searchRequest);
+  }
+
+
+
+  /**
+   * Creates a new simple bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param simpleBindRequest
+   *          The simple bind request to be copied.
+   * @return The new simple bind request.
+   * @throws NullPointerException
+   *           If {@code simpleBindRequest} was {@code null} .
+   */
+  public static SimpleBindRequest copyOfSimpleBindRequest(
+      final SimpleBindRequest simpleBindRequest)
+      throws NullPointerException
+  {
+    return new SimpleBindRequestImpl(simpleBindRequest);
+  }
+
+
+
+  /**
+   * Creates a new startTLS extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param startTLSExtendedRequest
+   *          The startTLS extended request to be copied.
+   * @return The new start TLS extended request.
+   * @throws NullPointerException
+   *           If {@code startTLSExtendedRequest} was {@code null} .
+   */
+  public static StartTLSExtendedRequest copyOfStartTLSExtendedRequest(
+      final StartTLSExtendedRequest startTLSExtendedRequest)
+      throws NullPointerException
+  {
+    return new StartTLSExtendedRequestImpl(startTLSExtendedRequest);
+  }
+
+
+
+  /**
+   * Creates a new unbind request that is an exact copy of the provided
+   * request.
+   *
+   * @param unbindRequest
+   *          The unbind request to be copied.
+   * @return The new unbind request.
+   * @throws NullPointerException
+   *           If {@code unbindRequest} was {@code null} .
+   */
+  public static UnbindRequest copyOfUnbindRequest(
+      final UnbindRequest unbindRequest)
+      throws NullPointerException
+  {
+    return new UnbindRequestImpl(unbindRequest);
+  }
+
+
+
+  /**
+   * Creates a new Who Am I extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param whoAmIExtendedRequest
+   *          The who Am I extended request to be copied.
+   * @return The new Who Am I extended request.
+   * @throws NullPointerException
+   *           If {@code whoAmIExtendedRequest} was {@code null} .
+   */
+  public static WhoAmIExtendedRequest copyOfWhoAmIExtendedRequest(
+      final WhoAmIExtendedRequest whoAmIExtendedRequest)
+      throws NullPointerException
+  {
+    return new WhoAmIExtendedRequestImpl(whoAmIExtendedRequest);
+  }
+
+
+
   private Requests()
   {
     // Prevent instantiation.
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/SearchRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/SearchRequestImpl.java
index a56b610..7d13fc6 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/SearchRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/SearchRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -49,7 +49,8 @@
 
   private DN name;
 
-  private DereferenceAliasesPolicy dereferenceAliasesPolicy = DereferenceAliasesPolicy.NEVER;
+  private DereferenceAliasesPolicy dereferenceAliasesPolicy =
+      DereferenceAliasesPolicy.NEVER;
 
   private Filter filter;
 
@@ -75,8 +76,6 @@
    * @param filter
    *          The filter that defines the conditions that must be fulfilled in
    *          order for an entry to be returned.
-   * @param attributeDescriptions
-   *          The names of the attributes to be included with each entry.
    * @throws NullPointerException
    *           If the {@code name}, {@code scope}, or {@code filter} were
    *           {@code null}.
@@ -92,6 +91,31 @@
 
 
   /**
+   * Creates a new search request that is an exact copy of the provided
+   * request.
+   *
+   * @param searchRequest
+   *          The search request to be copied.
+   * @throws NullPointerException
+   *           If {@code searchRequest} was {@code null} .
+   */
+  SearchRequestImpl(final SearchRequest searchRequest)
+      throws NullPointerException
+  {
+    super(searchRequest);
+    this.attributes.addAll(searchRequest.getAttributes());
+    this.name = searchRequest.getName();
+    this.dereferenceAliasesPolicy = searchRequest.getDereferenceAliasesPolicy();
+    this.filter = searchRequest.getFilter();
+    this.scope = searchRequest.getScope();
+    this.sizeLimit = searchRequest.getSizeLimit();
+    this.timeLimit = searchRequest.getTimeLimit();
+    this.typesOnly = searchRequest.isTypesOnly();
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   public SearchRequest addAttribute(final String... attributeDescriptions)
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/SimpleBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/SimpleBindRequestImpl.java
index e717430..59c9655 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/SimpleBindRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/SimpleBindRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -73,6 +73,25 @@
 
 
 
+  /**
+   * Creates a new simple bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param simpleBindRequest
+   *          The simple bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code simpleBindRequest} was {@code null} .
+   */
+  SimpleBindRequestImpl(final SimpleBindRequest simpleBindRequest)
+      throws NullPointerException
+  {
+    super(simpleBindRequest);
+    this.name = simpleBindRequest.getName();
+    this.password = simpleBindRequest.getPassword();
+  }
+
+
+
   public BindClient createBindClient(final String serverName)
       throws ErrorResultException
   {
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequest.java
index 012e294..abe4270 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequest.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequest.java
@@ -117,7 +117,7 @@
 
 
   /**
-   * Set the protocol versions enabled for secure connections with the
+   * Adds the protocol versions enabled for secure connections with the
    * Directory Server.
    *
    * The protocols must be supported by the SSLContext specified in
@@ -125,16 +125,18 @@
    * this method, only the protocols listed in the protocols parameter are
    * enabled for use.
    *
-   * @param protocols Names of all the protocols to enable or {@code null} to
-   *                  use the default protocols.
+   * @param protocols Names of all the protocols to enable.
    * @return A reference to this LDAP connection options.
+   * @throws UnsupportedOperationException
+   *           If this start TLS extended request does not permit the enabled
+   *           protocols to be set.
    */
-  StartTLSExtendedRequest setEnabledProtocols(String[] protocols);
-
+  StartTLSExtendedRequest addEnabledProtocol(String... protocols)
+      throws UnsupportedOperationException;
 
 
   /**
-   * Set the cipher suites enabled for secure connections with the
+   * Adds the cipher suites enabled for secure connections with the
    * Directory Server.
    *
    * The suites must be supported by the SSLContext specified in
@@ -142,11 +144,14 @@
    * this method, only the suites listed in the protocols parameter are
    * enabled for use.
    *
-   * @param suites Names of all the suites to enable or {@code null} to
-   *                  use the default cipher suites.
+   * @param suites Names of all the suites to enable.
    * @return A reference to this LDAP connection options.
+   * @throws UnsupportedOperationException
+   *           If this start TLS extended request does not permit the enabled
+   *           cipher suites to be set.
    */
-  StartTLSExtendedRequest setEnabledCipherSuites(String[] suites);
+  StartTLSExtendedRequest addEnabledCipherSuite(String... suites)
+      throws UnsupportedOperationException;
 
 
 
@@ -154,10 +159,10 @@
    * Returns the names of the protocol versions which are currently enabled
    * for secure connections with the Directory Server.
    *
-   * @return an array of protocols or {@code null} if the default protocols
+   * @return an array of protocols or empty set if the default protocols
    * are to be used.
    */
-  String[] getEnabledProtocols();
+  List<String> getEnabledProtocols();
 
 
 
@@ -165,10 +170,10 @@
    * Returns the names of the protocol versions which are currently enabled
    * for secure connections with the Directory Server.
    *
-   * @return an array of protocols or {@code null} if the default protocols
+   * @return an array of protocols or empty set if the default protocols
    * are to be used.
    */
-  String[] getEnabledCipherSuites();
+  List<String> getEnabledCipherSuites();
 
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequestImpl.java
index 513c75e..2d0c2c3 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequestImpl.java
@@ -37,6 +37,7 @@
 
 import com.sun.opends.sdk.util.Validator;
 
+import java.util.*;
 
 
 /**
@@ -55,7 +56,8 @@
         throws DecodeException
     {
       // TODO: Check the OID and that the value is not present.
-      final StartTLSExtendedRequest newRequest = new StartTLSExtendedRequestImpl();
+      final StartTLSExtendedRequest newRequest =
+          new StartTLSExtendedRequestImpl();
       for (final Control control : request.getControls())
       {
         newRequest.addControl(control);
@@ -95,15 +97,16 @@
   /**
    * The list of cipher suite
    */
-  private String[] enabledCipherSuites = null;
+  private List<String> enabledCipherSuites = new LinkedList<String>();
 
   /**
    * the list of protocols
    */
-  private String[] enabledProtocols = null;
+  private List<String> enabledProtocols = new LinkedList<String>();
 
   // No need to expose this.
-  private static final ExtendedResultDecoder<ExtendedResult> RESULT_DECODER = new ResultDecoder();
+  private static final ExtendedResultDecoder<ExtendedResult> RESULT_DECODER =
+      new ResultDecoder();
 
 
 
@@ -115,6 +118,28 @@
 
 
 
+  /**
+   * Creates a new startTLS extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param startTLSExtendedRequest
+   *          The startTLS extended request to be copied.
+   * @throws NullPointerException
+   *           If {@code startTLSExtendedRequest} was {@code null} .
+   */
+  StartTLSExtendedRequestImpl(
+      final StartTLSExtendedRequest startTLSExtendedRequest)
+      throws NullPointerException
+  {
+    super(startTLSExtendedRequest);
+    this.sslContext = startTLSExtendedRequest.getSSLContext();
+    this.enabledCipherSuites.addAll(
+        startTLSExtendedRequest.getEnabledCipherSuites());
+    this.enabledProtocols.addAll(startTLSExtendedRequest.getEnabledProtocols());
+  }
+
+
+
   // Prevent instantiation.
   private StartTLSExtendedRequestImpl()
   {
@@ -158,9 +183,12 @@
   /**
    * {@inheritDoc}}
    */
-  public StartTLSExtendedRequest setEnabledProtocols(String[] protocols)
+  public StartTLSExtendedRequest addEnabledProtocol(String... protocols)
   {
-    this.enabledProtocols = protocols;
+    for (final String protocol : protocols)
+    {
+      this.enabledProtocols.add(Validator.ensureNotNull(protocol));
+    }
     return this;
   }
 
@@ -169,9 +197,12 @@
   /**
    * {@inheritDoc}}
    */
-  public StartTLSExtendedRequest setEnabledCipherSuites(String[] suites)
+  public StartTLSExtendedRequest addEnabledCipherSuite(String... suites)
   {
-    this.enabledCipherSuites = suites;
+    for (final String suite : suites)
+    {
+      this.enabledCipherSuites.add(Validator.ensureNotNull(suite));
+    }
     return this;
   }
 
@@ -180,7 +211,7 @@
   /**
    * {@inheritDoc}}
    */
-  public String[] getEnabledProtocols()
+  public List<String> getEnabledProtocols()
   {
     return this.enabledProtocols;
   }
@@ -190,7 +221,7 @@
   /**
    * {@inheritDoc}}
    */
-  public String[] getEnabledCipherSuites()
+  public List<String> getEnabledCipherSuites()
   {
     return this.enabledCipherSuites;
   }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnbindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnbindRequestImpl.java
index 87c8eef..3c91a43 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnbindRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnbindRequestImpl.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk.requests;
@@ -47,6 +47,23 @@
 
 
   /**
+   * Creates a new unbind request that is an exact copy of the provided
+   * request.
+   *
+   * @param unbindRequest
+   *          The unbind request to be copied.
+   * @throws NullPointerException
+   *           If {@code unbindRequest} was {@code null} .
+   */
+  UnbindRequestImpl(final UnbindRequest unbindRequest)
+      throws NullPointerException
+  {
+    super(unbindRequest);
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   @Override
diff --git a/opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAbandonRequestImpl.java
similarity index 62%
copy from opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java
copy to opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAbandonRequestImpl.java
index e85f12d..3d058e6 100644
--- a/opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAbandonRequestImpl.java
@@ -25,10 +25,31 @@
  *      Copyright 2010 Sun Microsystems, Inc.
  */
 
+package org.opends.sdk.requests;
+
 /**
- * Examples which use the OpenDS LDAP SDK.
+ * Unmodifiable abandon request implementation.
  */
-package org.opends.sdk.examples;
+final class UnmodifiableAbandonRequestImpl
+    extends AbstractUnmodifiableRequest<AbandonRequest>
+    implements AbandonRequest
+{
+  UnmodifiableAbandonRequestImpl(AbandonRequest request) {
+    super(request);
+  }
 
+  /**
+   * {@inheritDoc}
+   */
+  public int getRequestID() {
+    return impl.getRequestID();
+  }
 
-
+  /**
+   * {@inheritDoc}
+   */
+  public AbandonRequest setRequestID(int id)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAddRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAddRequestImpl.java
new file mode 100644
index 0000000..5aac9d7
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAddRequestImpl.java
@@ -0,0 +1,201 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import com.sun.opends.sdk.util.Function;
+import com.sun.opends.sdk.util.Iterables;
+import org.opends.sdk.*;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+import java.util.Collection;
+
+/**
+ * Unmodifiable add request implementation.
+ */
+final class UnmodifiableAddRequestImpl
+    extends AbstractUnmodifiableRequest<AddRequest>
+    implements AddRequest
+{
+  private static final Function<Attribute, Attribute, Void>
+      UNMODIFIABLE_ATTRIBUTE_FUNCTION =
+      new Function<Attribute, Attribute, Void>()
+  {
+
+    public Attribute apply(final Attribute value, final Void p)
+    {
+      return Attributes.unmodifiableAttribute(value);
+    }
+
+  };
+
+  UnmodifiableAddRequestImpl(AddRequest impl) {
+    super(impl);
+  }
+
+  public <R, P> R accept(ChangeRecordVisitor<R, P> v, P p) {
+    return v.visitChangeRecord(p, this);
+  }
+
+  public boolean addAttribute(Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public boolean addAttribute(Attribute attribute,
+                             Collection<ByteString> duplicateValues)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public AddRequest addAttribute(String attributeDescription,
+                                 Object... values)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public AddRequest clearAttributes()
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  public boolean containsAttribute(Attribute attribute,
+                               Collection<ByteString> missingValues)
+      throws NullPointerException {
+    return impl.containsAttribute(attribute, missingValues);
+  }
+
+  public boolean containsAttribute(String attributeDescription,
+                                   Object... values)
+      throws LocalizedIllegalArgumentException,
+      NullPointerException {
+    return impl.containsAttribute(attributeDescription, values);
+  }
+
+  public Iterable<Attribute> getAllAttributes() {
+    return Iterables.unmodifiable(Iterables.transform(impl
+        .getAllAttributes(), UNMODIFIABLE_ATTRIBUTE_FUNCTION));
+  }
+
+  public Iterable<Attribute> getAllAttributes(
+      AttributeDescription attributeDescription)
+      throws NullPointerException {
+    return Iterables.unmodifiable(Iterables.transform(impl
+        .getAllAttributes(attributeDescription),
+        UNMODIFIABLE_ATTRIBUTE_FUNCTION));
+  }
+
+  public Iterable<Attribute> getAllAttributes(
+      String attributeDescription)
+      throws LocalizedIllegalArgumentException,
+      NullPointerException {
+    return Iterables.unmodifiable(Iterables.transform(impl
+        .getAllAttributes(attributeDescription),
+        UNMODIFIABLE_ATTRIBUTE_FUNCTION));
+  }
+
+  public Attribute getAttribute(
+      AttributeDescription attributeDescription)
+      throws NullPointerException {
+    final Attribute attribute =
+        impl.getAttribute(attributeDescription);
+    if (attribute != null)
+    {
+      return Attributes.unmodifiableAttribute(attribute);
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+  public Attribute getAttribute(String attributeDescription)
+      throws LocalizedIllegalArgumentException,
+      NullPointerException {
+    final Attribute attribute =
+        impl.getAttribute(attributeDescription);
+    if (attribute != null)
+    {
+      return Attributes.unmodifiableAttribute(attribute);
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+  public int getAttributeCount() {
+    return impl.getAttributeCount();
+  }
+
+  public DN getName() {
+    return impl.getName();
+  }
+
+  public boolean removeAttribute(Attribute attribute,
+                               Collection<ByteString> missingValues)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public boolean removeAttribute(
+      AttributeDescription attributeDescription)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public AddRequest removeAttribute(String attributeDescription,
+                                    Object... values)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public boolean replaceAttribute(Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public AddRequest replaceAttribute(String attributeDescription,
+                                     Object... values)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public AddRequest setName(DN dn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public AddRequest setName(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAnonymousSASLBindRequestImpl.java
similarity index 60%
copy from opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java
copy to opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAnonymousSASLBindRequestImpl.java
index e85f12d..38701cb 100644
--- a/opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAnonymousSASLBindRequestImpl.java
@@ -25,10 +25,27 @@
  *      Copyright 2010 Sun Microsystems, Inc.
  */
 
+package org.opends.sdk.requests;
+
 /**
- * Examples which use the OpenDS LDAP SDK.
+ * Unmodifiable anonymous SASL bind request implementation.
  */
-package org.opends.sdk.examples;
+final class UnmodifiableAnonymousSASLBindRequestImpl extends
+    AbstractUnmodifiableSASLBindRequest<AnonymousSASLBindRequest> implements
+    AnonymousSASLBindRequest
+{
+  UnmodifiableAnonymousSASLBindRequestImpl(AnonymousSASLBindRequest impl) {
+    super(impl);
+  }
 
+  @Override
+  public String getTraceString() {
+    return impl.getTraceString();
+  }
 
-
+  @Override
+  public AnonymousSASLBindRequest setTraceString(String traceString)
+      throws NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableCRAMMD5SASLBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableCRAMMD5SASLBindRequestImpl.java
new file mode 100644
index 0000000..381c5d0
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableCRAMMD5SASLBindRequestImpl.java
@@ -0,0 +1,71 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+/**
+ * Unmodifiable CRAM-MD5 SASL bind request implementation.
+ */
+public class UnmodifiableCRAMMD5SASLBindRequestImpl extends
+    AbstractUnmodifiableSASLBindRequest<CRAMMD5SASLBindRequest> implements
+    CRAMMD5SASLBindRequest
+{
+  UnmodifiableCRAMMD5SASLBindRequestImpl(CRAMMD5SASLBindRequest impl) {
+    super(impl);
+  }
+
+  @Override
+  public String getAuthenticationID() {
+    return impl.getAuthenticationID();
+  }
+
+  @Override
+  public ByteString getPassword() {
+    return impl.getPassword();
+  }
+
+  @Override
+  public CRAMMD5SASLBindRequest setAuthenticationID(String authenticationID)
+      throws LocalizedIllegalArgumentException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public CRAMMD5SASLBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public CRAMMD5SASLBindRequest setPassword(String password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableCancelExtendedRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableCancelExtendedRequestImpl.java
new file mode 100644
index 0000000..48770d7
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableCancelExtendedRequestImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.responses.ExtendedResult;
+
+/**
+ * Unmodifiable cancel extended request implementation.
+ */
+final class UnmodifiableCancelExtendedRequestImpl
+    extends AbstractUnmodifiableExtendedRequest
+    <CancelExtendedRequest, ExtendedResult>
+    implements CancelExtendedRequest
+{
+  UnmodifiableCancelExtendedRequestImpl(
+      CancelExtendedRequest impl) {
+    super(impl);
+  }
+
+  public int getRequestID() {
+    return impl.getRequestID();
+  }
+
+  public CancelExtendedRequest setRequestID(int id)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableCompareRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableCompareRequestImpl.java
new file mode 100644
index 0000000..7fad857
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableCompareRequestImpl.java
@@ -0,0 +1,95 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.AttributeDescription;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DN;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+/**
+ * Unmodifiable compare request implementation.
+ */
+final class UnmodifiableCompareRequestImpl
+    extends AbstractUnmodifiableRequest<CompareRequest>
+    implements CompareRequest
+{
+  UnmodifiableCompareRequestImpl(CompareRequest impl) {
+    super(impl);
+  }
+
+  public ByteString getAssertionValue() {
+    return impl.getAssertionValue();
+  }
+
+  public String getAssertionValueAsString() {
+    return impl.getAssertionValueAsString();
+  }
+
+  public AttributeDescription getAttributeDescription() {
+    return impl.getAttributeDescription();
+  }
+
+  public DN getName() {
+    return impl.getName();
+  }
+
+  public CompareRequest setAssertionValue(ByteString value)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public CompareRequest setAssertionValue(Object value)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public CompareRequest setAttributeDescription(
+      AttributeDescription attributeDescription)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public CompareRequest setAttributeDescription(
+      String attributeDescription)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public CompareRequest setName(DN dn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public CompareRequest setName(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableDeleteRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableDeleteRequestImpl.java
new file mode 100644
index 0000000..c91efb4
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableDeleteRequestImpl.java
@@ -0,0 +1,63 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.DN;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+/**
+ * Unmodifiable delete request implementation.
+ */
+final class UnmodifiableDeleteRequestImpl
+    extends AbstractUnmodifiableRequest<DeleteRequest>
+    implements DeleteRequest
+{
+  UnmodifiableDeleteRequestImpl(DeleteRequest impl) {
+    super(impl);
+  }
+
+  public <R, P> R accept(ChangeRecordVisitor<R, P> v, P p) {
+    return v.visitChangeRecord(p, this);
+  }
+
+  public DN getName() {
+    return impl.getName();
+  }
+
+  public DeleteRequest setName(DN dn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public DeleteRequest setName(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableDigestMD5SASLBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableDigestMD5SASLBindRequestImpl.java
new file mode 100644
index 0000000..0a0ce32
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableDigestMD5SASLBindRequestImpl.java
@@ -0,0 +1,165 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Unmodifiable digest-MD5 SASL bind request implementation.
+ */
+final class UnmodifiableDigestMD5SASLBindRequestImpl extends
+    AbstractUnmodifiableSASLBindRequest<DigestMD5SASLBindRequest> implements
+    DigestMD5SASLBindRequest
+{
+  UnmodifiableDigestMD5SASLBindRequestImpl(DigestMD5SASLBindRequest impl) {
+    super(impl);
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest addAdditionalAuthParam(String name,
+                                                         String value)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest addQOP(String... qopValues)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public Map<String, String> getAdditionalAuthParams() {
+    return Collections.unmodifiableMap(impl.getAdditionalAuthParams());
+  }
+
+  @Override
+  public String getAuthenticationID() {
+    return impl.getAuthenticationID();
+  }
+
+  @Override
+  public String getAuthorizationID() {
+    return impl.getAuthorizationID();
+  }
+
+  @Override
+  public String getCipher() {
+    return impl.getCipher();
+  }
+
+  @Override
+  public int getMaxReceiveBufferSize() {
+    return impl.getMaxReceiveBufferSize();
+  }
+
+  @Override
+  public int getMaxSendBufferSize() {
+    return impl.getMaxSendBufferSize();
+  }
+
+  @Override
+  public ByteString getPassword() {
+    return impl.getPassword();
+  }
+
+  @Override
+  public List<String> getQOPs() {
+    return Collections.unmodifiableList(impl.getQOPs());
+  }
+
+  @Override
+  public String getRealm() {
+    return impl.getRealm();
+  }
+
+  @Override
+  public boolean isServerAuth() {
+    return impl.isServerAuth();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setAuthenticationID(String authenticationID)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setAuthorizationID(String authorizationID)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setCipher(String cipher)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setMaxReceiveBufferSize(int size)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setMaxSendBufferSize(int size)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setPassword(String password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setRealm(String realm)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setServerAuth(boolean serverAuth)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableExternalSASLBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableExternalSASLBindRequestImpl.java
new file mode 100644
index 0000000..cc596e2
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableExternalSASLBindRequestImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+/**
+ * Unmodifiable external SASL bind request implementation.
+ */
+final class UnmodifiableExternalSASLBindRequestImpl extends
+    AbstractUnmodifiableSASLBindRequest<ExternalSASLBindRequest> implements
+    ExternalSASLBindRequest
+{
+  UnmodifiableExternalSASLBindRequestImpl(ExternalSASLBindRequest impl) {
+    super(impl);
+  }
+
+  @Override
+  public String getAuthorizationID() {
+    return  impl.getAuthorizationID();
+  }
+
+  @Override
+  public ExternalSASLBindRequest setAuthorizationID(String authorizationID)
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableGSSAPISASLBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableGSSAPISASLBindRequestImpl.java
new file mode 100644
index 0000000..3f563f1
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableGSSAPISASLBindRequestImpl.java
@@ -0,0 +1,175 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+import javax.security.auth.Subject;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Unmodifiable GSSAPI SASL bind request implementation.
+ */
+final class UnmodifiableGSSAPISASLBindRequestImpl extends
+    AbstractUnmodifiableSASLBindRequest<GSSAPISASLBindRequest> implements
+    GSSAPISASLBindRequest
+{
+  UnmodifiableGSSAPISASLBindRequestImpl(GSSAPISASLBindRequest impl) {
+    super(impl);
+  }
+
+  @Override
+  public GSSAPISASLBindRequest addAdditionalAuthParam(String name, String value)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public Map<String, String> getAdditionalAuthParams() {
+    return Collections.unmodifiableMap(impl.getAdditionalAuthParams());
+  }
+
+  @Override
+  public GSSAPISASLBindRequest addQOP(String... qopValues)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public String getAuthenticationID() {
+    return impl.getAuthenticationID();
+  }
+
+  @Override
+  public String getAuthorizationID() {
+    return impl.getAuthorizationID();
+  }
+
+  @Override
+  public String getKDCAddress() {
+    return impl.getKDCAddress();
+  }
+
+  @Override
+  public int getMaxReceiveBufferSize() {
+    return impl.getMaxReceiveBufferSize();
+  }
+
+  @Override
+  public int getMaxSendBufferSize() {
+    return impl.getMaxSendBufferSize();
+  }
+
+  @Override
+  public ByteString getPassword() {
+    return impl.getPassword();
+  }
+
+  @Override
+  public List<String> getQOPs() {
+    return Collections.unmodifiableList(impl.getQOPs());
+  }
+
+  @Override
+  public String getRealm() {
+    return impl.getRealm();
+  }
+
+  @Override
+  public Subject getSubject() {
+    return impl.getSubject();
+  }
+
+  @Override
+  public boolean isServerAuth() {
+    return impl.isServerAuth();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setAuthenticationID(String authenticationID)
+      throws LocalizedIllegalArgumentException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setAuthorizationID(String authorizationID)
+      throws LocalizedIllegalArgumentException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setKDCAddress(String address)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setMaxReceiveBufferSize(int size)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setMaxSendBufferSize(int size)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setPassword(String password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setRealm(String realm)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setServerAuth(boolean serverAuth)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setSubject(Subject subject)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableGenericBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableGenericBindRequestImpl.java
new file mode 100644
index 0000000..2308a85
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableGenericBindRequestImpl.java
@@ -0,0 +1,61 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+
+/**
+ * Unmodifiable generic bind request implementation.
+ */
+final class UnmodifiableGenericBindRequestImpl
+    extends AbstractUnmodifiableBindRequest<GenericBindRequest>
+    implements GenericBindRequest
+{
+  UnmodifiableGenericBindRequestImpl(GenericBindRequest impl) {
+    super(impl);
+  }
+
+  public ByteString getAuthenticationValue() {
+    return impl.getAuthenticationValue();
+  }
+
+  public GenericBindRequest setAuthenticationType(byte type)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  public GenericBindRequest setAuthenticationValue(ByteString bytes)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public GenericBindRequest setName(String name)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableGenericExtendedRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableGenericExtendedRequestImpl.java
new file mode 100644
index 0000000..b17d854
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableGenericExtendedRequestImpl.java
@@ -0,0 +1,54 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.responses.GenericExtendedResult;
+
+/**
+ * Unmodifiable generic extended request implementation.
+ */
+final class UnmodifiableGenericExtendedRequestImpl
+    extends AbstractUnmodifiableExtendedRequest
+    <GenericExtendedRequest, GenericExtendedResult>
+    implements GenericExtendedRequest
+{
+  UnmodifiableGenericExtendedRequestImpl(GenericExtendedRequest impl) {
+    super(impl);
+  }
+
+  public GenericExtendedRequest setOID(String oid)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public GenericExtendedRequest setValue(ByteString bytes)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableModifyDNRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableModifyDNRequestImpl.java
new file mode 100644
index 0000000..7231be6
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableModifyDNRequestImpl.java
@@ -0,0 +1,103 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.DN;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+import org.opends.sdk.RDN;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+/**
+ * Unmodifiable modify DN request implementation.
+ */
+final class UnmodifiableModifyDNRequestImpl
+    extends AbstractUnmodifiableRequest<ModifyDNRequest>
+    implements ModifyDNRequest
+{
+  UnmodifiableModifyDNRequestImpl(ModifyDNRequest impl) {
+    super(impl);
+  }
+
+  public <R, P> R accept(ChangeRecordVisitor<R, P> v, P p) {
+    return v.visitChangeRecord(p, this);
+  }
+
+  public DN getName() {
+    return impl.getName();
+  }
+
+  public RDN getNewRDN() {
+    return impl.getNewRDN();
+  }
+
+  public DN getNewSuperior() {
+    return impl.getNewSuperior();
+  }
+
+  public boolean isDeleteOldRDN() {
+    return impl.isDeleteOldRDN();
+  }
+
+  public ModifyDNRequest setDeleteOldRDN(boolean deleteOldRDN)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyDNRequest setName(DN dn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyDNRequest setName(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyDNRequest setNewRDN(RDN rdn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyDNRequest setNewRDN(String rdn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyDNRequest setNewSuperior(DN dn)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyDNRequest setNewSuperior(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableModifyRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableModifyRequestImpl.java
new file mode 100644
index 0000000..5b143d6
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableModifyRequestImpl.java
@@ -0,0 +1,85 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.DN;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+import org.opends.sdk.Modification;
+import org.opends.sdk.ModificationType;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Unmodifiable modify request implementation.
+ */
+final class UnmodifiableModifyRequestImpl
+    extends AbstractUnmodifiableRequest<ModifyRequest>
+    implements ModifyRequest
+{
+  UnmodifiableModifyRequestImpl(ModifyRequest impl) {
+    super(impl);
+  }
+
+  public <R, P> R accept(ChangeRecordVisitor<R, P> v, P p) {
+    return v.visitChangeRecord(p, this);
+  }
+
+  public ModifyRequest addModification(Modification modification)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyRequest addModification(ModificationType type,
+                                       String attributeDescription,
+                                       Object... values)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public List<Modification> getModifications() {
+    return Collections.unmodifiableList(impl.getModifications());
+  }
+
+  public DN getName() {
+    return impl.getName();
+  }
+
+  public ModifyRequest setName(DN dn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyRequest setName(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiablePasswordModifyExtendedRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiablePasswordModifyExtendedRequestImpl.java
new file mode 100644
index 0000000..1679ee5
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiablePasswordModifyExtendedRequestImpl.java
@@ -0,0 +1,96 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.responses.PasswordModifyExtendedResult;
+
+/**
+ * Unmodifiable password modify extended request implementation.
+ */
+final class UnmodifiablePasswordModifyExtendedRequestImpl
+    extends AbstractUnmodifiableExtendedRequest
+    <PasswordModifyExtendedRequest, PasswordModifyExtendedResult>
+    implements PasswordModifyExtendedRequest
+{
+  UnmodifiablePasswordModifyExtendedRequestImpl(
+      PasswordModifyExtendedRequest impl) {
+    super(impl);
+  }
+
+  public ByteString getNewPassword() {
+    return impl.getNewPassword();
+  }
+
+  public String getNewPasswordAsString() {
+    return impl.getNewPasswordAsString();
+  }
+
+  public ByteString getOldPassword() {
+    return impl.getOldPassword();
+  }
+
+  public String getOldPasswordAsString() {
+    return impl.getOldPasswordAsString();
+  }
+
+  public ByteString getUserIdentity() {
+    return impl.getUserIdentity();
+  }
+
+  public String getUserIdentityAsString() {
+    return impl.getUserIdentityAsString();
+  }
+
+  public PasswordModifyExtendedRequest setNewPassword(ByteString newPassword)
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  public PasswordModifyExtendedRequest setNewPassword(String newPassword) {
+    throw new UnsupportedOperationException();
+  }
+
+  public PasswordModifyExtendedRequest setOldPassword(ByteString oldPassword)
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  public PasswordModifyExtendedRequest setOldPassword(String oldPassword) {
+    throw new UnsupportedOperationException();
+  }
+
+  public PasswordModifyExtendedRequest setUserIdentity(
+      ByteString userIdentity) {
+    throw new UnsupportedOperationException();
+  }
+
+  public PasswordModifyExtendedRequest setUserIdentity(String userIdentity) {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiablePlainSASLBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiablePlainSASLBindRequestImpl.java
new file mode 100644
index 0000000..a893b36d
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiablePlainSASLBindRequestImpl.java
@@ -0,0 +1,83 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+/**
+ * Unmodifiable plain SASL bind request implementation.
+ */
+final class UnmodifiablePlainSASLBindRequestImpl extends
+    AbstractUnmodifiableSASLBindRequest<PlainSASLBindRequest> implements
+    PlainSASLBindRequest
+{
+  UnmodifiablePlainSASLBindRequestImpl(PlainSASLBindRequest impl) {
+    super(impl);
+  }
+
+  @Override
+  public String getAuthenticationID() {
+    return impl.getAuthenticationID();
+  }
+
+  @Override
+  public String getAuthorizationID() {
+    return impl.getAuthorizationID();
+  }
+
+  @Override
+  public ByteString getPassword() {
+    return impl.getPassword();
+  }
+
+  @Override
+  public PlainSASLBindRequest setAuthenticationID(String authenticationID)
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException,
+      NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public PlainSASLBindRequest setAuthorizationID(String authorizationID)
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public PlainSASLBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public PlainSASLBindRequest setPassword(String password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableSearchRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableSearchRequestImpl.java
new file mode 100644
index 0000000..29c740f
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableSearchRequestImpl.java
@@ -0,0 +1,132 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.*;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Unmodifiable search request implementation.
+ */
+final class UnmodifiableSearchRequestImpl
+    extends AbstractUnmodifiableRequest<SearchRequest>
+    implements SearchRequest
+{
+  UnmodifiableSearchRequestImpl(SearchRequest impl) {
+    super(impl);
+  }
+
+  public SearchRequest addAttribute(String... attributeDescriptions)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public List<String> getAttributes() {
+    return Collections.unmodifiableList(impl.getAttributes());
+  }
+
+  public DereferenceAliasesPolicy getDereferenceAliasesPolicy() {
+    return impl.getDereferenceAliasesPolicy();
+  }
+
+  public Filter getFilter() {
+    return impl.getFilter();
+  }
+
+  public DN getName() {
+    return impl.getName();
+  }
+
+  public SearchScope getScope() {
+    return impl.getScope();
+  }
+
+  public int getSizeLimit() {
+    return impl.getSizeLimit();
+  }
+
+  public int getTimeLimit() {
+    return impl.getTimeLimit();
+  }
+
+  public boolean isTypesOnly() {
+    return impl.isTypesOnly();
+  }
+
+  public SearchRequest setDereferenceAliasesPolicy(
+      DereferenceAliasesPolicy policy)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setFilter(Filter filter)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setFilter(String filter)
+      throws UnsupportedOperationException,
+      LocalizedIllegalArgumentException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setName(DN dn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setName(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setScope(SearchScope scope)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setSizeLimit(int limit)
+      throws UnsupportedOperationException,
+      LocalizedIllegalArgumentException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setTimeLimit(int limit)
+      throws UnsupportedOperationException,
+      LocalizedIllegalArgumentException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setTypesOnly(boolean typesOnly)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableSimpleBindRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableSimpleBindRequestImpl.java
new file mode 100644
index 0000000..c279ed2
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableSimpleBindRequestImpl.java
@@ -0,0 +1,65 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+
+/**
+ * Unmodifiable simple bind request implementation.
+ */
+final class UnmodifiableSimpleBindRequestImpl
+    extends AbstractUnmodifiableBindRequest<SimpleBindRequest>
+    implements SimpleBindRequest
+{
+  UnmodifiableSimpleBindRequestImpl(SimpleBindRequest impl) {
+    super(impl);
+  }
+
+  public ByteString getPassword() {
+    return impl.getPassword();
+  }
+
+  public String getPasswordAsString() {
+    return impl.getPasswordAsString();
+  }
+
+  public SimpleBindRequest setName(String name)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SimpleBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SimpleBindRequest setPassword(String password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableStartTLSExtendedRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableStartTLSExtendedRequestImpl.java
new file mode 100644
index 0000000..8f14d81
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableStartTLSExtendedRequestImpl.java
@@ -0,0 +1,71 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.responses.ExtendedResult;
+
+import javax.net.ssl.SSLContext;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Unmodifiable start TLS extended request implementation.
+ */
+final class UnmodifiableStartTLSExtendedRequestImpl
+    extends AbstractUnmodifiableExtendedRequest
+    <StartTLSExtendedRequest, ExtendedResult>
+    implements StartTLSExtendedRequest
+{
+  UnmodifiableStartTLSExtendedRequestImpl(StartTLSExtendedRequest impl) {
+    super(impl);
+  }
+
+  public SSLContext getSSLContext() {
+    return impl.getSSLContext();
+  }
+
+  public StartTLSExtendedRequest addEnabledProtocol(String... protocols) {
+    throw new UnsupportedOperationException();
+  }
+
+  public StartTLSExtendedRequest addEnabledCipherSuite(String... suites) {
+    throw new UnsupportedOperationException();
+  }
+
+  public List<String> getEnabledProtocols() {
+    return Collections.unmodifiableList(impl.getEnabledProtocols());
+  }
+
+  public List<String> getEnabledCipherSuites() {
+    return Collections.unmodifiableList(impl.getEnabledCipherSuites());
+  }
+
+  public StartTLSExtendedRequest setSSLContext(SSLContext sslContext) {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableUnbindRequestImpl.java
similarity index 76%
rename from opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java
rename to opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableUnbindRequestImpl.java
index e85f12d..823ce66 100644
--- a/opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableUnbindRequestImpl.java
@@ -25,10 +25,16 @@
  *      Copyright 2010 Sun Microsystems, Inc.
  */
 
+package org.opends.sdk.requests;
+
 /**
- * Examples which use the OpenDS LDAP SDK.
+ * Unmodifiable unbind request implementation.
  */
-package org.opends.sdk.examples;
-
-
-
+final class UnmodifiableUnbindRequestImpl
+    extends AbstractUnmodifiableRequest<UnbindRequest>
+    implements UnbindRequest
+{
+  UnmodifiableUnbindRequestImpl(UnbindRequest impl) {
+    super(impl);
+  }
+}
diff --git a/opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableWhoAmIExtendedRequestImpl.java
similarity index 68%
copy from opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java
copy to opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableWhoAmIExtendedRequestImpl.java
index e85f12d..1d94ee2 100644
--- a/opendj-sdk/sdk/examples/org/opends/sdk/examples/package-info.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableWhoAmIExtendedRequestImpl.java
@@ -25,10 +25,19 @@
  *      Copyright 2010 Sun Microsystems, Inc.
  */
 
+package org.opends.sdk.requests;
+
+import org.opends.sdk.responses.WhoAmIExtendedResult;
+
 /**
- * Examples which use the OpenDS LDAP SDK.
+ * Unmodifiable Who Am I extended request implementation.
  */
-package org.opends.sdk.examples;
-
-
-
+final class UnmodifiableWhoAmIExtendedRequestImpl
+    extends AbstractUnmodifiableExtendedRequest
+    <WhoAmIExtendedRequest, WhoAmIExtendedResult>
+    implements WhoAmIExtendedRequest
+{
+  UnmodifiableWhoAmIExtendedRequestImpl(WhoAmIExtendedRequest impl) {
+    super(impl);
+  }
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/WhoAmIExtendedRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/WhoAmIExtendedRequestImpl.java
index d1bb727..bec193f 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/WhoAmIExtendedRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/WhoAmIExtendedRequestImpl.java
@@ -131,6 +131,24 @@
 
 
   /**
+   * Creates a new Who Am I extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param whoAmIExtendedRequest
+   *          The who Am I extended request to be copied.
+   * @throws NullPointerException
+   *           If {@code whoAmIExtendedRequest} was {@code null} .
+   */
+  WhoAmIExtendedRequestImpl(
+      final WhoAmIExtendedRequest whoAmIExtendedRequest)
+      throws NullPointerException
+  {
+    super(whoAmIExtendedRequest);
+  }
+
+
+
+  /**
    * {@inheritDoc}
    */
   @Override
diff --git a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/ConnectionFactoryTestCase.java b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/ConnectionFactoryTestCase.java
index 3984c96..e6195c8 100644
--- a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/ConnectionFactoryTestCase.java
+++ b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/ConnectionFactoryTestCase.java
@@ -40,7 +40,6 @@
 import org.opends.sdk.requests.DigestMD5SASLBindRequest;
 import org.opends.sdk.requests.Requests;
 import org.opends.sdk.requests.SearchRequest;
-import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 import org.testng.annotations.DataProvider;
@@ -142,7 +141,7 @@
     LDAPOptions options = new LDAPOptions()
         .setSSLContext(sslContext)
         .setUseStartTLS(true)
-        .setEnabledCipherSuites(
+        .addEnabledCipherSuite(
             new String[] { "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
                 "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
                 "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",

--
Gitblit v1.10.0