From a3d5c5661dd11285ebafd742c1da6d10b91639f7 Mon Sep 17 00:00:00 2001
From: Ludovic Poitou <ludovic.poitou@forgerock.com>
Date: Sun, 24 Oct 2010 20:47:53 +0000
Subject: [PATCH] Sync commits from OpenDS by matthew_swift

---
 opendj-sdk/sdk/src/org/opends/sdk/requests/AddRequestImpl.java                          |    2 
 opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyRequestImpl.java                       |   10 
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableModifyRequestImpl.java           |   32 +
 opendj-sdk/sdk/src/org/opends/sdk/Entries.java                                          |    6 
 opendj-sdk/sdk/src/com/sun/opends/sdk/util/Iterators.java                               |   30 
 opendj-sdk/sdk/src/org/opends/sdk/Attributes.java                                       |    4 
 opendj-sdk/sdk/src/org/opends/sdk/responses/Responses.java                              |  212 ++++---
 opendj-sdk/sdk/src/org/opends/sdk/responses/SearchResultEntryImpl.java                  |    2 
 opendj-sdk/sdk/src/org/opends/sdk/TreeMapEntry.java                                     |   35 +
 opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractRequestImpl.java                     |    8 
 opendj-sdk/sdk/src/org/opends/sdk/AbstractEntry.java                                    |    2 
 opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractUnmodifiableResponseImpl.java       |   69 ++
 opendj-sdk/sdk/src/org/opends/sdk/Modification.java                                     |    4 
 opendj-sdk/sdk/src/org/opends/sdk/responses/PasswordModifyExtendedResultImpl.java       |    2 
 opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableBindRequest.java         |    0 
 opendj-sdk/sdk/src/org/opends/sdk/responses/UnmodifiableSearchResultEntryImpl.java      |    6 
 opendj-sdk/sdk/src/org/opends/sdk/requests/Requests.java                                |  536 +++++++++++---------
 opendj-sdk/sdk/src/com/sun/opends/sdk/util/Iterables.java                               |   48 
 opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequest.java             |   68 ++
 opendj-sdk/sdk/src/org/opends/sdk/LinkedHashMapEntry.java                               |   44 +
 opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAddRequestImpl.java              |    6 
 opendj-sdk/sdk/src/org/opends/sdk/AttributeDescription.java                             |    6 
 opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractExtendedResult.java                 |    6 
 opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractIntermediateResponse.java           |    6 
 opendj-sdk/sdk/src/com/sun/opends/sdk/extensions/GetConnectionIDExtendedResult.java     |    4 
 opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractResponseImpl.java                   |    7 
 opendj-sdk/sdk/src/org/opends/sdk/responses/GenericIntermediateResponseImpl.java        |    2 
 opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java                                          |    2 
 opendj-sdk/sdk/src/com/sun/opends/sdk/util/Functions.java                               |   30 +
 opendj-sdk/sdk/src/com/sun/opends/sdk/util/Collections2.java                            |  319 +++++++++++
 opendj-sdk/sdk/src/org/opends/sdk/responses/WhoAmIExtendedResultImpl.java               |    2 
 opendj-sdk/sdk/src/com/sun/opends/sdk/extensions/PasswordPolicyStateExtendedResult.java |    4 
 opendj-sdk/sdk/src/org/opends/sdk/responses/GenericExtendedResultImpl.java              |    2 
 33 files changed, 1,058 insertions(+), 458 deletions(-)

diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/extensions/GetConnectionIDExtendedResult.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/extensions/GetConnectionIDExtendedResult.java
index 1992c59..7ed2385 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/extensions/GetConnectionIDExtendedResult.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/extensions/GetConnectionIDExtendedResult.java
@@ -36,7 +36,7 @@
 import org.opends.sdk.ResultCode;
 import org.opends.sdk.asn1.ASN1;
 import org.opends.sdk.asn1.ASN1Writer;
-import org.opends.sdk.responses.AbstractExtendedResultImpl;
+import org.opends.sdk.responses.AbstractExtendedResult;
 
 import com.sun.opends.sdk.util.Validator;
 
@@ -47,7 +47,7 @@
  * @see GetConnectionIDExtendedRequest
  */
 public final class GetConnectionIDExtendedResult extends
-    AbstractExtendedResultImpl<GetConnectionIDExtendedResult>
+    AbstractExtendedResult<GetConnectionIDExtendedResult>
 {
   /**
    * Creates a new get connection ID extended result.
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/extensions/PasswordPolicyStateExtendedResult.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/extensions/PasswordPolicyStateExtendedResult.java
index 9e8df68..2bb5f5f 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/extensions/PasswordPolicyStateExtendedResult.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/extensions/PasswordPolicyStateExtendedResult.java
@@ -35,7 +35,7 @@
 import org.opends.sdk.ByteString;
 import org.opends.sdk.DN;
 import org.opends.sdk.ResultCode;
-import org.opends.sdk.responses.AbstractExtendedResultImpl;
+import org.opends.sdk.responses.AbstractExtendedResult;
 
 
 
@@ -43,7 +43,7 @@
  * The password policy state extended result.
  */
 public final class PasswordPolicyStateExtendedResult extends
-    AbstractExtendedResultImpl<PasswordPolicyStateExtendedResult> implements
+    AbstractExtendedResult<PasswordPolicyStateExtendedResult> implements
     PasswordPolicyStateOperationContainer
 {
   private final String targetUser;
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Collections2.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Collections2.java
index 27a7724..fd54426 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Collections2.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Collections2.java
@@ -22,16 +22,14 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
  */
 
 package com.sun.opends.sdk.util;
 
 
 
-import java.util.AbstractCollection;
-import java.util.Collection;
-import java.util.Iterator;
+import java.util.*;
 
 
 
@@ -40,21 +38,21 @@
  */
 public final class Collections2
 {
-  private static final class TransformedCollection<M, N, P> extends
-      AbstractCollection<N> implements Collection<N>
+  private static class TransformedCollection<M, N, P, C extends Collection<M>>
+      extends AbstractCollection<N> implements Collection<N>
   {
 
-    private final Collection<M> collection;
+    protected final C collection;
 
-    private final Function<? super M, ? extends N, P> funcMtoN;
+    protected final Function<? super M, ? extends N, P> funcMtoN;
 
-    private final Function<? super N, ? extends M, P> funcNtoM;
+    protected final Function<? super N, ? extends M, P> funcNtoM;
 
-    private final P p;
+    protected final P p;
 
 
 
-    private TransformedCollection(final Collection<M> collection,
+    protected TransformedCollection(final C collection,
         final Function<? super M, ? extends N, P> funcMtoN,
         final Function<? super N, ? extends M, P> funcNtoM, final P p)
     {
@@ -118,7 +116,7 @@
     @Override
     public Iterator<N> iterator()
     {
-      return Iterators.transform(collection.iterator(), funcMtoN, p);
+      return Iterators.transformedIterator(collection.iterator(), funcMtoN, p);
     }
 
 
@@ -149,6 +147,217 @@
 
 
 
+  private static final class TransformedList<M, N, P> extends
+      TransformedCollection<M, N, P, List<M>> implements List<N>
+  {
+
+    private TransformedList(final List<M> list,
+        final Function<? super M, ? extends N, P> funcMtoN,
+        final Function<? super N, ? extends M, P> funcNtoM, final P p)
+    {
+      super(list, funcMtoN, funcNtoM, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void add(final int index, final N element)
+    {
+      collection.add(index, funcNtoM.apply(element, p));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean addAll(final int index, final Collection<? extends N> c)
+    {
+      // We cannot transform c here due to type-safety.
+      boolean result = false;
+      for (final N e : c)
+      {
+        result |= add(e);
+      }
+      return result;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public N get(final int index)
+    {
+      return funcMtoN.apply(collection.get(index), p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public int indexOf(final Object o)
+    {
+      final N tmp = (N) o;
+      return collection.indexOf(funcNtoM.apply(tmp, p));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public int lastIndexOf(final Object o)
+    {
+      final N tmp = (N) o;
+      return collection.lastIndexOf(funcNtoM.apply(tmp, p));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ListIterator<N> listIterator()
+    {
+      return listIterator(0);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ListIterator<N> listIterator(final int index)
+    {
+      final ListIterator<M> iterator = collection.listIterator(index);
+      return new ListIterator<N>()
+      {
+
+        @Override
+        public void add(final N e)
+        {
+          iterator.add(funcNtoM.apply(e, p));
+        }
+
+
+
+        @Override
+        public boolean hasNext()
+        {
+          return iterator.hasNext();
+        }
+
+
+
+        @Override
+        public boolean hasPrevious()
+        {
+          return iterator.hasPrevious();
+        }
+
+
+
+        @Override
+        public N next()
+        {
+          return funcMtoN.apply(iterator.next(), p);
+        }
+
+
+
+        @Override
+        public int nextIndex()
+        {
+          return iterator.nextIndex();
+        }
+
+
+
+        @Override
+        public N previous()
+        {
+          return funcMtoN.apply(iterator.previous(), p);
+        }
+
+
+
+        @Override
+        public int previousIndex()
+        {
+          return iterator.previousIndex();
+        }
+
+
+
+        @Override
+        public void remove()
+        {
+          iterator.remove();
+        }
+
+
+
+        @Override
+        public void set(final N e)
+        {
+          iterator.set(funcNtoM.apply(e, p));
+        }
+
+      };
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public N remove(final int index)
+    {
+      return funcMtoN.apply(collection.remove(index), p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public N set(final int index, final N element)
+    {
+      final M result = collection.set(index, funcNtoM.apply(element, p));
+      return funcMtoN.apply(result, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<N> subList(final int fromIndex, final int toIndex)
+    {
+      final List<M> subList = collection.subList(fromIndex, toIndex);
+      return new TransformedList<M, N, P>(subList, funcMtoN, funcNtoM, p);
+    }
+
+  }
+
+
+
   /**
    * Returns a view of {@code collection} whose values have been mapped to
    * elements of type {@code N} using {@code funcMtoN}. The returned collection
@@ -159,9 +368,9 @@
    * @param <N>
    *          The type of elements contained in the returned collection.
    * @param <P>
-   *          The type of the additional parameter to the function's {@code
-   *          apply} method. Use {@link java.lang.Void} for functions that do
-   *          not need an additional parameter.
+   *          The type of the additional parameter to the function's
+   *          {@code apply} method. Use {@link java.lang.Void} for functions
+   *          that do not need an additional parameter.
    * @param collection
    *          The collection to be transformed.
    * @param funcMtoN
@@ -177,12 +386,13 @@
    * @return A view of {@code collection} whose values have been mapped to
    *         elements of type {@code N} using {@code funcMtoN}.
    */
-  public static <M, N, P> Collection<N> transform(
+  public static <M, N, P> Collection<N> transformedCollection(
       final Collection<M> collection,
       final Function<? super M, ? extends N, P> funcMtoN,
       final Function<? super N, ? extends M, P> funcNtoM, final P p)
   {
-    return new TransformedCollection<M, N, P>(collection, funcMtoN, funcNtoM, p);
+    return new TransformedCollection<M, N, P, Collection<M>>(collection,
+        funcMtoN, funcNtoM, p);
   }
 
 
@@ -209,12 +419,81 @@
    * @return A view of {@code collection} whose values have been mapped to
    *         elements of type {@code N} using {@code funcMtoN}.
    */
-  public static <M, N> Collection<N> transform(final Collection<M> collection,
+  public static <M, N> Collection<N> transformedCollection(
+      final Collection<M> collection,
       final Function<? super M, ? extends N, Void> funcMtoN,
       final Function<? super N, ? extends M, Void> funcNtoM)
   {
-    return new TransformedCollection<M, N, Void>(collection, funcMtoN,
-        funcNtoM, null);
+    return new TransformedCollection<M, N, Void, Collection<M>>(collection,
+        funcMtoN, funcNtoM, null);
+  }
+
+
+
+  /**
+   * Returns a view of {@code list} whose values have been mapped to elements of
+   * type {@code N} using {@code funcMtoN}. The returned list supports all
+   * operations.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code list}.
+   * @param <N>
+   *          The type of elements contained in the returned list.
+   * @param <P>
+   *          The type of the additional parameter to the function's
+   *          {@code apply} method. Use {@link java.lang.Void} for functions
+   *          that do not need an additional parameter.
+   * @param list
+   *          The list to be transformed.
+   * @param funcMtoN
+   *          A function which maps values of type {@code M} to values of type
+   *          {@code N}. This function will be used when retrieving values from
+   *          {@code list}.
+   * @param funcNtoM
+   *          A function which maps values of type {@code N} to values of type
+   *          {@code M}. This function will be used when performing queries and
+   *          adding values to {@code list} .
+   * @param p
+   *          A predicate specified parameter.
+   * @return A view of {@code list} whose values have been mapped to elements of
+   *         type {@code N} using {@code funcMtoN}.
+   */
+  public static <M, N, P> List<N> transformedList(final List<M> list,
+      final Function<? super M, ? extends N, P> funcMtoN,
+      final Function<? super N, ? extends M, P> funcNtoM, final P p)
+  {
+    return new TransformedList<M, N, P>(list, funcMtoN, funcNtoM, p);
+  }
+
+
+
+  /**
+   * Returns a view of {@code list} whose values have been mapped to elements of
+   * type {@code N} using {@code funcMtoN}. The returned list supports all
+   * operations.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code list}.
+   * @param <N>
+   *          The type of elements contained in the returned list.
+   * @param list
+   *          The list to be transformed.
+   * @param funcMtoN
+   *          A function which maps values of type {@code M} to values of type
+   *          {@code N}. This function will be used when retrieving values from
+   *          {@code list}.
+   * @param funcNtoM
+   *          A function which maps values of type {@code N} to values of type
+   *          {@code M}. This function will be used when performing queries and
+   *          adding values to {@code list} .
+   * @return A view of {@code list} whose values have been mapped to elements of
+   *         type {@code N} using {@code funcMtoN}.
+   */
+  public static <M, N> List<N> transformedList(final List<M> list,
+      final Function<? super M, ? extends N, Void> funcMtoN,
+      final Function<? super N, ? extends M, Void> funcNtoM)
+  {
+    return new TransformedList<M, N, Void>(list, funcMtoN, funcNtoM, null);
   }
 
 
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Functions.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Functions.java
index d90d987..7892222 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Functions.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Functions.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
  */
 
 package com.sun.opends.sdk.util;
@@ -174,6 +174,17 @@
     }
   };
 
+  private static final Function<Object, Object, Void> IDENTITY =
+    new Function<Object, Object, Void>()
+  {
+
+    public Object apply(Object value, Void p)
+    {
+      return value;
+    }
+
+  };
+
 
 
   /**
@@ -204,6 +215,23 @@
 
 
   /**
+   * Returns a function which always returns the value that it was provided
+   * with.
+   *
+   * @param <M>
+   *          The type of values transformed by this function.
+   * @return A function which always returns the value that it was provided
+   *         with.
+   */
+  @SuppressWarnings("unchecked")
+  public static <M> Function<M, M, Void> identityFunction()
+  {
+    return (Function<M, M, Void>) IDENTITY;
+  }
+
+
+
+  /**
    * Returns a function which converts a {@code String} to lower case using
    * {@link StaticUtils#toLowerCase} and then trims it.
    *
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Iterables.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Iterables.java
index 84f2bc9..c3e3d66 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Iterables.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Iterables.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
  */
 
 package com.sun.opends.sdk.util;
@@ -73,7 +73,7 @@
      */
     public Iterator<M> iterator()
     {
-      return Iterators.empty();
+      return Iterators.emptyIterator();
     }
 
   }
@@ -105,7 +105,7 @@
      */
     public Iterator<M> iterator()
     {
-      return Iterators.filter(iterable.iterator(), predicate, parameter);
+      return Iterators.filteredIterator(iterable.iterator(), predicate, parameter);
     }
 
   }
@@ -132,7 +132,7 @@
      */
     public Iterator<M> iterator()
     {
-      return Iterators.singleton(value);
+      return Iterators.singletonIterator(value);
     }
 
   }
@@ -165,7 +165,7 @@
      */
     public Iterator<N> iterator()
     {
-      return Iterators.transform(iterable.iterator(), function, parameter);
+      return Iterators.transformedIterator(iterable.iterator(), function, parameter);
     }
 
   }
@@ -192,7 +192,7 @@
      */
     public Iterator<M> iterator()
     {
-      return Iterators.unmodifiable(iterable.iterator());
+      return Iterators.unmodifiableIterator(iterable.iterator());
     }
 
   }
@@ -205,8 +205,8 @@
 
   /**
    * Returns an iterable containing the elements of {@code a}. The returned
-   * iterable's iterator does not support element removal via the {@code
-   * remove()} method.
+   * iterable's iterator does not support element removal via the
+   * {@code remove()} method.
    *
    * @param <M>
    *          The type of elements contained in {@code a}.
@@ -229,7 +229,7 @@
    * @return An immutable empty iterable.
    */
   @SuppressWarnings("unchecked")
-  public static <M> Iterable<M> empty()
+  public static <M> Iterable<M> emptyIterable()
   {
     return (Iterable<M>) EMPTY_ITERABLE;
   }
@@ -245,9 +245,9 @@
    * @param <M>
    *          The type of elements contained in {@code iterable}.
    * @param <P>
-   *          The type of the additional parameter to the predicate's {@code
-   *          matches} method. Use {@link java.lang.Void} for predicates that do
-   *          not need an additional parameter.
+   *          The type of the additional parameter to the predicate's
+   *          {@code matches} method. Use {@link java.lang.Void} for predicates
+   *          that do not need an additional parameter.
    * @param iterable
    *          The iterable to be filtered.
    * @param predicate
@@ -257,7 +257,7 @@
    * @return A filtered view of {@code iterable} containing only those elements
    *         which match {@code predicate}.
    */
-  public static <M, P> Iterable<M> filter(final Iterable<M> iterable,
+  public static <M, P> Iterable<M> filteredIterable(final Iterable<M> iterable,
       final Predicate<? super M, P> predicate, final P p)
   {
     return new FilteredIterable<M, P>(iterable, predicate, p);
@@ -280,7 +280,7 @@
    * @return A filtered view of {@code iterable} containing only those elements
    *         which match {@code predicate}.
    */
-  public static <M> Iterable<M> filter(final Iterable<M> iterable,
+  public static <M> Iterable<M> filteredIterable(final Iterable<M> iterable,
       final Predicate<? super M, Void> predicate)
   {
     return new FilteredIterable<M, Void>(iterable, predicate, null);
@@ -299,7 +299,7 @@
    *          The single element.
    * @return An iterable containing the single element {@code value}.
    */
-  public static <M> Iterable<M> singleton(final M value)
+  public static <M> Iterable<M> singletonIterable(final M value)
   {
     return new SingletonIterable<M>(value);
   }
@@ -317,9 +317,9 @@
    * @param <N>
    *          The type of elements contained in the returned iterable.
    * @param <P>
-   *          The type of the additional parameter to the function's {@code
-   *          apply} method. Use {@link java.lang.Void} for functions that do
-   *          not need an additional parameter.
+   *          The type of the additional parameter to the function's
+   *          {@code apply} method. Use {@link java.lang.Void} for functions
+   *          that do not need an additional parameter.
    * @param iterable
    *          The iterable to be transformed.
    * @param function
@@ -329,7 +329,8 @@
    * @return A view of {@code iterable} whose values have been mapped to
    *         elements of type {@code N} using {@code function}.
    */
-  public static <M, N, P> Iterable<N> transform(final Iterable<M> iterable,
+  public static <M, N, P> Iterable<N> transformedIterable(
+      final Iterable<M> iterable,
       final Function<? super M, ? extends N, P> function, final P p)
   {
     return new TransformedIterable<M, N, P>(iterable, function, p);
@@ -354,7 +355,8 @@
    * @return A view of {@code iterable} whose values have been mapped to
    *         elements of type {@code N} using {@code function}.
    */
-  public static <M, N> Iterable<N> transform(final Iterable<M> iterable,
+  public static <M, N> Iterable<N> transformedIterable(
+      final Iterable<M> iterable,
       final Function<? super M, ? extends N, Void> function)
   {
     return new TransformedIterable<M, N, Void>(iterable, function, null);
@@ -365,8 +367,8 @@
   /**
    * Returns a read-only view of {@code iterable} whose iterator does not
    * support element removal via the {@code remove()}. Attempts to use the
-   * {@code remove()} method will result in a {@code
-   * UnsupportedOperationException}.
+   * {@code remove()} method will result in a
+   * {@code UnsupportedOperationException}.
    *
    * @param <M>
    *          The type of elements contained in {@code iterable}.
@@ -375,7 +377,7 @@
    * @return A read-only view of {@code iterable} whose iterator does not
    *         support element removal via the {@code remove()}.
    */
-  public static <M> Iterable<M> unmodifiable(final Iterable<M> iterable)
+  public static <M> Iterable<M> unmodifiableIterable(final Iterable<M> iterable)
   {
     return new UnmodifiableIterable<M>(iterable);
   }
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Iterators.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Iterators.java
index b26f4e0..e58e1e0 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Iterators.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Iterators.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
  */
 
 package com.sun.opends.sdk.util;
@@ -384,7 +384,7 @@
    * @return An immutable empty iterator.
    */
   @SuppressWarnings("unchecked")
-  public static <M> Iterator<M> empty()
+  public static <M> Iterator<M> emptyIterator()
   {
     return (Iterator<M>) EMPTY_ITERATOR;
   }
@@ -400,9 +400,9 @@
    * @param <M>
    *          The type of elements contained in {@code iterator}.
    * @param <P>
-   *          The type of the additional parameter to the predicate's {@code
-   *          matches} method. Use {@link java.lang.Void} for predicates that do
-   *          not need an additional parameter.
+   *          The type of the additional parameter to the predicate's
+   *          {@code matches} method. Use {@link java.lang.Void} for predicates
+   *          that do not need an additional parameter.
    * @param iterator
    *          The iterator to be filtered.
    * @param predicate
@@ -412,7 +412,7 @@
    * @return A filtered view of {@code iterator} containing only those elements
    *         which match {@code predicate}.
    */
-  public static <M, P> Iterator<M> filter(final Iterator<M> iterator,
+  public static <M, P> Iterator<M> filteredIterator(final Iterator<M> iterator,
       final Predicate<? super M, P> predicate, final P p)
   {
     return new FilteredIterator<M, P>(iterator, predicate, p);
@@ -435,7 +435,7 @@
    * @return A filtered view of {@code iterator} containing only those elements
    *         which match {@code predicate}.
    */
-  public static <M> Iterator<M> filter(final Iterator<M> iterator,
+  public static <M> Iterator<M> filteredIterator(final Iterator<M> iterator,
       final Predicate<? super M, Void> predicate)
   {
     return new FilteredIterator<M, Void>(iterator, predicate, null);
@@ -454,7 +454,7 @@
    *          The single element to be returned by the iterator.
    * @return An iterator containing the single element {@code value}.
    */
-  public static <M> Iterator<M> singleton(final M value)
+  public static <M> Iterator<M> singletonIterator(final M value)
   {
     return new SingletonIterator<M>(value);
   }
@@ -472,9 +472,9 @@
    * @param <N>
    *          The type of elements contained in the returned iterator.
    * @param <P>
-   *          The type of the additional parameter to the function's {@code
-   *          apply} method. Use {@link java.lang.Void} for functions that do
-   *          not need an additional parameter.
+   *          The type of the additional parameter to the function's
+   *          {@code apply} method. Use {@link java.lang.Void} for functions
+   *          that do not need an additional parameter.
    * @param iterator
    *          The iterator to be transformed.
    * @param function
@@ -484,7 +484,8 @@
    * @return A view of {@code iterator} whose values have been mapped to
    *         elements of type {@code N} using {@code function}.
    */
-  public static <M, N, P> Iterator<N> transform(final Iterator<M> iterator,
+  public static <M, N, P> Iterator<N> transformedIterator(
+      final Iterator<M> iterator,
       final Function<? super M, ? extends N, P> function, final P p)
   {
     return new TransformedIterator<M, N, P>(iterator, function, p);
@@ -509,7 +510,8 @@
    * @return A view of {@code iterator} whose values have been mapped to
    *         elements of type {@code N} using {@code function}.
    */
-  public static <M, N> Iterator<N> transform(final Iterator<M> iterator,
+  public static <M, N> Iterator<N> transformedIterator(
+      final Iterator<M> iterator,
       final Function<? super M, ? extends N, Void> function)
   {
     return new TransformedIterator<M, N, Void>(iterator, function, null);
@@ -529,7 +531,7 @@
    * @return A read-only view of {@code iterator} which does not support element
    *         removal via the {@code remove()}.
    */
-  public static <M> Iterator<M> unmodifiable(final Iterator<M> iterator)
+  public static <M> Iterator<M> unmodifiableIterator(final Iterator<M> iterator)
   {
     return new UnmodifiableIterator<M>(iterator);
   }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/AbstractEntry.java b/opendj-sdk/sdk/src/org/opends/sdk/AbstractEntry.java
index 6898a9a..a266c2d 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/AbstractEntry.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/AbstractEntry.java
@@ -266,7 +266,7 @@
   {
     Validator.ensureNotNull(attributeDescription);
 
-    return Iterables.filter(getAllAttributes(), FIND_ATTRIBUTES_PREDICATE,
+    return Iterables.filteredIterable(getAllAttributes(), FIND_ATTRIBUTES_PREDICATE,
         attributeDescription);
   }
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/AttributeDescription.java b/opendj-sdk/sdk/src/org/opends/sdk/AttributeDescription.java
index 07d3e22..6367cdb 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/AttributeDescription.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/AttributeDescription.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk;
@@ -394,7 +394,7 @@
 
     public Iterator<String> iterator()
     {
-      return Iterators.singleton(option);
+      return Iterators.singletonIterator(option);
     }
 
 
@@ -489,7 +489,7 @@
 
     public Iterator<String> iterator()
     {
-      return Iterators.empty();
+      return Iterators.emptyIterator();
     }
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/Attributes.java b/opendj-sdk/sdk/src/org/opends/sdk/Attributes.java
index 1ae5c2a..aec200c 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/Attributes.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/Attributes.java
@@ -107,7 +107,7 @@
     @Override
     public Iterator<ByteString> iterator()
     {
-      return Iterators.empty();
+      return Iterators.emptyIterator();
     }
 
 
@@ -464,7 +464,7 @@
 
     public Iterator<ByteString> iterator()
     {
-      return Iterators.unmodifiable(attribute.iterator());
+      return Iterators.unmodifiableIterator(attribute.iterator());
     }
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/Entries.java b/opendj-sdk/sdk/src/org/opends/sdk/Entries.java
index 55a17da..821aea3 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/Entries.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/Entries.java
@@ -141,7 +141,7 @@
     @Override
     public Iterable<Attribute> getAllAttributes()
     {
-      return Iterables.unmodifiable(Iterables.transform(
+      return Iterables.unmodifiableIterable(Iterables.transformedIterable(
           entry.getAllAttributes(), UNMODIFIABLE_ATTRIBUTE_FUNCTION));
     }
 
@@ -151,7 +151,7 @@
     public Iterable<Attribute> getAllAttributes(
         final AttributeDescription attributeDescription)
     {
-      return Iterables.unmodifiable(Iterables.transform(
+      return Iterables.unmodifiableIterable(Iterables.transformedIterable(
           entry.getAllAttributes(attributeDescription),
           UNMODIFIABLE_ATTRIBUTE_FUNCTION));
     }
@@ -166,7 +166,7 @@
         final String attributeDescription)
         throws LocalizedIllegalArgumentException, NullPointerException
     {
-      return Iterables.unmodifiable(Iterables.transform(
+      return Iterables.unmodifiableIterable(Iterables.transformedIterable(
           entry.getAllAttributes(attributeDescription),
           UNMODIFIABLE_ATTRIBUTE_FUNCTION));
     }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/LinkedHashMapEntry.java b/opendj-sdk/sdk/src/org/opends/sdk/LinkedHashMapEntry.java
index 9ddd0e9..3dd847e 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/LinkedHashMapEntry.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/LinkedHashMapEntry.java
@@ -38,10 +38,10 @@
 
 
 /**
- * An implementation of the {@code Entry} interface which uses a {@code
- * LinkedHashMap} for storing attributes. Attributes are returned in the same
- * order that they were added to the entry. All operations are supported by this
- * implementation.
+ * An implementation of the {@code Entry} interface which uses a
+ * {@code LinkedHashMap} for storing attributes. Attributes are returned in the
+ * same order that they were added to the entry. All operations are supported by
+ * this implementation.
  * <p>
  * A {@code LinkedHashMapEntry} stores references to attributes which have been
  * added using the {@link #addAttribute} methods. Attributes sharing the same
@@ -69,6 +69,34 @@
 
 
   /**
+   * Creates an entry having the same distinguished name, attributes, and object
+   * classes of the provided entry. This constructor performs a deep copy of
+   * {@code entry} and will copy each attribute as a {@link LinkedAttribute}.
+   * <p>
+   * A shallow copy constructor is provided by
+   * {@link #LinkedHashMapEntry(Entry)}.
+   *
+   * @param entry
+   *          The entry to be copied.
+   * @return A deep copy of {@code entry}.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   * @see #LinkedHashMapEntry(Entry)
+   */
+  public static LinkedHashMapEntry deepCopyOfEntry(final Entry entry)
+      throws NullPointerException
+  {
+    LinkedHashMapEntry copy = new LinkedHashMapEntry(entry.getName());
+    for (final Attribute attribute : entry.getAllAttributes())
+    {
+      copy.addAttribute(new LinkedAttribute(attribute));
+    }
+    return copy;
+  }
+
+
+
+  /**
    * Creates an entry with an empty (root) distinguished name and no attributes.
    */
   public LinkedHashMapEntry()
@@ -97,19 +125,23 @@
 
   /**
    * Creates an entry having the same distinguished name, attributes, and object
-   * classes of the provided entry.
+   * classes of the provided entry. This constructor performs a shallow copy of
+   * {@code entry} and will not copy the attributes contained in {@code entry}.
+   * <p>
+   * A deep copy constructor is provided by {@link #deepCopyOfEntry(Entry)}
    *
    * @param entry
    *          The entry to be copied.
    * @throws NullPointerException
    *           If {@code entry} was {@code null}.
+   * @see #deepCopyOfEntry(Entry)
    */
   public LinkedHashMapEntry(final Entry entry) throws NullPointerException
   {
     this(entry.getName());
     for (final Attribute attribute : entry.getAllAttributes())
     {
-      addAttribute(new LinkedAttribute(attribute));
+      addAttribute(attribute);
     }
   }
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/Modification.java b/opendj-sdk/sdk/src/org/opends/sdk/Modification.java
index e0fe1f0..3f61b9c 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/Modification.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/Modification.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk;
@@ -35,8 +35,6 @@
 
 /**
  * A modification to be performed on an entry during a Modify operation.
- * <p>
- * TODO: other constructors.
  */
 public final class Modification
 {
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java b/opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java
index b5762dd..f06a1da 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java
@@ -481,7 +481,7 @@
     final Attribute attr = entry.getAttribute(attributeDescription);
     if (attr != null)
     {
-      return Collections.unmodifiableCollection(Collections2.transform(attr,
+      return Collections.unmodifiableCollection(Collections2.transformedCollection(attr,
           function, Functions.objectToByteString()));
     }
     else
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/TreeMapEntry.java b/opendj-sdk/sdk/src/org/opends/sdk/TreeMapEntry.java
index 75b46d3..0cd3550 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/TreeMapEntry.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/TreeMapEntry.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
  */
 
 package org.opends.sdk;
@@ -70,6 +70,33 @@
 
 
   /**
+   * Creates an entry having the same distinguished name, attributes, and object
+   * classes of the provided entry. This constructor performs a deep copy of
+   * {@code entry} and will copy each attribute as a {@link LinkedAttribute}.
+   * <p>
+   * A shallow copy constructor is provided by {@link #TreeMapEntry(Entry)}.
+   *
+   * @param entry
+   *          The entry to be copied.
+   * @return A deep copy of {@code entry}.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   * @see #TreeMapEntry(Entry)
+   */
+  public static TreeMapEntry deepCopyOfEntry(final Entry entry)
+      throws NullPointerException
+  {
+    TreeMapEntry copy = new TreeMapEntry(entry.getName());
+    for (final Attribute attribute : entry.getAllAttributes())
+    {
+      copy.addAttribute(new LinkedAttribute(attribute));
+    }
+    return copy;
+  }
+
+
+
+  /**
    * Creates an entry with an empty (root) distinguished name and no attributes.
    */
   public TreeMapEntry()
@@ -98,12 +125,16 @@
 
   /**
    * Creates an entry having the same distinguished name, attributes, and object
-   * classes of the provided entry.
+   * classes of the provided entry. This constructor performs a shallow copy of
+   * {@code entry} and will not copy the attributes contained in {@code entry}.
+   * <p>
+   * A deep copy constructor is provided by {@link #deepCopyOfEntry(Entry)}
    *
    * @param entry
    *          The entry to be copied.
    * @throws NullPointerException
    *           If {@code entry} was {@code null}.
+   * @see #deepCopyOfEntry(Entry)
    */
   public TreeMapEntry(final Entry entry) throws NullPointerException
   {
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 e614f8d..310b594 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractRequestImpl.java
@@ -36,6 +36,7 @@
 import org.opends.sdk.DecodeOptions;
 import org.opends.sdk.controls.Control;
 import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.controls.GenericControl;
 
 import com.sun.opends.sdk.util.Validator;
 
@@ -75,10 +76,15 @@
   AbstractRequestImpl(Request request) throws NullPointerException
   {
     Validator.ensureNotNull(request);
-    controls.addAll(request.getControls());
+    for (Control control : request.getControls())
+    {
+      // Create defensive copy.
+      controls.add(GenericControl.newControl(control));
+    }
   }
 
 
+
   /**
    * {@inheritDoc}
    */
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractaUnmodifiableBindRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableBindRequest.java
similarity index 100%
rename from opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractaUnmodifiableBindRequest.java
rename to opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableBindRequest.java
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequest.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequest.java
index 3bba75c..128b2c9 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequest.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AbstractUnmodifiableRequest.java
@@ -36,6 +36,12 @@
 import org.opends.sdk.DecodeOptions;
 import org.opends.sdk.controls.Control;
 import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.controls.GenericControl;
+
+import com.sun.opends.sdk.util.Collections2;
+import com.sun.opends.sdk.util.Function;
+import com.sun.opends.sdk.util.Functions;
+import com.sun.opends.sdk.util.Validator;
 
 
 
@@ -69,6 +75,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public final R addControl(final Control control)
       throws UnsupportedOperationException, NullPointerException
   {
@@ -80,12 +87,49 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public final <C extends Control> C getControl(
       final ControlDecoder<C> decoder, final DecodeOptions options)
       throws NullPointerException, DecodeException
   {
-    // FIXME: ensure that controls are immutable.
-    return impl.getControl(decoder, options);
+    Validator.ensureNotNull(decoder, options);
+
+    final List<Control> controls = impl.getControls();
+
+    // Avoid creating an iterator if possible.
+    if (controls.isEmpty())
+    {
+      return null;
+    }
+
+    for (final Control control : controls)
+    {
+      if (control.getOID().equals(decoder.getOID()))
+      {
+        // Got a match. Return a defensive copy only if necessary.
+        final C decodedControl = decoder.decodeControl(control, options);
+
+        if (decodedControl != control)
+        {
+          // This was not the original control so return it immediately.
+          return decodedControl;
+        }
+        else if (decodedControl instanceof GenericControl)
+        {
+          // Generic controls are immutable, so return it immediately.
+          return decodedControl;
+        }
+        else
+        {
+          // Re-decode to get defensive copy.
+          final GenericControl genericControl = GenericControl
+              .newControl(control);
+          return decoder.decodeControl(genericControl, options);
+        }
+      }
+    }
+
+    return null;
   }
 
 
@@ -93,10 +137,26 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public final List<Control> getControls()
   {
-    // FIXME: ensure that controls are immutable.
-    return Collections.unmodifiableList(impl.getControls());
+    // We need to make all controls unmodifiable as well, which implies making
+    // defensive copies where necessary.
+    final Function<Control, Control, Void> function = new Function<Control, Control, Void>()
+    {
+
+      @Override
+      public Control apply(final Control value, final Void p)
+      {
+        // Return defensive copy.
+        return GenericControl.newControl(value);
+      }
+
+    };
+
+    final List<Control> unmodifiableControls = Collections2.transformedList(
+        impl.getControls(), function, Functions.<Control> identityFunction());
+    return Collections.unmodifiableList(unmodifiableControls);
   }
 
 
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 a0436b8..8115fcf 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/AddRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/AddRequestImpl.java
@@ -77,7 +77,7 @@
   AddRequestImpl(final AddRequest addRequest) throws NullPointerException
   {
     super(addRequest);
-    this.entry = new LinkedHashMapEntry(addRequest);
+    this.entry = LinkedHashMapEntry.deepCopyOfEntry(addRequest);
   }
 
 
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 1f07117..0577a5c 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/ModifyRequestImpl.java
@@ -80,7 +80,15 @@
   {
     super(modifyRequest);
     this.name = modifyRequest.getName();
-    this.changes.addAll(modifyRequest.getModifications());
+
+    // Deep copy.
+    for (Modification modification : modifyRequest.getModifications())
+    {
+      ModificationType type = modification.getModificationType();
+      Attribute attribute = new LinkedAttribute(modification.getAttribute());
+      Modification copy = new Modification(type, attribute);
+      this.changes.add(copy);
+    }
   }
 
 
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 f3963ab..9815d0b 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/Requests.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/Requests.java
@@ -29,7 +29,7 @@
 
 
 
-import static com.sun.opends.sdk.messages.Messages.WARN_READ_LDIF_RECORD_CHANGE_RECORD_WRONG_TYPE;
+import static com.sun.opends.sdk.messages.Messages.*;
 
 import javax.net.ssl.SSLContext;
 import javax.security.auth.Subject;
@@ -45,15 +45,25 @@
 /**
  * This class contains various methods for creating and manipulating requests.
  * <p>
- * TODO: search request from LDAP URL.
+ * All copy constructors of the form {@code copyOfXXXRequest} perform deep
+ * copies of their request parameter. More specifically, any controls,
+ * modifications, and attributes contained within the response will be
+ * duplicated.
  * <p>
- * TODO: update request from persistent search result.
- * <p>
- * TODO: synchronized requests?
+ * Similarly, all unmodifiable views of request returned by methods of the form
+ * {@code unmodifiableXXXRequest} return deep unmodifiable views of their
+ * request parameter. More specifically, any controls, modifications, and
+ * attributes contained within the returned request will be unmodifiable.
  */
 public final class Requests
 {
 
+  // TODO: search request from LDAP URL.
+
+  // TODO: update request from persistent search result.
+
+  // TODO: synchronized requests?
+
   /**
    * Creates a new abandon request using the provided message ID.
    *
@@ -232,8 +242,8 @@
    *          The assertion value to be compared.
    * @return The new compare request.
    * @throws NullPointerException
-   *           If {@code name}, {@code attributeDescription}, or {@code
-   *           assertionValue} was {@code null}.
+   *           If {@code name}, {@code attributeDescription}, or
+   *           {@code assertionValue} was {@code null}.
    */
   public static CompareRequest newCompareRequest(final DN name,
       final AttributeDescription attributeDescription,
@@ -263,16 +273,17 @@
    *           If {@code name} or {@code attributeDescription} could not be
    *           decoded using the default schema.
    * @throws NullPointerException
-   *           If {@code name}, {@code attributeDescription}, or {@code
-   *           assertionValue} was {@code null}.
+   *           If {@code name}, {@code attributeDescription}, or
+   *           {@code assertionValue} was {@code null}.
    */
   public static CompareRequest newCompareRequest(final String name,
       final String attributeDescription, final Object assertionValue)
       throws LocalizedIllegalArgumentException, NullPointerException
   {
     Validator.ensureNotNull(name, attributeDescription, assertionValue);
-    return new CompareRequestImpl(DN.valueOf(name), AttributeDescription
-        .valueOf(attributeDescription), ByteString.valueOf(assertionValue));
+    return new CompareRequestImpl(DN.valueOf(name),
+        AttributeDescription.valueOf(attributeDescription),
+        ByteString.valueOf(assertionValue));
   }
 
 
@@ -874,20 +885,23 @@
 
 
 
-
   /**
    * Creates an unmodifiable abandon request of the provided request.
    *
-   * @param abandonRequest
+   * @param request
    *          The abandon request to be copied.
    * @return The new abandon request.
    * @throws NullPointerException
-   *           If {@code abandonRequest} was {@code null}
+   *           If {@code request} was {@code null}
    */
   public static AbandonRequest unmodifiableAbandonRequest(
-      final AbandonRequest abandonRequest) throws NullPointerException
+      final AbandonRequest request) throws NullPointerException
   {
-    return new UnmodifiableAbandonRequestImpl(abandonRequest);
+    if (request instanceof UnmodifiableAbandonRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableAbandonRequestImpl(request);
   }
 
 
@@ -895,35 +909,42 @@
   /**
    * Creates an unmodifiable add request of the provided request.
    *
-   * @param addRequest
+   * @param request
    *          The add request to be copied.
    * @return The new add request.
    * @throws NullPointerException
-   *           If {@code addRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
-  public static AddRequest unmodifiableAddRequest(final AddRequest addRequest)
+  public static AddRequest unmodifiableAddRequest(final AddRequest request)
       throws NullPointerException
   {
-    return new UnmodifiableAddRequestImpl(addRequest);
+    if (request instanceof UnmodifiableAddRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableAddRequestImpl(request);
   }
 
 
 
   /**
-   * Creates an unmodifiable anonymous SASL bind request of the provided request.
+   * Creates an unmodifiable anonymous SASL bind request of the provided
+   * request.
    *
-   * @param anonymousSASLBindRequest
+   * @param request
    *          The anonymous SASL bind request to be copied.
    * @return The new anonymous SASL bind request.
    * @throws NullPointerException
-   *           If {@code anonymousSASLBindRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static AnonymousSASLBindRequest unmodifiableAnonymousSASLBindRequest(
-      final AnonymousSASLBindRequest anonymousSASLBindRequest)
-      throws NullPointerException
+      final AnonymousSASLBindRequest request) throws NullPointerException
   {
-    return new UnmodifiableAnonymousSASLBindRequestImpl(
-        anonymousSASLBindRequest);
+    if (request instanceof UnmodifiableAnonymousSASLBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableAnonymousSASLBindRequestImpl(request);
   }
 
 
@@ -931,17 +952,20 @@
   /**
    * Creates an unmodifiable cancel extended request of the provided request.
    *
-   * @param cancelExtendedRequest
+   * @param request
    *          The cancel extended request to be copied.
    * @return The new cancel extended request.
    * @throws NullPointerException
-   *           If {@code cancelExtendedRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static CancelExtendedRequest unmodifiableCancelExtendedRequest(
-      final CancelExtendedRequest cancelExtendedRequest)
-      throws NullPointerException
+      final CancelExtendedRequest request) throws NullPointerException
   {
-    return new UnmodifiableCancelExtendedRequestImpl(cancelExtendedRequest);
+    if (request instanceof UnmodifiableCancelExtendedRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableCancelExtendedRequestImpl(request);
   }
 
 
@@ -949,17 +973,20 @@
   /**
    * Creates an unmodifiable compare request of the provided request.
    *
-   * @param compareRequest
+   * @param request
    *          The compare request to be copied.
    * @return The new compare request.
    * @throws NullPointerException
-   *           If {@code compareRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static CompareRequest unmodifiableCompareRequest(
-      final CompareRequest compareRequest)
-      throws NullPointerException
+      final CompareRequest request) throws NullPointerException
   {
-    return new UnmodifiableCompareRequestImpl(compareRequest);
+    if (request instanceof UnmodifiableCompareRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableCompareRequestImpl(request);
   }
 
 
@@ -967,17 +994,20 @@
   /**
    * Creates an unmodifiable CRAM MD5 SASL bind request of the provided request.
    *
-   * @param cramMD5SASLBindRequest
+   * @param request
    *          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}.
+   *           If {@code request} was {@code null}.
    */
   public static CRAMMD5SASLBindRequest unmodifiableCRAMMD5SASLBindRequest(
-      final CRAMMD5SASLBindRequest cramMD5SASLBindRequest)
-      throws NullPointerException
+      final CRAMMD5SASLBindRequest request) throws NullPointerException
   {
-    return new UnmodifiableCRAMMD5SASLBindRequestImpl(cramMD5SASLBindRequest);
+    if (request instanceof UnmodifiableCRAMMD5SASLBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableCRAMMD5SASLBindRequestImpl(request);
   }
 
 
@@ -985,17 +1015,20 @@
   /**
    * Creates an unmodifiable delete request of the provided request.
    *
-   * @param deleteRequest
+   * @param request
    *          The add request to be copied.
    * @return The new delete request.
    * @throws NullPointerException
-   *           If {@code name} was {@code null}.
+   *           If {@code request} was {@code null}.
    */
   public static DeleteRequest unmodifiableDeleteRequest(
-      final DeleteRequest deleteRequest)
-      throws NullPointerException
+      final DeleteRequest request) throws NullPointerException
   {
-    return new UnmodifiableDeleteRequestImpl(deleteRequest);
+    if (request instanceof UnmodifiableDeleteRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableDeleteRequestImpl(request);
   }
 
 
@@ -1004,18 +1037,20 @@
    * Creates an unmodifiable digest MD5 SASL bind request of the provided
    * request.
    *
-   * @param digestMD5SASLBindRequest
+   * @param request
    *          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}.
+   *           If {@code request} was {@code null}.
    */
   public static DigestMD5SASLBindRequest unmodifiableDigestMD5SASLBindRequest(
-      final DigestMD5SASLBindRequest digestMD5SASLBindRequest)
-      throws NullPointerException
+      final DigestMD5SASLBindRequest request) throws NullPointerException
   {
-    return new UnmodifiableDigestMD5SASLBindRequestImpl(
-        digestMD5SASLBindRequest);
+    if (request instanceof UnmodifiableDigestMD5SASLBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableDigestMD5SASLBindRequestImpl(request);
   }
 
 
@@ -1023,17 +1058,20 @@
   /**
    * Creates an unmodifiable external SASL bind request of the provided request.
    *
-   * @param externalSASLBindRequest
+   * @param request
    *          The external SASL bind request to be copied.
    * @return The new External SASL bind request.
    * @throws NullPointerException
-   *           If {@code externalSASLBindRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static ExternalSASLBindRequest unmodifiableExternalSASLBindRequest(
-      final ExternalSASLBindRequest externalSASLBindRequest)
-      throws NullPointerException
+      final ExternalSASLBindRequest request) throws NullPointerException
   {
-    return new UnmodifiableExternalSASLBindRequestImpl(externalSASLBindRequest);
+    if (request instanceof UnmodifiableExternalSASLBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableExternalSASLBindRequestImpl(request);
   }
 
 
@@ -1041,17 +1079,20 @@
   /**
    * Creates an unmodifiable generic bind request of the provided request.
    *
-   * @param genericBindRequest
+   * @param request
    *          The generic bind request to be copied.
    * @return The new generic bind request.
    * @throws NullPointerException
-   *           If {@code genericBindRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static GenericBindRequest unmodifiableGenericBindRequest(
-      final GenericBindRequest genericBindRequest)
-      throws NullPointerException
+      final GenericBindRequest request) throws NullPointerException
   {
-    return new UnmodifiableGenericBindRequestImpl(genericBindRequest);
+    if (request instanceof UnmodifiableGenericBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableGenericBindRequestImpl(request);
   }
 
 
@@ -1059,17 +1100,20 @@
   /**
    * Creates an unmodifiable generic extended request of the provided request.
    *
-   * @param genericExtendedRequest
+   * @param request
    *          The generic extended request to be copied.
    * @return The new generic extended request.
    * @throws NullPointerException
-   *           If {@code extendedRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static GenericExtendedRequest unmodifiableGenericExtendedRequest(
-      GenericExtendedRequest genericExtendedRequest)
-      throws NullPointerException
+      GenericExtendedRequest request) throws NullPointerException
   {
-    return new UnmodifiableGenericExtendedRequestImpl(genericExtendedRequest);
+    if (request instanceof UnmodifiableGenericExtendedRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableGenericExtendedRequestImpl(request);
   }
 
 
@@ -1077,17 +1121,20 @@
   /**
    * Creates an unmodifiable GSSAPI SASL bind request of the provided request.
    *
-   * @param gssapiSASLBindRequest
+   * @param request
    *          The GSSAPI SASL bind request to be copied.
    * @return The new GSSAPI SASL bind request.
    * @throws NullPointerException
-   *           If {@code gssAPISASLBindRequest} was {@code null}.
+   *           If {@code request} was {@code null}.
    */
   public static GSSAPISASLBindRequest unmodifiableGSSAPISASLBindRequest(
-      final GSSAPISASLBindRequest gssapiSASLBindRequest)
-      throws NullPointerException
+      final GSSAPISASLBindRequest request) throws NullPointerException
   {
-    return new UnmodifiableGSSAPISASLBindRequestImpl(gssapiSASLBindRequest);
+    if (request instanceof UnmodifiableGSSAPISASLBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableGSSAPISASLBindRequestImpl(request);
   }
 
 
@@ -1095,34 +1142,41 @@
   /**
    * Creates an unmodifiable modify DN request of the provided request.
    *
-   * @param modifyDNRequest
+   * @param request
    *          The modify DN request to be copied.
    * @return The new modify DN request.
    * @throws NullPointerException
-   *           If {@code modifyDNRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static ModifyDNRequest unmodifiableModifyDNRequest(
-      final ModifyDNRequest modifyDNRequest)
-      throws NullPointerException
+      final ModifyDNRequest request) throws NullPointerException
   {
-    return new UnmodifiableModifyDNRequestImpl(modifyDNRequest);
+    if (request instanceof UnmodifiableModifyDNRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableModifyDNRequestImpl(request);
   }
 
 
+
   /**
    * Creates an unmodifiable modify request of the provided request.
    *
-   * @param modifyRequest
+   * @param request
    *          The modify request to be copied.
    * @return The new modify request.
    * @throws NullPointerException
-   *           If {@code modifyRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static ModifyRequest unmodifiableModifyRequest(
-      final ModifyRequest modifyRequest)
-      throws NullPointerException
+      final ModifyRequest request) throws NullPointerException
   {
-    return new UnmodifiableModifyRequestImpl(modifyRequest);
+    if (request instanceof UnmodifiableModifyRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableModifyRequestImpl(request);
   }
 
 
@@ -1131,19 +1185,20 @@
    * Creates an unmodifiable password modify extended request of the provided
    * request.
    *
-   * @param passwordModifyExtendedRequest
+   * @param request
    *          The password modify extended request to be copied.
    * @return The new password modify extended request.
    * @throws NullPointerException
-   *           If {@code passwordModifyExtendedRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
-  public static PasswordModifyExtendedRequest
-      unmodifiablePasswordModifyExtendedRequest(
-        final PasswordModifyExtendedRequest passwordModifyExtendedRequest)
-      throws NullPointerException
+  public static PasswordModifyExtendedRequest unmodifiablePasswordModifyExtendedRequest(
+      final PasswordModifyExtendedRequest request) throws NullPointerException
   {
-    return new UnmodifiablePasswordModifyExtendedRequestImpl(
-        passwordModifyExtendedRequest);
+    if (request instanceof UnmodifiablePasswordModifyExtendedRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiablePasswordModifyExtendedRequestImpl(request);
   }
 
 
@@ -1151,17 +1206,20 @@
   /**
    * Creates an unmodifiable plain SASL bind request of the provided request.
    *
-   * @param plainSASLBindRequest
+   * @param request
    *          The plain SASL bind request to be copied.
    * @return The new Plain SASL bind request.
    * @throws NullPointerException
-   *           If {@code plainSASLBindRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static PlainSASLBindRequest unmodifiablePlainSASLBindRequest(
-      final PlainSASLBindRequest plainSASLBindRequest)
-      throws NullPointerException
+      final PlainSASLBindRequest request) throws NullPointerException
   {
-    return new UnmodifiablePlainSASLBindRequestImpl(plainSASLBindRequest);
+    if (request instanceof UnmodifiablePlainSASLBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiablePlainSASLBindRequestImpl(request);
   }
 
 
@@ -1169,17 +1227,20 @@
   /**
    * Creates an unmodifiable search request of the provided request.
    *
-   * @param searchRequest
+   * @param request
    *          The search request to be copied.
    * @return The new search request.
    * @throws NullPointerException
-   *           If {@code searchRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static SearchRequest unmodifiableSearchRequest(
-      final SearchRequest searchRequest)
-      throws NullPointerException
+      final SearchRequest request) throws NullPointerException
   {
-    return new UnmodifiableSearchRequestImpl(searchRequest);
+    if (request instanceof UnmodifiableSearchRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableSearchRequestImpl(request);
   }
 
 
@@ -1187,17 +1248,20 @@
   /**
    * Creates an unmodifiable simple bind request of the provided request.
    *
-   * @param simpleBindRequest
+   * @param request
    *          The simple bind request to be copied.
    * @return The new simple bind request.
    * @throws NullPointerException
-   *           If {@code simpleBindRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static SimpleBindRequest unmodifiableSimpleBindRequest(
-      final SimpleBindRequest simpleBindRequest)
-      throws NullPointerException
+      final SimpleBindRequest request) throws NullPointerException
   {
-    return new UnmodifiableSimpleBindRequestImpl(simpleBindRequest);
+    if (request instanceof UnmodifiableSimpleBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableSimpleBindRequestImpl(request);
   }
 
 
@@ -1205,17 +1269,20 @@
   /**
    * Creates an unmodifiable startTLS extended request of the provided request.
    *
-   * @param startTLSExtendedRequest
+   * @param request
    *          The startTLS extended request to be copied.
    * @return The new start TLS extended request.
    * @throws NullPointerException
-   *           If {@code startTLSExtendedRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static StartTLSExtendedRequest unmodifiableStartTLSExtendedRequest(
-      final StartTLSExtendedRequest startTLSExtendedRequest)
-      throws NullPointerException
+      final StartTLSExtendedRequest request) throws NullPointerException
   {
-    return new UnmodifiableStartTLSExtendedRequestImpl(startTLSExtendedRequest);
+    if (request instanceof UnmodifiableStartTLSExtendedRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableStartTLSExtendedRequestImpl(request);
   }
 
 
@@ -1223,17 +1290,20 @@
   /**
    * Creates an unmodifiable unbind request of the provided request.
    *
-   * @param unbindRequest
+   * @param request
    *          The unbind request to be copied.
    * @return The new unbind request.
    * @throws NullPointerException
-   *           If {@code unbindRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static UnbindRequest unmodifiableUnbindRequest(
-      final UnbindRequest unbindRequest)
-      throws NullPointerException
+      final UnbindRequest request) throws NullPointerException
   {
-    return new UnmodifiableUnbindRequestImpl(unbindRequest);
+    if (request instanceof UnmodifiableUnbindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableUnbindRequestImpl(request);
   }
 
 
@@ -1242,54 +1312,55 @@
    * Creates an unmodifiable new Who Am I extended request of the provided
    * request.
    *
-   * @param whoAmIExtendedRequest
+   * @param request
    *          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} .
+   *           If {@code request} was {@code null} .
    */
   public static WhoAmIExtendedRequest unmodifiableWhoAmIExtendedRequest(
-      final WhoAmIExtendedRequest whoAmIExtendedRequest)
-      throws NullPointerException
+      final WhoAmIExtendedRequest request) throws NullPointerException
   {
-    return new UnmodifiableWhoAmIExtendedRequestImpl(whoAmIExtendedRequest);
+    if (request instanceof UnmodifiableWhoAmIExtendedRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableWhoAmIExtendedRequestImpl(request);
   }
 
 
 
-
   /**
    * Creates a new abandon request that is an exact copy of the provided
    * request.
    *
-   * @param abandonRequest
+   * @param request
    *          The abandon request to be copied.
    * @return The new abandon request.
    * @throws NullPointerException
-   *           If {@code abandonRequest} was {@code null}
+   *           If {@code request} was {@code null}
    */
-  public static AbandonRequest copyOfAbandonRequest(
-      final AbandonRequest abandonRequest) throws NullPointerException
+  public static AbandonRequest copyOfAbandonRequest(final AbandonRequest request)
+      throws NullPointerException
   {
-    return new AbandonRequestImpl(abandonRequest);
+    return new AbandonRequestImpl(request);
   }
 
 
 
   /**
-   * Creates a new add request that is an exact copy of the provided
-   * request.
+   * Creates a new add request that is an exact copy of the provided request.
    *
-   * @param addRequest
+   * @param request
    *          The add request to be copied.
    * @return The new add request.
    * @throws NullPointerException
-   *           If {@code addRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
-  public static AddRequest copyOfAddRequest(final AddRequest addRequest)
+  public static AddRequest copyOfAddRequest(final AddRequest request)
       throws NullPointerException
   {
-    return new AddRequestImpl(addRequest);
+    return new AddRequestImpl(request);
   }
 
 
@@ -1298,17 +1369,16 @@
    * Creates a new anonymous SASL bind request that is an exact copy of the
    * provided request.
    *
-   * @param anonymousSASLBindRequest
+   * @param request
    *          The anonymous SASL bind request to be copied.
    * @return The new anonymous SASL bind request.
    * @throws NullPointerException
-   *           If {@code anonymousSASLBindRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static AnonymousSASLBindRequest copyOfAnonymousSASLBindRequest(
-      final AnonymousSASLBindRequest anonymousSASLBindRequest)
-      throws NullPointerException
+      final AnonymousSASLBindRequest request) throws NullPointerException
   {
-    return new AnonymousSASLBindRequestImpl(anonymousSASLBindRequest);
+    return new AnonymousSASLBindRequestImpl(request);
   }
 
 
@@ -1317,17 +1387,16 @@
    * Creates a new cancel extended request that is an exact copy of the provided
    * request.
    *
-   * @param cancelExtendedRequest
+   * @param request
    *          The cancel extended request to be copied.
    * @return The new cancel extended request.
    * @throws NullPointerException
-   *           If {@code cancelExtendedRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static CancelExtendedRequest copyOfCancelExtendedRequest(
-      final CancelExtendedRequest cancelExtendedRequest)
-      throws NullPointerException
+      final CancelExtendedRequest request) throws NullPointerException
   {
-    return new CancelExtendedRequestImpl(cancelExtendedRequest);
+    return new CancelExtendedRequestImpl(request);
   }
 
 
@@ -1336,17 +1405,16 @@
    * Creates a new compare request that is an exact copy of the provided
    * request.
    *
-   * @param compareRequest
+   * @param request
    *          The compare request to be copied.
    * @return The new compare request.
    * @throws NullPointerException
-   *           If {@code compareRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
-  public static CompareRequest copyOfCompareRequest(
-      final CompareRequest compareRequest)
+  public static CompareRequest copyOfCompareRequest(final CompareRequest request)
       throws NullPointerException
   {
-    return new CompareRequestImpl(compareRequest);
+    return new CompareRequestImpl(request);
   }
 
 
@@ -1355,36 +1423,33 @@
    * Creates a new CRAM MD5 SASL bind request that is an exact copy of the
    * provided request.
    *
-   * @param cramMD5SASLBindRequest
+   * @param request
    *          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}.
+   *           If {@code request} was {@code null}.
    */
   public static CRAMMD5SASLBindRequest copyOfCRAMMD5SASLBindRequest(
-      final CRAMMD5SASLBindRequest cramMD5SASLBindRequest)
-      throws NullPointerException
+      final CRAMMD5SASLBindRequest request) throws NullPointerException
   {
-    return new CRAMMD5SASLBindRequestImpl(cramMD5SASLBindRequest);
+    return new CRAMMD5SASLBindRequestImpl(request);
   }
 
 
 
   /**
-   * Creates a new delete request that is an exact copy of the provided
-   * request.
+   * Creates a new delete request that is an exact copy of the provided request.
    *
-   * @param deleteRequest
+   * @param request
    *          The add request to be copied.
    * @return The new delete request.
    * @throws NullPointerException
-   *           If {@code name} was {@code null}.
+   *           If {@code request} was {@code null}.
    */
-  public static DeleteRequest copyOfDeleteRequest(
-      final DeleteRequest deleteRequest)
+  public static DeleteRequest copyOfDeleteRequest(final DeleteRequest request)
       throws NullPointerException
   {
-    return new DeleteRequestImpl(deleteRequest);
+    return new DeleteRequestImpl(request);
   }
 
 
@@ -1393,17 +1458,16 @@
    * Creates a new digest MD5 SASL bind request that is an exact copy of the
    * provided request.
    *
-   * @param digestMD5SASLBindRequest
+   * @param request
    *          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}.
+   *           If {@code request} was {@code null}.
    */
   public static DigestMD5SASLBindRequest copyOfDigestMD5SASLBindRequest(
-      final DigestMD5SASLBindRequest digestMD5SASLBindRequest)
-      throws NullPointerException
+      final DigestMD5SASLBindRequest request) throws NullPointerException
   {
-    return new DigestMD5SASLBindRequestImpl(digestMD5SASLBindRequest);
+    return new DigestMD5SASLBindRequestImpl(request);
   }
 
 
@@ -1412,36 +1476,34 @@
    * Creates a new external SASL bind request that is an exact copy of the
    * provided request.
    *
-   * @param externalSASLBindRequest
+   * @param request
    *          The external SASL bind request to be copied.
    * @return The new External SASL bind request.
    * @throws NullPointerException
-   *           If {@code externalSASLBindRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static ExternalSASLBindRequest copyOfExternalSASLBindRequest(
-      final ExternalSASLBindRequest externalSASLBindRequest)
-      throws NullPointerException
+      final ExternalSASLBindRequest request) throws NullPointerException
   {
-    return new ExternalSASLBindRequestImpl(externalSASLBindRequest);
+    return new ExternalSASLBindRequestImpl(request);
   }
 
 
 
   /**
-   * Creates a new generic bind request that is an exact copy of the
-   * provided request.
+   * Creates a new generic bind request that is an exact copy of the provided
+   * request.
    *
-   * @param genericBindRequest
+   * @param request
    *          The generic bind request to be copied.
    * @return The new generic bind request.
    * @throws NullPointerException
-   *           If {@code genericBindRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static GenericBindRequest copyOfGenericBindRequest(
-      final GenericBindRequest genericBindRequest)
-      throws NullPointerException
+      final GenericBindRequest request) throws NullPointerException
   {
-    return new GenericBindRequestImpl(genericBindRequest);
+    return new GenericBindRequestImpl(request);
   }
 
 
@@ -1450,17 +1512,16 @@
    * Creates a new generic extended request that is an exact copy of the
    * provided request.
    *
-   * @param genericExtendedRequest
+   * @param request
    *          The generic extended request to be copied.
    * @return The new generic extended request.
    * @throws NullPointerException
-   *           If {@code extendedRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static GenericExtendedRequest copyOfGenericExtendedRequest(
-      GenericExtendedRequest genericExtendedRequest)
-      throws NullPointerException
+      GenericExtendedRequest request) throws NullPointerException
   {
-    return new GenericExtendedRequestImpl(genericExtendedRequest);
+    return new GenericExtendedRequestImpl(request);
   }
 
 
@@ -1469,17 +1530,16 @@
    * Creates a new GSSAPI SASL bind request that is an exact copy of the
    * provided request.
    *
-   * @param gssapiSASLBindRequest
+   * @param request
    *          The GSSAPI SASL bind request to be copied.
    * @return The new GSSAPI SASL bind request.
    * @throws NullPointerException
-   *           If {@code gssAPISASLBindRequest} was {@code null}.
+   *           If {@code request} was {@code null}.
    */
   public static GSSAPISASLBindRequest copyOfGSSAPISASLBindRequest(
-      final GSSAPISASLBindRequest gssapiSASLBindRequest)
-      throws NullPointerException
+      final GSSAPISASLBindRequest request) throws NullPointerException
   {
-    return new GSSAPISASLBindRequestImpl(gssapiSASLBindRequest);
+    return new GSSAPISASLBindRequestImpl(request);
   }
 
 
@@ -1488,35 +1548,33 @@
    * Creates a new modify DN request that is an exact copy of the provided
    * request.
    *
-   * @param modifyDNRequest
+   * @param request
    *          The modify DN request to be copied.
    * @return The new modify DN request.
    * @throws NullPointerException
-   *           If {@code modifyDNRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static ModifyDNRequest copyOfModifyDNRequest(
-      final ModifyDNRequest modifyDNRequest)
-      throws NullPointerException
+      final ModifyDNRequest request) throws NullPointerException
   {
-    return new ModifyDNRequestImpl(modifyDNRequest);
+    return new ModifyDNRequestImpl(request);
   }
 
 
+
   /**
-   * Creates a new modify request that is an exact copy of the provided
-   * request.
+   * Creates a new modify request that is an exact copy of the provided request.
    *
-   * @param modifyRequest
+   * @param request
    *          The modify request to be copied.
    * @return The new modify request.
    * @throws NullPointerException
-   *           If {@code modifyRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
-  public static ModifyRequest copyOfModifyRequest(
-      final ModifyRequest modifyRequest)
+  public static ModifyRequest copyOfModifyRequest(final ModifyRequest request)
       throws NullPointerException
   {
-    return new ModifyRequestImpl(modifyRequest);
+    return new ModifyRequestImpl(request);
   }
 
 
@@ -1525,75 +1583,69 @@
    * Creates a new password modify extended request that is an exact copy of the
    * provided request.
    *
-   * @param passwordModifyExtendedRequest
+   * @param request
    *          The password modify extended request to be copied.
    * @return The new password modify extended request.
    * @throws NullPointerException
-   *           If {@code passwordModifyExtendedRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
-  public static PasswordModifyExtendedRequest
-      copyOfPasswordModifyExtendedRequest(
-        final PasswordModifyExtendedRequest passwordModifyExtendedRequest)
-      throws NullPointerException
+  public static PasswordModifyExtendedRequest copyOfPasswordModifyExtendedRequest(
+      final PasswordModifyExtendedRequest request) throws NullPointerException
   {
-    return new PasswordModifyExtendedRequestImpl(passwordModifyExtendedRequest);
+    return new PasswordModifyExtendedRequestImpl(request);
   }
 
 
 
   /**
-   * Creates a new plain SASL bind request that is an exact copy of the
-   * provided request.
+   * Creates a new plain SASL bind request that is an exact copy of the provided
+   * request.
    *
-   * @param plainSASLBindRequest
+   * @param request
    *          The plain SASL bind request to be copied.
    * @return The new Plain SASL bind request.
    * @throws NullPointerException
-   *           If {@code plainSASLBindRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static PlainSASLBindRequest copyOfPlainSASLBindRequest(
-      final PlainSASLBindRequest plainSASLBindRequest)
-      throws NullPointerException
+      final PlainSASLBindRequest request) throws NullPointerException
   {
-    return new PlainSASLBindRequestImpl(plainSASLBindRequest);
+    return new PlainSASLBindRequestImpl(request);
   }
 
 
 
   /**
-   * Creates a new search request that is an exact copy of the provided
-   * request.
+   * Creates a new search request that is an exact copy of the provided request.
    *
-   * @param searchRequest
+   * @param request
    *          The search request to be copied.
    * @return The new search request.
    * @throws NullPointerException
-   *           If {@code searchRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
-  public static SearchRequest copyOfSearchRequest(
-      final SearchRequest searchRequest)
+  public static SearchRequest copyOfSearchRequest(final SearchRequest request)
       throws NullPointerException
   {
-    return new SearchRequestImpl(searchRequest);
+    return new SearchRequestImpl(request);
   }
 
 
 
   /**
-   * Creates a new simple bind request that is an exact copy of the
-   * provided request.
+   * Creates a new simple bind request that is an exact copy of the provided
+   * request.
    *
-   * @param simpleBindRequest
+   * @param request
    *          The simple bind request to be copied.
    * @return The new simple bind request.
    * @throws NullPointerException
-   *           If {@code simpleBindRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static SimpleBindRequest copyOfSimpleBindRequest(
-      final SimpleBindRequest simpleBindRequest)
-      throws NullPointerException
+      final SimpleBindRequest request) throws NullPointerException
   {
-    return new SimpleBindRequestImpl(simpleBindRequest);
+    return new SimpleBindRequestImpl(request);
   }
 
 
@@ -1602,36 +1654,33 @@
    * Creates a new startTLS extended request that is an exact copy of the
    * provided request.
    *
-   * @param startTLSExtendedRequest
+   * @param request
    *          The startTLS extended request to be copied.
    * @return The new start TLS extended request.
    * @throws NullPointerException
-   *           If {@code startTLSExtendedRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
   public static StartTLSExtendedRequest copyOfStartTLSExtendedRequest(
-      final StartTLSExtendedRequest startTLSExtendedRequest)
-      throws NullPointerException
+      final StartTLSExtendedRequest request) throws NullPointerException
   {
-    return new StartTLSExtendedRequestImpl(startTLSExtendedRequest);
+    return new StartTLSExtendedRequestImpl(request);
   }
 
 
 
   /**
-   * Creates a new unbind request that is an exact copy of the provided
-   * request.
+   * Creates a new unbind request that is an exact copy of the provided request.
    *
-   * @param unbindRequest
+   * @param request
    *          The unbind request to be copied.
    * @return The new unbind request.
    * @throws NullPointerException
-   *           If {@code unbindRequest} was {@code null} .
+   *           If {@code request} was {@code null} .
    */
-  public static UnbindRequest copyOfUnbindRequest(
-      final UnbindRequest unbindRequest)
+  public static UnbindRequest copyOfUnbindRequest(final UnbindRequest request)
       throws NullPointerException
   {
-    return new UnbindRequestImpl(unbindRequest);
+    return new UnbindRequestImpl(request);
   }
 
 
@@ -1640,17 +1689,16 @@
    * Creates a new Who Am I extended request that is an exact copy of the
    * provided request.
    *
-   * @param whoAmIExtendedRequest
+   * @param request
    *          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} .
+   *           If {@code request} was {@code null} .
    */
   public static WhoAmIExtendedRequest copyOfWhoAmIExtendedRequest(
-      final WhoAmIExtendedRequest whoAmIExtendedRequest)
-      throws NullPointerException
+      final WhoAmIExtendedRequest request) throws NullPointerException
   {
-    return new WhoAmIExtendedRequestImpl(whoAmIExtendedRequest);
+    return new WhoAmIExtendedRequestImpl(request);
   }
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAddRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAddRequestImpl.java
index 5aac9d7..5e081d4 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAddRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableAddRequestImpl.java
@@ -98,14 +98,14 @@
   }
 
   public Iterable<Attribute> getAllAttributes() {
-    return Iterables.unmodifiable(Iterables.transform(impl
+    return Iterables.unmodifiableIterable(Iterables.transformedIterable(impl
         .getAllAttributes(), UNMODIFIABLE_ATTRIBUTE_FUNCTION));
   }
 
   public Iterable<Attribute> getAllAttributes(
       AttributeDescription attributeDescription)
       throws NullPointerException {
-    return Iterables.unmodifiable(Iterables.transform(impl
+    return Iterables.unmodifiableIterable(Iterables.transformedIterable(impl
         .getAllAttributes(attributeDescription),
         UNMODIFIABLE_ATTRIBUTE_FUNCTION));
   }
@@ -114,7 +114,7 @@
       String attributeDescription)
       throws LocalizedIllegalArgumentException,
       NullPointerException {
-    return Iterables.unmodifiable(Iterables.transform(impl
+    return Iterables.unmodifiableIterable(Iterables.transformedIterable(impl
         .getAllAttributes(attributeDescription),
         UNMODIFIABLE_ATTRIBUTE_FUNCTION));
   }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableModifyRequestImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableModifyRequestImpl.java
index 5b143d6..f871a40 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableModifyRequestImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/requests/UnmodifiableModifyRequestImpl.java
@@ -27,12 +27,13 @@
 
 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.*;
 import org.opends.sdk.ldif.ChangeRecordVisitor;
 
+import com.sun.opends.sdk.util.Collections2;
+import com.sun.opends.sdk.util.Function;
+import com.sun.opends.sdk.util.Functions;
+
 import java.util.Collections;
 import java.util.List;
 
@@ -64,8 +65,27 @@
     throw new UnsupportedOperationException();
   }
 
-  public List<Modification> getModifications() {
-    return Collections.unmodifiableList(impl.getModifications());
+  public List<Modification> getModifications()
+  {
+    // We need to make all attributes unmodifiable as well.
+    Function<Modification, Modification, Void> function =
+      new Function<Modification, Modification, Void>()
+    {
+
+      public Modification apply(Modification value, Void p)
+      {
+        ModificationType type = value.getModificationType();
+        Attribute attribute = Attributes.unmodifiableAttribute(value
+            .getAttribute());
+        return new Modification(type, attribute);
+      }
+
+    };
+
+    List<Modification> unmodifiableModifications = Collections2.transformedList(
+        impl.getModifications(), function,
+        Functions.<Modification> identityFunction());
+    return Collections.unmodifiableList(unmodifiableModifications);
   }
 
   public DN getName() {
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractExtendedResultImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractExtendedResult.java
similarity index 93%
rename from opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractExtendedResultImpl.java
rename to opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractExtendedResult.java
index e81944f..12e5cec 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractExtendedResultImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractExtendedResult.java
@@ -43,7 +43,7 @@
  * @param <S>
  *          The type of Extended result.
  */
-public abstract class AbstractExtendedResultImpl<S extends ExtendedResult>
+public abstract class AbstractExtendedResult<S extends ExtendedResult>
     extends AbstractResultImpl<S> implements ExtendedResult
 {
 
@@ -55,7 +55,7 @@
    * @throws NullPointerException
    *           If {@code resultCode} was {@code null}.
    */
-  protected AbstractExtendedResultImpl(final ResultCode resultCode)
+  protected AbstractExtendedResult(final ResultCode resultCode)
       throws NullPointerException
   {
     super(resultCode);
@@ -72,7 +72,7 @@
    * @throws NullPointerException
    *           If {@code extendedResult} was {@code null} .
    */
-  protected AbstractExtendedResultImpl(ExtendedResult extendedResult)
+  protected AbstractExtendedResult(ExtendedResult extendedResult)
       throws NullPointerException
   {
     super(extendedResult);
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractIntermediateResponseImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractIntermediateResponse.java
similarity index 93%
rename from opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractIntermediateResponseImpl.java
rename to opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractIntermediateResponse.java
index c7ef0d1..348d1ad 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractIntermediateResponseImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractIntermediateResponse.java
@@ -42,14 +42,14 @@
  * @param <S>
  *          The type of Intermediate response.
  */
-public abstract class AbstractIntermediateResponseImpl<S extends IntermediateResponse>
+public abstract class AbstractIntermediateResponse<S extends IntermediateResponse>
     extends AbstractResponseImpl<S> implements IntermediateResponse
 {
 
   /**
    * Creates a new intermediate response.
    */
-  protected AbstractIntermediateResponseImpl()
+  protected AbstractIntermediateResponse()
   {
     // Nothing to do.
   }
@@ -65,7 +65,7 @@
    * @throws NullPointerException
    *           If {@code intermediateResponse} was {@code null} .
    */
-  protected AbstractIntermediateResponseImpl(
+  protected AbstractIntermediateResponse(
       IntermediateResponse intermediateResponse)
       throws NullPointerException
   {
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractResponseImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractResponseImpl.java
index ebe2e5c..d5f0dff 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractResponseImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractResponseImpl.java
@@ -36,6 +36,7 @@
 import org.opends.sdk.DecodeOptions;
 import org.opends.sdk.controls.Control;
 import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.controls.GenericControl;
 
 import com.sun.opends.sdk.util.Validator;
 
@@ -74,7 +75,11 @@
   AbstractResponseImpl(Response response) throws NullPointerException
   {
     Validator.ensureNotNull(response);
-    controls.addAll(response.getControls());
+    for (Control control : response.getControls())
+    {
+      // Create defensive copy.
+      controls.add(GenericControl.newControl(control));
+    }
   }
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractUnmodifiableResponseImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractUnmodifiableResponseImpl.java
index 7d813b3..30d35b7 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractUnmodifiableResponseImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/responses/AbstractUnmodifiableResponseImpl.java
@@ -32,11 +32,16 @@
 import java.util.Collections;
 import java.util.List;
 
-import com.sun.opends.sdk.util.Validator;
 import org.opends.sdk.DecodeException;
 import org.opends.sdk.DecodeOptions;
 import org.opends.sdk.controls.Control;
 import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.controls.GenericControl;
+
+import com.sun.opends.sdk.util.Collections2;
+import com.sun.opends.sdk.util.Function;
+import com.sun.opends.sdk.util.Functions;
+import com.sun.opends.sdk.util.Validator;
 
 
 
@@ -71,6 +76,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public final S addControl(final Control control)
       throws UnsupportedOperationException, NullPointerException
   {
@@ -82,12 +88,49 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public final <C extends Control> C getControl(
       final ControlDecoder<C> decoder, final DecodeOptions options)
       throws NullPointerException, DecodeException
   {
-    // FIXME: ensure that controls are immutable.
-    return impl.getControl(decoder, options);
+    Validator.ensureNotNull(decoder, options);
+
+    final List<Control> controls = impl.getControls();
+
+    // Avoid creating an iterator if possible.
+    if (controls.isEmpty())
+    {
+      return null;
+    }
+
+    for (final Control control : controls)
+    {
+      if (control.getOID().equals(decoder.getOID()))
+      {
+        // Got a match. Return a defensive copy only if necessary.
+        final C decodedControl = decoder.decodeControl(control, options);
+
+        if (decodedControl != control)
+        {
+          // This was not the original control so return it immediately.
+          return decodedControl;
+        }
+        else if (decodedControl instanceof GenericControl)
+        {
+          // Generic controls are immutable, so return it immediately.
+          return decodedControl;
+        }
+        else
+        {
+          // Re-decode to get defensive copy.
+          final GenericControl genericControl = GenericControl
+              .newControl(control);
+          return decoder.decodeControl(genericControl, options);
+        }
+      }
+    }
+
+    return null;
   }
 
 
@@ -95,10 +138,26 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public final List<Control> getControls()
   {
-    // FIXME: ensure that controls are immutable.
-    return Collections.unmodifiableList(impl.getControls());
+    // We need to make all controls unmodifiable as well, which implies making
+    // defensive copies where necessary.
+    final Function<Control, Control, Void> function = new Function<Control, Control, Void>()
+    {
+
+      @Override
+      public Control apply(final Control value, final Void p)
+      {
+        // Return defensive copy.
+        return GenericControl.newControl(value);
+      }
+
+    };
+
+    final List<Control> unmodifiableControls = Collections2.transformedList(
+        impl.getControls(), function, Functions.<Control> identityFunction());
+    return Collections.unmodifiableList(unmodifiableControls);
   }
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/responses/GenericExtendedResultImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/responses/GenericExtendedResultImpl.java
index d747f32..c5633c3 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/responses/GenericExtendedResultImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/responses/GenericExtendedResultImpl.java
@@ -40,7 +40,7 @@
  * Generic extended result implementation.
  */
 final class GenericExtendedResultImpl extends
-    AbstractExtendedResultImpl<GenericExtendedResult> implements ExtendedResult,
+    AbstractExtendedResult<GenericExtendedResult> implements ExtendedResult,
     GenericExtendedResult
 {
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/responses/GenericIntermediateResponseImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/responses/GenericIntermediateResponseImpl.java
index aa5d20b..966d078 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/responses/GenericIntermediateResponseImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/responses/GenericIntermediateResponseImpl.java
@@ -39,7 +39,7 @@
  * Generic intermediate response implementation.
  */
 final class GenericIntermediateResponseImpl extends
-    AbstractIntermediateResponseImpl<GenericIntermediateResponse> implements
+    AbstractIntermediateResponse<GenericIntermediateResponse> implements
     GenericIntermediateResponse
 {
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/responses/PasswordModifyExtendedResultImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/responses/PasswordModifyExtendedResultImpl.java
index f7069cf..4c50a01 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/responses/PasswordModifyExtendedResultImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/responses/PasswordModifyExtendedResultImpl.java
@@ -43,7 +43,7 @@
  * Password modify extended result implementation.
  */
 final class PasswordModifyExtendedResultImpl extends
-    AbstractExtendedResultImpl<PasswordModifyExtendedResult> implements
+    AbstractExtendedResult<PasswordModifyExtendedResult> implements
     PasswordModifyExtendedResult
 {
   private ByteString password;
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/responses/Responses.java b/opendj-sdk/sdk/src/org/opends/sdk/responses/Responses.java
index bf4a15b..d7b48eb 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/responses/Responses.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/responses/Responses.java
@@ -38,17 +38,24 @@
 /**
  * This class contains various methods for creating and manipulating responses.
  * <p>
- * TODO: search reference from LDAP URL.
+ * All copy constructors of the form {@code copyOfXXXResult} perform deep copies
+ * of their response parameter. More specifically, any controls, modifications,
+ * and attributes contained within the response will be duplicated.
  * <p>
- * TODO: referral from LDAP URL.
- * <p>
- * TODO: synchronized requests?
- * <p>
- * TODO: copy constructors.
+ * Similarly, all unmodifiable views of responses returned by methods of the
+ * form {@code unmodifiableXXXResult} return deep unmodifiable views of their
+ * response parameter. More specifically, any controls, modifications, and
+ * attributes contained within the returned response will be unmodifiable.
  */
 public final class Responses
 {
 
+  // TODO: search reference from LDAP URL.
+
+  // TODO: referral from LDAP URL.
+
+  // TODO: synchronized requests?
+
   /**
    * Creates a new bind result using the provided result code.
    *
@@ -300,16 +307,20 @@
   /**
    * Creates an unmodifiable bind result using the provided response.
    *
-   * @param bindResult
+   * @param result
    *          The bind result to be copied.
    * @return The unmodifiable bind result.
    * @throws NullPointerException
-   *           If {@code bindResult} was {@code null}.
+   *           If {@code result} was {@code null}.
    */
-  public static BindResult unmodifiableBindResult(final BindResult bindResult)
+  public static BindResult unmodifiableBindResult(final BindResult result)
       throws NullPointerException
   {
-    return new UnmodifiableBindResultImpl(bindResult);
+    if (result instanceof UnmodifiableBindResultImpl)
+    {
+      return result;
+    }
+    return new UnmodifiableBindResultImpl(result);
   }
 
 
@@ -317,17 +328,20 @@
   /**
    * Creates an unmodifiable compare result using the provided response.
    *
-   * @param compareResult
+   * @param result
    *          The compare result to be copied.
    * @return The unmodifiable compare result.
    * @throws NullPointerException
-   *           If {@code compareResult} was {@code null}.
+   *           If {@code result} was {@code null}.
    */
   public static CompareResult unmodifiableCompareResult(
-      final CompareResult compareResult)
-      throws NullPointerException
+      final CompareResult result) throws NullPointerException
   {
-    return new UnmodifiableCompareResultImpl(compareResult);
+    if (result instanceof UnmodifiableCompareResultImpl)
+    {
+      return result;
+    }
+    return new UnmodifiableCompareResultImpl(result);
   }
 
 
@@ -336,17 +350,20 @@
    * Creates an unmodifiable generic extended result using the provided
    * response.
    *
-   * @param genericExtendedResult
+   * @param result
    *          The generic extended result to be copied.
    * @return The unmodifiable generic extended result.
    * @throws NullPointerException
-   *           If {@code genericExtendedResult} was {@code null}.
+   *           If {@code result} was {@code null}.
    */
   public static GenericExtendedResult unmodifiableGenericExtendedResult(
-      final GenericExtendedResult genericExtendedResult)
-      throws NullPointerException
+      final GenericExtendedResult result) throws NullPointerException
   {
-    return new UnmodifiableGenericExtendedResultImpl(genericExtendedResult);
+    if (result instanceof UnmodifiableGenericExtendedResultImpl)
+    {
+      return result;
+    }
+    return new UnmodifiableGenericExtendedResultImpl(result);
   }
 
 
@@ -355,19 +372,20 @@
    * Creates an unmodifiable generic intermediate response using the provided
    * response.
    *
-   * @param genericIntermediateResponse
+   * @param response
    *          The generic intermediate response to be copied.
    * @return The unmodifiable generic intermediate response.
    * @throws NullPointerException
-   *           If {@code genericIntermediateResponse} was {@code null}.
+   *           If {@code response} was {@code null}.
    */
-  public static GenericIntermediateResponse
-  unmodifiableGenericIntermediateResponse(
-      final GenericIntermediateResponse genericIntermediateResponse)
-      throws NullPointerException
+  public static GenericIntermediateResponse unmodifiableGenericIntermediateResponse(
+      final GenericIntermediateResponse response) throws NullPointerException
   {
-    return new UnmodifiableGenericIntermediateResponseImpl(
-        genericIntermediateResponse);
+    if (response instanceof UnmodifiableGenericIntermediateResponseImpl)
+    {
+      return response;
+    }
+    return new UnmodifiableGenericIntermediateResponseImpl(response);
   }
 
 
@@ -376,19 +394,20 @@
    * Creates an unmodifiable password modify extended result using the provided
    * response.
    *
-   * @param passwordModifyExtendedResult
+   * @param result
    *          The password modify extended result to be copied.
    * @return The unmodifiable password modify extended result.
    * @throws NullPointerException
-   *           If {@code passwordModifyExtendedResult} was {@code null}.
+   *           If {@code result} was {@code null}.
    */
-  public static PasswordModifyExtendedResult
-  unmodifiablePasswordModifyExtendedResult(
-      final PasswordModifyExtendedResult passwordModifyExtendedResult)
-      throws NullPointerException
+  public static PasswordModifyExtendedResult unmodifiablePasswordModifyExtendedResult(
+      final PasswordModifyExtendedResult result) throws NullPointerException
   {
-    return new UnmodifiablePasswordModifyExtendedResultImpl(
-        passwordModifyExtendedResult);
+    if (result instanceof UnmodifiablePasswordModifyExtendedResultImpl)
+    {
+      return result;
+    }
+    return new UnmodifiablePasswordModifyExtendedResultImpl(result);
   }
 
 
@@ -405,6 +424,10 @@
   public static Result unmodifiableResult(final Result result)
       throws NullPointerException
   {
+    if (result instanceof UnmodifiableResultImpl)
+    {
+      return result;
+    }
     return new UnmodifiableResultImpl(result);
   }
 
@@ -413,17 +436,20 @@
   /**
    * Creates an unmodifiable search result entry using the provided response.
    *
-   * @param searchResultEntry
+   * @param entry
    *          The search result entry to be copied.
    * @return The unmodifiable search result entry.
    * @throws NullPointerException
-   *           If {@code searchResultEntry} was {@code null}.
+   *           If {@code entry} was {@code null}.
    */
   public static SearchResultEntry unmodifiableSearchResultEntry(
-      final SearchResultEntry searchResultEntry)
-      throws NullPointerException
+      final SearchResultEntry entry) throws NullPointerException
   {
-    return new UnmodifiableSearchResultEntryImpl(searchResultEntry);
+    if (entry instanceof UnmodifiableSearchResultEntryImpl)
+    {
+      return entry;
+    }
+    return new UnmodifiableSearchResultEntryImpl(entry);
   }
 
 
@@ -432,17 +458,20 @@
    * Creates an unmodifiable search result reference using the provided
    * response.
    *
-   * @param searchResultReference
+   * @param reference
    *          The search result reference to be copied.
    * @return The unmodifiable search result reference.
    * @throws NullPointerException
    *           If {@code searchResultReference} was {@code null}.
    */
   public static SearchResultReference unmodifiableSearchResultReference(
-      final SearchResultReference searchResultReference)
-      throws NullPointerException
+      final SearchResultReference reference) throws NullPointerException
   {
-    return new UnmodifiableSearchResultReferenceImpl(searchResultReference);
+    if (reference instanceof UnmodifiableSearchResultReferenceImpl)
+    {
+      return reference;
+    }
+    return new UnmodifiableSearchResultReferenceImpl(reference);
   }
 
 
@@ -451,53 +480,54 @@
    * Creates an unmodifiable who am I extended result using the provided
    * response.
    *
-   * @param whoAmIExtendedResult
+   * @param result
    *          The who am I result to be copied.
    * @return The unmodifiable who am I extended result.
    * @throws NullPointerException
-   *           If {@code whoAmIExtendedResult} was {@code null} .
+   *           If {@code result} was {@code null} .
    */
   public static WhoAmIExtendedResult unmodifiableWhoAmIExtendedResult(
-      final WhoAmIExtendedResult whoAmIExtendedResult)
-      throws NullPointerException
+      final WhoAmIExtendedResult result) throws NullPointerException
   {
-    return new UnmodifiableWhoAmIExtendedResultImpl(whoAmIExtendedResult);
+    if (result instanceof UnmodifiableSearchResultReferenceImpl)
+    {
+      return result;
+    }
+    return new UnmodifiableWhoAmIExtendedResultImpl(result);
   }
 
 
 
   /**
-   * Creates a new bind result that is an exact copy of the provided
-   * result.
+   * Creates a new bind result that is an exact copy of the provided result.
    *
-   * @param bindResult
+   * @param result
    *          The bind result to be copied.
    * @return The new bind result.
    * @throws NullPointerException
-   *           If {@code bindResult} was {@code null}.
+   *           If {@code result} was {@code null}.
    */
-  public static BindResult copyOfBindResult(final BindResult bindResult)
+  public static BindResult copyOfBindResult(final BindResult result)
       throws NullPointerException
   {
-    return new BindResultImpl(bindResult);
+    return new BindResultImpl(result);
   }
 
 
+
   /**
-   * Creates a new compare result that is an exact copy of the provided
-   * result.
+   * Creates a new compare result that is an exact copy of the provided result.
    *
-   * @param compareResult
+   * @param result
    *          The compare result to be copied.
    * @return The new compare result.
    * @throws NullPointerException
-   *           If {@code compareResult} was {@code null}.
+   *           If {@code result} was {@code null}.
    */
-  public static CompareResult copyOfCompareResult(
-      final CompareResult compareResult)
+  public static CompareResult copyOfCompareResult(final CompareResult result)
       throws NullPointerException
   {
-    return new CompareResultImpl(compareResult);
+    return new CompareResultImpl(result);
   }
 
 
@@ -506,17 +536,16 @@
    * Creates a new generic extended result that is an exact copy of the provided
    * result.
    *
-   * @param genericExtendedResult
+   * @param result
    *          The generic extended result to be copied.
    * @return The new generic extended result.
    * @throws NullPointerException
-   *           If {@code genericExtendedResult} was {@code null}.
+   *           If {@code result} was {@code null}.
    */
   public static GenericExtendedResult copyOfGenericExtendedResult(
-      final GenericExtendedResult genericExtendedResult)
-      throws NullPointerException
+      final GenericExtendedResult result) throws NullPointerException
   {
-    return new GenericExtendedResultImpl(genericExtendedResult);
+    return new GenericExtendedResultImpl(result);
   }
 
 
@@ -525,18 +554,16 @@
    * Creates a new generic intermediate response that is an exact copy of the
    * provided response.
    *
-   * @param genericIntermediateResponse
+   * @param result
    *          The generic intermediate response to be copied.
    * @return The new generic intermediate response.
    * @throws NullPointerException
-   *           If {@code genericIntermediateResponse} was {@code null}.
+   *           If {@code result} was {@code null}.
    */
   public static GenericIntermediateResponse copyOfGenericIntermediateResponse(
-      final GenericIntermediateResponse genericIntermediateResponse)
-      throws NullPointerException
+      final GenericIntermediateResponse result) throws NullPointerException
   {
-    return new GenericIntermediateResponseImpl(
-        genericIntermediateResponse);
+    return new GenericIntermediateResponseImpl(result);
   }
 
 
@@ -545,18 +572,16 @@
    * Creates a new password modify extended result that is an exact copy of the
    * provided result.
    *
-   * @param passwordModifyExtendedResult
+   * @param result
    *          The password modify extended result to be copied.
    * @return The new password modify extended result.
    * @throws NullPointerException
-   *           If {@code passwordModifyExtendedResult} was {@code null}.
+   *           If {@code result} was {@code null}.
    */
   public static PasswordModifyExtendedResult copyOfPasswordModifyExtendedResult(
-      final PasswordModifyExtendedResult passwordModifyExtendedResult)
-      throws NullPointerException
+      final PasswordModifyExtendedResult result) throws NullPointerException
   {
-    return new PasswordModifyExtendedResultImpl(
-        passwordModifyExtendedResult);
+    return new PasswordModifyExtendedResultImpl(result);
   }
 
 
@@ -582,17 +607,16 @@
    * Creates a new search result entry that is an exact copy of the provided
    * result.
    *
-   * @param searchResultEntry
+   * @param entry
    *          The search result entry to be copied.
    * @return The new search result entry.
    * @throws NullPointerException
-   *           If {@code searchResultEntry} was {@code null}.
+   *           If {@code entry} was {@code null}.
    */
   public static SearchResultEntry copyOfSearchResultEntry(
-      final SearchResultEntry searchResultEntry)
-      throws NullPointerException
+      final SearchResultEntry entry) throws NullPointerException
   {
-    return new SearchResultEntryImpl(searchResultEntry);
+    return new SearchResultEntryImpl(entry);
   }
 
 
@@ -601,17 +625,16 @@
    * Creates a new search result reference that is an exact copy of the provided
    * result.
    *
-   * @param searchResultReference
+   * @param reference
    *          The search result reference to be copied.
    * @return The new search result reference.
    * @throws NullPointerException
-   *           If {@code searchResultReference} was {@code null}.
+   *           If {@code reference} was {@code null}.
    */
   public static SearchResultReference copyOfSearchResultReference(
-      final SearchResultReference searchResultReference)
-      throws NullPointerException
+      final SearchResultReference reference) throws NullPointerException
   {
-    return new SearchResultReferenceImpl(searchResultReference);
+    return new SearchResultReferenceImpl(reference);
   }
 
 
@@ -620,17 +643,16 @@
    * Creates a new who am I extended result that is an exact copy of the
    * provided result.
    *
-   * @param whoAmIExtendedResult
+   * @param result
    *          The who am I result to be copied.
    * @return The new who am I extended result.
    * @throws NullPointerException
-   *           If {@code whoAmIExtendedResult} was {@code null} .
+   *           If {@code result} was {@code null} .
    */
   public static WhoAmIExtendedResult copyOfWhoAmIExtendedResult(
-      final WhoAmIExtendedResult whoAmIExtendedResult)
-      throws NullPointerException
+      final WhoAmIExtendedResult result) throws NullPointerException
   {
-    return new WhoAmIExtendedResultImpl(whoAmIExtendedResult);
+    return new WhoAmIExtendedResultImpl(result);
   }
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/responses/SearchResultEntryImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/responses/SearchResultEntryImpl.java
index 5aeb20c..77c03dc 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/responses/SearchResultEntryImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/responses/SearchResultEntryImpl.java
@@ -78,7 +78,7 @@
       throws NullPointerException
   {
     super(searchResultEntry);
-    this.entry = new LinkedHashMapEntry(searchResultEntry);
+    this.entry = LinkedHashMapEntry.deepCopyOfEntry(searchResultEntry);
   }
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/responses/UnmodifiableSearchResultEntryImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/responses/UnmodifiableSearchResultEntryImpl.java
index db7dae9..ee50662 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/responses/UnmodifiableSearchResultEntryImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/responses/UnmodifiableSearchResultEntryImpl.java
@@ -93,14 +93,14 @@
   }
 
   public Iterable<Attribute> getAllAttributes() {
-    return Iterables.unmodifiable(Iterables.transform(impl
+    return Iterables.unmodifiableIterable(Iterables.transformedIterable(impl
         .getAllAttributes(), UNMODIFIABLE_ATTRIBUTE_FUNCTION));
   }
 
   public Iterable<Attribute> getAllAttributes(
       AttributeDescription attributeDescription)
       throws NullPointerException {
-    return Iterables.unmodifiable(Iterables.transform(impl
+    return Iterables.unmodifiableIterable(Iterables.transformedIterable(impl
         .getAllAttributes(attributeDescription),
         UNMODIFIABLE_ATTRIBUTE_FUNCTION));
   }
@@ -109,7 +109,7 @@
       String attributeDescription)
       throws LocalizedIllegalArgumentException,
       NullPointerException {
-    return Iterables.unmodifiable(Iterables.transform(impl
+    return Iterables.unmodifiableIterable(Iterables.transformedIterable(impl
         .getAllAttributes(attributeDescription),
         UNMODIFIABLE_ATTRIBUTE_FUNCTION));
   }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/responses/WhoAmIExtendedResultImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/responses/WhoAmIExtendedResultImpl.java
index 5f30316..577ab11 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/responses/WhoAmIExtendedResultImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/responses/WhoAmIExtendedResultImpl.java
@@ -42,7 +42,7 @@
  * Who Am I extended result implementation.
  */
 final class WhoAmIExtendedResultImpl extends
-    AbstractExtendedResultImpl<WhoAmIExtendedResult> implements
+    AbstractExtendedResult<WhoAmIExtendedResult> implements
     WhoAmIExtendedResult
 {
 

--
Gitblit v1.10.0