From 990307fb4882528986169d7b58f554f35521a030 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Fri, 11 Dec 2009 18:45:45 +0000
Subject: [PATCH] Various incremental improvements.

---
 opendj-sdk/sdk/src/org/opends/sdk/EntryNotFoundException.java                                     |   15 
 opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/AttributeDescriptionTest.java           |    3 
 opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/EnumSyntaxTestCase.java          |    3 
 opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPUtils.java                                             |   35 
 opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRuleImpl.java                                    |    2 
 opendj-sdk/sdk/src/org/opends/sdk/controls/MatchedValuesControl.java                              |    8 
 opendj-sdk/sdk/src/org/opends/sdk/schema/Schema.java                                              |  434 +++
 opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/MatchingRuleTest.java            |    3 
 opendj-sdk/sdk/src/org/opends/sdk/SynchronousConnection.java                                      |   23 
 opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/OrderingMatchingRuleTest.java    |    3 
 opendj-sdk/sdk/src/org/opends/sdk/schema/GenerateCoreSchema.java                                  |   10 
 opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/ApproximateMatchingRuleTest.java |    3 
 opendj-sdk/sdk/src/org/opends/sdk/MultipleEntriesFoundException.java                              |   11 
 opendj-sdk/sdk/src/org/opends/sdk/Connection.java                                                 |  570 +++-
 opendj-sdk/sdk/src/com/sun/opends/sdk/util/Collections2.java                                      |  225 ++
 opendj-sdk/sdk/src/org/opends/sdk/HeartBeatConnectionFactory.java                                 |  448 +++-
 opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractMatchingRuleImpl.java                            |    2 
 opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/SubstringMatchingRuleTest.java   |    5 
 opendj-sdk/sdk/src/org/opends/sdk/FilterVisitor.java                                              |   16 
 opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/SyntaxTestCase.java              |    3 
 opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRule.java                                        |    2 
 opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaBuilder.java                                       |  452 ++--
 opendj-sdk/sdk/src/org/opends/sdk/ResultFuture.java                                               |   41 
 opendj-sdk/sdk/tests/unit-tests-testng/src/com/sun/opends/sdk/util/StaticUtilsTest.java           |    2 
 opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractSubstringMatchingRuleImpl.java                   |    2 
 opendj-sdk/sdk/src/org/opends/sdk/Filter.java                                                     |  293 ++
 opendj-sdk/sdk/src/org/opends/sdk/ErrorResultException.java                                       |   28 
 opendj-sdk/sdk/src/org/opends/sdk/Matcher.java                                                    |  307 +-
 opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java                                    |   13 
 opendj-sdk/sdk/src/org/opends/sdk/AuthenticatedConnectionFactory.java                             |   74 
 opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchemaImpl.java                                      |   60 
 opendj-sdk/sdk/src/org/opends/sdk/AsynchronousConnection.java                                     |  271 ++
 opendj-sdk/sdk/src/org/opends/sdk/CancelledResultException.java                                   |   13 
 opendj-sdk/sdk/src/org/opends/sdk/schema/AttributeType.java                                       |   25 
 opendj-sdk/sdk/src/org/opends/sdk/TimeoutResultException.java                                     |    4 
 opendj-sdk/sdk/src/org/opends/sdk/ResultCode.java                                                 |   31 
 opendj-sdk/sdk/src/org/opends/sdk/AbstractConnection.java                                         |  245 +
 opendj-sdk/sdk/src/org/opends/sdk/ResultHandler.java                                              |   14 
 opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/LinkedAttributeTest.java                |    3 
 opendj-sdk/sdk/src/org/opends/sdk/AbstractFilterVisitor.java                                      |   16 
 /dev/null                                                                                         |   94 
 opendj-sdk/sdk/src/com/sun/opends/sdk/util/ResultChain.java                                       |  315 +++
 opendj-sdk/sdk/src/com/sun/opends/sdk/util/ResultTransformer.java                                 |  202 +
 opendj-sdk/sdk/src/org/opends/sdk/AbstractAsynchronousConnection.java                             |  315 +++
 opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java                                                    |  692 +++---
 opendj-sdk/sdk/src/com/sun/opends/sdk/util/Functions.java                                         |  177 
 opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchema.java                                          |    2 
 opendj-sdk/sdk/src/com/sun/opends/sdk/messages/messages.properties                                |    4 
 opendj-sdk/sdk/src/org/opends/sdk/ConnectionPool.java                                             |  551 ++++-
 49 files changed, 4,303 insertions(+), 1,767 deletions(-)

diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java
index 12437e4..d3e7233 100644
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java
@@ -69,7 +69,8 @@
  * <p>
  * TODO: handle illegal state exceptions.
  */
-public final class LDAPConnection implements AsynchronousConnection
+public final class LDAPConnection extends
+    AbstractAsynchronousConnection implements AsynchronousConnection
 {
 
   private final class LDAPMessageHandlerImpl extends
@@ -919,16 +920,6 @@
   }
 
 
-
-  /**
-   * {@inheritDoc}
-   */
-  public void close()
-  {
-    close(Requests.newUnbindRequest(), null);
-  }
-
-
   /**
    * {@inheritDoc}
    */
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/messages/messages.properties b/opendj-sdk/sdk/src/com/sun/opends/sdk/messages/messages.properties
index 41e3c13..c968558 100755
--- a/opendj-sdk/sdk/src/com/sun/opends/sdk/messages/messages.properties
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/messages/messages.properties
@@ -1240,7 +1240,7 @@
 INFO_RESULT_CLIENT_SIDE_NOT_SUPPORTED=Operation Not Supported
 INFO_RESULT_CLIENT_SIDE_CONTROL_NOT_FOUND=Control Not Found
 INFO_RESULT_CLIENT_SIDE_NO_RESULTS_RETURNED=No Results Returned
-INFO_RESULT_CLIENT_SIDE_MORE_RESULTS_TO_RETURN=More Results to Return
+INFO_RESULT_CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED=Unexpected Results Returned
 INFO_RESULT_CLIENT_SIDE_CLIENT_LOOP=Referral Loop Detected
 INFO_RESULT_CLIENT_SIDE_REFERRAL_LIMIT_EXCEEDED=Referral Hop Limit Exceeded
 INFO_RESULT_AUTHORIZATION_DENIED=Authorization Denied
@@ -2644,6 +2644,8 @@
  decode the control value:  %s
 MILD_ERR_ASN1_SEQUENCE_WRITE_NOT_STARTED=Cannot encode the end of the ASN.1 \
  sequence or set because the start of the sequence was not written
+MILD_ERR_NO_SEARCH_RESULT_ENTRIES=The search request succeeded \
+ but did not return any search result entries when one was expected
 MILD_ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES=The search request succeeded \
  but returned %d search result entry when only one was expected
 MILD_ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES=The search request succeeded \
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
new file mode 100644
index 0000000..847aa4e
--- /dev/null
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/Collections2.java
@@ -0,0 +1,225 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Iterator;
+
+
+
+/**
+ * Additional {@code Collection} based utility methods.
+ */
+public final class Collections2
+{
+  private static final class TransformedCollection<M, N, P> extends
+      AbstractCollection<N> implements Collection<N>
+  {
+
+    private final Collection<M> collection;
+
+    private final Function<? super M, ? extends N, P> funcMtoN;
+
+    private final Function<? super N, ? extends M, P> funcNtoM;
+
+    private final P p;
+
+
+
+    private TransformedCollection(Collection<M> collection,
+        Function<? super M, ? extends N, P> funcMtoN,
+        Function<? super N, ? extends M, P> funcNtoM, P p)
+    {
+      this.collection = collection;
+      this.funcMtoN = funcMtoN;
+      this.funcNtoM = funcNtoM;
+      this.p = p;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean add(N e)
+    {
+      return collection.add(funcNtoM.apply(e, p));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear()
+    {
+      collection.clear();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    public boolean contains(Object o)
+    {
+      N tmp = (N) o;
+      return collection.contains(funcNtoM.apply(tmp, p));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEmpty()
+    {
+      return collection.isEmpty();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<N> iterator()
+    {
+      return Iterators.transform(collection.iterator(), funcMtoN, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    public boolean remove(Object o)
+    {
+      N tmp = (N) o;
+      return collection.remove(funcNtoM.apply(tmp, p));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+      return collection.size();
+    }
+
+  }
+
+
+
+  /**
+   * Returns a view of {@code collection} whose values have been mapped
+   * to elements of type {@code N} using {@code funcMtoN}. The returned
+   * collection supports all operations.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code collection}.
+   * @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.
+   * @param collection
+   *          The collection 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 collection}.
+   * @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 collection}
+   *          .
+   * @param p
+   *          A predicate specified parameter.
+   * @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(
+      Collection<M> collection,
+      Function<? super M, ? extends N, P> funcMtoN,
+      Function<? super N, ? extends M, P> funcNtoM, P p)
+  {
+    return new TransformedCollection<M, N, P>(collection, 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 supports all operations.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code collection}.
+   * @param <N>
+   *          The type of elements contained in the returned collection.
+   * @param collection
+   *          The collection 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 collection}.
+   * @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 collection}
+   *          .
+   * @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(
+      Collection<M> collection,
+      Function<? super M, ? extends N, Void> funcMtoN,
+      Function<? super N, ? extends M, Void> funcNtoM)
+  {
+    return new TransformedCollection<M, N, Void>(collection, funcMtoN,
+        funcNtoM, null);
+  }
+
+
+
+  // Prevent instantiation
+  private Collections2()
+  {
+    // Do nothing.
+  }
+
+}
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 716f081..3353564 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
@@ -46,6 +46,7 @@
       Function<M, N, Void>
   {
     private final Function<M, N, P> function;
+
     private final P parameter;
 
 
@@ -68,99 +69,101 @@
 
   }
 
-  private static final Function<ByteString, AttributeDescription, Schema> BYTESTRING_TO_ATTRIBUTE_DESCRIPTION =
-      new Function<ByteString, AttributeDescription, Schema>()
+
+
+  private static final Function<ByteString, AttributeDescription, Schema> BYTESTRING_TO_ATTRIBUTE_DESCRIPTION = new Function<ByteString, AttributeDescription, Schema>()
+  {
+
+    public AttributeDescription apply(ByteString value, Schema p)
+    {
+      // FIXME: what should we do if parsing fails?
+      return AttributeDescription.valueOf(value.toString(), p);
+    }
+  };
+
+  private static final Function<ByteString, Boolean, Void> BYTESTRING_TO_BOOLEAN = new Function<ByteString, Boolean, Void>()
+  {
+
+    public Boolean apply(ByteString value, Void p)
+    {
+      String valueString = StaticUtils.toLowerCase(value.toString());
+
+      if (valueString.equals("true") || valueString.equals("yes")
+          || valueString.equals("on") || valueString.equals("1"))
       {
-
-        public AttributeDescription apply(ByteString value, Schema p)
-        {
-          // FIXME: what should we do if parsing fails?
-          return AttributeDescription.valueOf(value.toString(), p);
-        }
-      };
-
-  private static final Function<ByteString, Boolean, Void> BYTESTRING_TO_BOOLEAN =
-      new Function<ByteString, Boolean, Void>()
+        return Boolean.TRUE;
+      }
+      else if (valueString.equals("false") || valueString.equals("no")
+          || valueString.equals("off") || valueString.equals("0"))
       {
-
-        public Boolean apply(ByteString value, Void p)
-        {
-          String valueString =
-              StaticUtils.toLowerCase(value.toString());
-
-          if (valueString.equals("true") || valueString.equals("yes")
-              || valueString.equals("on") || valueString.equals("1"))
-          {
-            return Boolean.TRUE;
-          }
-          else if (valueString.equals("false")
-              || valueString.equals("no") || valueString.equals("off")
-              || valueString.equals("0"))
-          {
-            return Boolean.FALSE;
-          }
-          else
-          {
-            throw new NumberFormatException("Invalid boolean value \""
-                + valueString + "\"");
-          }
-        }
-      };
-
-  private static final Function<ByteString, DN, Schema> BYTESTRING_TO_DN =
-      new Function<ByteString, DN, Schema>()
+        return Boolean.FALSE;
+      }
+      else
       {
+        throw new NumberFormatException("Invalid boolean value \""
+            + valueString + "\"");
+      }
+    }
+  };
 
-        public DN apply(ByteString value, Schema p)
-        {
-          // FIXME: what should we do if parsing fails?
+  private static final Function<ByteString, DN, Schema> BYTESTRING_TO_DN = new Function<ByteString, DN, Schema>()
+  {
 
-          // FIXME: we should have a ByteString valueOf implementation.
-          return DN.valueOf(value.toString(), p);
-        }
-      };
+    public DN apply(ByteString value, Schema p)
+    {
+      // FIXME: what should we do if parsing fails?
 
-  private static final Function<ByteString, Integer, Void> BYTESTRING_TO_INTEGER =
-      new Function<ByteString, Integer, Void>()
-      {
+      // FIXME: we should have a ByteString valueOf implementation.
+      return DN.valueOf(value.toString(), p);
+    }
+  };
 
-        public Integer apply(ByteString value, Void p)
-        {
-          // We do not use ByteString.toInt() as we are string based.
-          return Integer.valueOf(value.toString());
-        }
-      };
+  private static final Function<ByteString, Integer, Void> BYTESTRING_TO_INTEGER = new Function<ByteString, Integer, Void>()
+  {
 
-  private static final Function<ByteString, Long, Void> BYTESTRING_TO_LONG =
-      new Function<ByteString, Long, Void>()
-      {
+    public Integer apply(ByteString value, Void p)
+    {
+      // We do not use ByteString.toInt() as we are string based.
+      return Integer.valueOf(value.toString());
+    }
+  };
 
-        public Long apply(ByteString value, Void p)
-        {
-          // We do not use ByteString.toLong() as we are string based.
-          return Long.valueOf(value.toString());
-        }
-      };
+  private static final Function<ByteString, Long, Void> BYTESTRING_TO_LONG = new Function<ByteString, Long, Void>()
+  {
 
-  private static final Function<ByteString, String, Void> BYTESTRING_TO_STRING =
-      new Function<ByteString, String, Void>()
-      {
+    public Long apply(ByteString value, Void p)
+    {
+      // We do not use ByteString.toLong() as we are string based.
+      return Long.valueOf(value.toString());
+    }
+  };
 
-        public String apply(ByteString value, Void p)
-        {
-          return value.toString();
-        }
-      };
+  private static final Function<ByteString, String, Void> BYTESTRING_TO_STRING = new Function<ByteString, String, Void>()
+  {
 
-  private static final Function<String, String, Void> NORMALIZE_STRING =
-      new Function<String, String, Void>()
-      {
+    public String apply(ByteString value, Void p)
+    {
+      return value.toString();
+    }
+  };
 
-        public String apply(String value, Void p)
-        {
-          return StaticUtils.toLowerCase(value).trim();
-        }
-      };
+  private static final Function<Object, ByteString, Void> OBJECT_TO_BYTESTRING = new Function<Object, ByteString, Void>()
+  {
+
+    public ByteString apply(Object value, Void p)
+    {
+      return ByteString.valueOf(value);
+    }
+  };
+
+  private static final Function<String, String, Void> NORMALIZE_STRING = new Function<String, String, Void>()
+  {
+
+    public String apply(String value, Void p)
+    {
+      return StaticUtils.toLowerCase(value).trim();
+    }
+  };
 
 
 
@@ -337,6 +340,20 @@
 
 
 
+  /**
+   * Returns a function which converts an {@code Object} to a {@code
+   * ByteString} using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @return A function which converts an {@code Object} to a {@code
+   *         ByteString}.
+   */
+  public static Function<Object, ByteString, Void> objectToByteString()
+  {
+    return OBJECT_TO_BYTESTRING;
+  }
+
+
+
   // Prevent instantiation
   private Functions()
   {
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/util/ResultChain.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/ResultChain.java
new file mode 100644
index 0000000..b8642d2
--- /dev/null
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/ResultChain.java
@@ -0,0 +1,315 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.ResultFuture;
+import org.opends.sdk.ResultHandler;
+
+
+
+/**
+ * A base class which can be used to transform the result of an inner
+ * asynchronous request to another result type.
+ * <p>
+ * FIXME: I don't think that this is right. There's too much locking for
+ * a start.
+ *
+ * @param <M>
+ *          The type of the inner result.
+ * @param <N>
+ *          The type of the outer result.
+ * @param <P>
+ *          The type of the additional parameter to the handler's
+ *          methods.
+ */
+public abstract class ResultChain<M, N, P> implements ResultFuture<N>,
+    ResultHandler<M, P>
+{
+
+  private ErrorResultException errorResult;
+
+  private final ResultHandler<? super N, P> handler;
+
+  private final Object stateLock = new Object();
+
+  private final CountDownLatch latch = new CountDownLatch(1);
+
+  private ResultFuture<N> outerFuture = null;
+
+  private boolean cancelled = false;
+
+  private volatile ResultFuture<M> innerFuture = null;
+
+
+
+  /**
+   * Creates a new asynchronous result chain which will chain an outer
+   * asynchronous request once the inner asynchronous request completes.
+   *
+   * @param handler
+   *          The outer result handler.
+   */
+  protected ResultChain(ResultHandler<? super N, P> handler)
+  {
+    this.handler = handler;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean cancel(boolean mayInterruptIfRunning)
+  {
+    synchronized (stateLock)
+    {
+      if (!isDone())
+      {
+        cancelled = true;
+        innerFuture.cancel(mayInterruptIfRunning);
+        if (outerFuture != null)
+        {
+          outerFuture.cancel(mayInterruptIfRunning);
+        }
+        latch.countDown();
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public N get() throws ErrorResultException, CancellationException,
+      InterruptedException
+  {
+    latch.await();
+    return get0();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public N get(long timeout, TimeUnit unit)
+      throws ErrorResultException, TimeoutException,
+      CancellationException, InterruptedException
+  {
+    if (!latch.await(timeout, unit))
+    {
+      throw new TimeoutException();
+    }
+    return get0();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int getMessageID()
+  {
+    // Best effort.
+    synchronized (stateLock)
+    {
+      if (outerFuture != null)
+      {
+        return outerFuture.getMessageID();
+      }
+      else
+      {
+        return innerFuture.getMessageID();
+      }
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void handleErrorResult(P p, ErrorResultException error)
+  {
+    synchronized (stateLock)
+    {
+      try
+      {
+        outerFuture = chainErrorResult(error, handler);
+      }
+      catch (ErrorResultException e)
+      {
+        errorResult = e;
+        if (handler != null)
+        {
+          handler.handleErrorResult(p, errorResult);
+        }
+        latch.countDown();
+      }
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void handleResult(P p, M result)
+  {
+    synchronized (stateLock)
+    {
+      try
+      {
+        outerFuture = chainResult(result, handler);
+      }
+      catch (ErrorResultException e)
+      {
+        errorResult = e;
+        if (handler != null)
+        {
+          handler.handleErrorResult(p, errorResult);
+        }
+        latch.countDown();
+      }
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCancelled()
+  {
+    return isDone() && cancelled;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isDone()
+  {
+    return latch.getCount() == 0;
+  }
+
+
+
+  /**
+   * Sets the inner future for this result chain. This must be done
+   * before this future is published.
+   *
+   * @param future
+   *          The inner future.
+   */
+  public final void setInnerResultFuture(ResultFuture<M> future)
+  {
+    innerFuture = future;
+  }
+
+
+
+  private N get0() throws ErrorResultException, CancellationException,
+      InterruptedException
+  {
+    synchronized (stateLock)
+    {
+      if (cancelled)
+      {
+        throw new CancellationException();
+      }
+
+      if (errorResult != null)
+      {
+        throw errorResult;
+      }
+
+      return outerFuture.get();
+    }
+  }
+
+
+
+  /**
+   * Invokes the outer request based on the error result of the inner
+   * request and returns a future representing the result of the outer
+   * request.
+   * <p>
+   * The default implementation is to terminate further processing by
+   * re-throwing the inner error result.
+   *
+   * @param innerError
+   *          The error result of the inner request.
+   * @param handler
+   *          The result handler to be used for the outer request.
+   * @return A future representing the result of the outer request.
+   * @throws ErrorResultException
+   *           If the outer request could not be invoked and processing
+   *           should terminate.
+   */
+  protected ResultFuture<N> chainErrorResult(
+      ErrorResultException innerError,
+      ResultHandler<? super N, P> handler) throws ErrorResultException
+  {
+    throw innerError;
+  }
+
+
+
+  /**
+   * Invokes the outer request based on the result of the inner request
+   * and returns a future representing the result of the outer request.
+   *
+   * @param innerResult
+   *          The result of the inner request.
+   * @param handler
+   *          The result handler to be used for the outer request.
+   * @return A future representing the result of the outer request.
+   * @throws ErrorResultException
+   *           If the outer request could not be invoked and processing
+   *           should terminate.
+   */
+  protected abstract ResultFuture<N> chainResult(M innerResult,
+      ResultHandler<? super N, P> handler) throws ErrorResultException;
+
+}
diff --git a/opendj-sdk/sdk/src/com/sun/opends/sdk/util/ResultTransformer.java b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/ResultTransformer.java
new file mode 100644
index 0000000..d879c2f
--- /dev/null
+++ b/opendj-sdk/sdk/src/com/sun/opends/sdk/util/ResultTransformer.java
@@ -0,0 +1,202 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.ResultFuture;
+import org.opends.sdk.ResultHandler;
+
+
+
+/**
+ * A base class which can be used to transform the result of an inner
+ * asynchronous request to another result type.
+ *
+ * @param <M>
+ *          The type of the inner result.
+ * @param <N>
+ *          The type of the outer result.
+ * @param <P>
+ *          The type of the additional parameter to the handler's
+ *          methods.
+ */
+public abstract class ResultTransformer<M, N, P> implements
+    ResultFuture<N>, ResultHandler<M, P>
+{
+
+  private final ResultHandler<? super N, P> handler;
+
+  private volatile ResultFuture<M> future = null;
+
+
+
+  /**
+   * Sets the inner future for this result transformer. This must be
+   * done before this future is published.
+   *
+   * @param future
+   *          The inner future.
+   */
+  public final void setResultFuture(ResultFuture<M> future)
+  {
+    this.future = future;
+  }
+
+
+
+  /**
+   * Transforms the inner result to an outer result, possibly throwing
+   * an {@code ErrorResultException} if the transformation fails for
+   * some reason.
+   *
+   * @param result
+   *          The inner result.
+   * @return The outer result.
+   * @throws ErrorResultException
+   *           If the transformation fails for some reason.
+   */
+  protected abstract N transformResult(M result)
+      throws ErrorResultException;
+
+
+
+  /**
+   * Creates a new result transformer which will transform the results
+   * of an inner asynchronous request.
+   *
+   * @param handler
+   *          The outer result handler.
+   */
+  protected ResultTransformer(ResultHandler<? super N, P> handler)
+  {
+    this.handler = handler;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final void handleErrorResult(P p, ErrorResultException error)
+  {
+    if (handler != null)
+    {
+      handler.handleErrorResult(p, error);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final void handleResult(P p, M result)
+  {
+    if (handler != null)
+    {
+      try
+      {
+        handler.handleResult(p, transformResult(result));
+      }
+      catch (ErrorResultException e)
+      {
+        handler.handleErrorResult(p, e);
+      }
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean cancel(boolean mayInterruptIfRunning)
+  {
+    return future.cancel(mayInterruptIfRunning);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final N get() throws ErrorResultException,
+      CancellationException, InterruptedException
+  {
+    return transformResult(future.get());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final N get(long timeout, TimeUnit unit)
+      throws ErrorResultException, TimeoutException,
+      CancellationException, InterruptedException
+  {
+    return transformResult(future.get(timeout, unit));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final int getMessageID()
+  {
+    return future.getMessageID();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean isCancelled()
+  {
+    return future.isCancelled();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean isDone()
+  {
+    return future.isDone();
+  }
+
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/AbstractAsynchronousConnection.java b/opendj-sdk/sdk/src/org/opends/sdk/AbstractAsynchronousConnection.java
new file mode 100644
index 0000000..58a6f89
--- /dev/null
+++ b/opendj-sdk/sdk/src/org/opends/sdk/AbstractAsynchronousConnection.java
@@ -0,0 +1,315 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+
+import java.util.Collection;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.SearchRequest;
+import org.opends.sdk.responses.Responses;
+import org.opends.sdk.responses.Result;
+import org.opends.sdk.responses.SearchResultEntry;
+import org.opends.sdk.responses.SearchResultReference;
+import org.opends.sdk.schema.Schema;
+
+
+
+/**
+ * This class provides a skeletal implementation of the {@code
+ * AsynchronousConnection} interface, to minimize the effort required to
+ * implement this interface.
+ */
+public abstract class AbstractAsynchronousConnection implements
+    AsynchronousConnection
+{
+
+  private static final class SingleEntryFuture<P> implements
+      ResultFuture<SearchResultEntry>, ResultHandler<Result, P>,
+      SearchResultHandler<P>
+  {
+    private final ResultHandler<? super SearchResultEntry, P> handler;
+
+    private volatile SearchResultEntry firstEntry = null;
+
+    private volatile SearchResultReference firstReference = null;
+
+    private volatile int entryCount = 0;
+
+    private volatile ResultFuture<Result> future = null;
+
+
+
+    private SingleEntryFuture(
+        ResultHandler<? super SearchResultEntry, P> handler)
+    {
+      this.handler = handler;
+    }
+
+
+
+    public boolean cancel(boolean mayInterruptIfRunning)
+    {
+      return future.cancel(mayInterruptIfRunning);
+    }
+
+
+
+    public SearchResultEntry get() throws ErrorResultException,
+        CancellationException, InterruptedException
+    {
+      future.get();
+      return get0();
+    }
+
+
+
+    public SearchResultEntry get(long timeout, TimeUnit unit)
+        throws ErrorResultException, TimeoutException,
+        CancellationException, InterruptedException
+    {
+      future.get(timeout, unit);
+      return get0();
+    }
+
+
+
+    private SearchResultEntry get0() throws ErrorResultException
+    {
+      if (entryCount == 0)
+      {
+        // Did not find any entries.
+        Result result = Responses.newResult(
+            ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED)
+            .setDiagnosticMessage(
+                ERR_NO_SEARCH_RESULT_ENTRIES.get().toString());
+        throw ErrorResultException.wrap(result);
+      }
+      else if (entryCount > 1)
+      {
+        // Got more entries than expected.
+        Result result = Responses.newResult(
+            ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED)
+            .setDiagnosticMessage(
+                ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(entryCount)
+                    .toString());
+        throw ErrorResultException.wrap(result);
+      }
+      else if (firstReference != null)
+      {
+        // Got an unexpected search result reference.
+        Result result = Responses.newResult(
+            ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED)
+            .setDiagnosticMessage(
+                ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get(
+                    firstReference.getURIs().iterator().next())
+                    .toString());
+        throw ErrorResultException.wrap(result);
+      }
+      else
+      {
+        return firstEntry;
+      }
+    }
+
+
+
+    public int getMessageID()
+    {
+      return future.getMessageID();
+    }
+
+
+
+    public void handleEntry(P p, SearchResultEntry entry)
+    {
+      if (firstEntry == null)
+      {
+        firstEntry = entry;
+      }
+      entryCount++;
+    }
+
+
+
+    public void handleErrorResult(P p, ErrorResultException error)
+    {
+      if (handler != null)
+      {
+        handler.handleErrorResult(p, error);
+      }
+    }
+
+
+
+    public void handleReference(P p, SearchResultReference reference)
+    {
+      if (firstReference == null)
+      {
+        firstReference = reference;
+      }
+    }
+
+
+
+    public void handleResult(P p, Result result)
+    {
+      if (handler != null)
+      {
+        try
+        {
+          handler.handleResult(p, get0());
+        }
+        catch (ErrorResultException e)
+        {
+          handler.handleErrorResult(p, e);
+        }
+      }
+    }
+
+
+
+    public boolean isCancelled()
+    {
+      return future.isCancelled();
+    }
+
+
+
+    public boolean isDone()
+    {
+      return future.isDone();
+    }
+
+
+
+    private void setResultFuture(ResultFuture<Result> future)
+    {
+      this.future = future;
+    }
+  }
+
+
+
+  /**
+   * Creates a new abstract connection.
+   */
+  protected AbstractAsynchronousConnection()
+  {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close()
+  {
+    close(Requests.newUnbindRequest(), null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <P> ResultFuture<SearchResultEntry> readEntry(DN name,
+      Collection<String> attributeDescriptions,
+      ResultHandler<? super SearchResultEntry, P> handler, P p)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    SearchRequest request = Requests.newSearchRequest(name,
+        SearchScope.BASE_OBJECT, Filter.getObjectClassPresentFilter())
+        .addAttribute(attributeDescriptions);
+    return searchSingleEntry(request, handler, p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <P> ResultFuture<RootDSE> readRootDSE(
+      ResultHandler<RootDSE, P> handler, P p)
+      throws UnsupportedOperationException, IllegalStateException
+  {
+    return RootDSE.readRootDSE(this, handler, p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <P> ResultFuture<Schema> readSchema(DN name,
+      ResultHandler<Schema, P> handler, P p)
+      throws UnsupportedOperationException, IllegalStateException
+  {
+    return Schema.readSchema(this, name, handler, p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <P> ResultFuture<Schema> readSchemaForEntry(DN name,
+      ResultHandler<Schema, P> handler, P p)
+      throws UnsupportedOperationException, IllegalStateException
+  {
+    return Schema.readSchema(this, name, handler, p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <P> ResultFuture<SearchResultEntry> searchSingleEntry(
+      SearchRequest request,
+      ResultHandler<? super SearchResultEntry, P> handler, P p)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final SingleEntryFuture<P> innerFuture = new SingleEntryFuture<P>(
+        handler);
+    final ResultFuture<Result> future = search(request, innerFuture,
+        innerFuture, p);
+    innerFuture.setResultFuture(future);
+    return innerFuture;
+  }
+
+}
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/AbstractConnection.java b/opendj-sdk/sdk/src/org/opends/sdk/AbstractConnection.java
index f13dc9f..7b3f780 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/AbstractConnection.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/AbstractConnection.java
@@ -38,6 +38,7 @@
 import org.opends.sdk.requests.Requests;
 import org.opends.sdk.requests.SearchRequest;
 import org.opends.sdk.responses.*;
+import org.opends.sdk.schema.Schema;
 
 import com.sun.opends.sdk.util.Validator;
 
@@ -51,35 +52,14 @@
 public abstract class AbstractConnection implements Connection
 {
 
-  /**
-   * Creates a new abstract connection.
-   */
-  protected AbstractConnection()
-  {
-    // No implementation required.
-  }
-
-
-
   private static final class SingleEntryHandler implements
       SearchResultHandler<Void>
   {
-    // FIXME: does this need to be thread safe?
-    private SearchResultEntry firstEntry = null;
+    private volatile SearchResultEntry firstEntry = null;
 
-    private SearchResultReference firstReference = null;
+    private volatile SearchResultReference firstReference = null;
 
-    private int entryCount = 0;
-
-
-
-    public void handleReference(Void p, SearchResultReference reference)
-    {
-      if (firstReference == null)
-      {
-        firstReference = reference;
-      }
-    }
+    private volatile int entryCount = 0;
 
 
 
@@ -92,6 +72,26 @@
       entryCount++;
     }
 
+
+
+    public void handleReference(Void p, SearchResultReference reference)
+    {
+      if (firstReference == null)
+      {
+        firstReference = reference;
+      }
+    }
+
+  }
+
+
+
+  /**
+   * Creates a new abstract connection.
+   */
+  protected AbstractConnection()
+  {
+    // No implementation required.
   }
 
 
@@ -178,37 +178,99 @@
 
 
 
-  public Result search(SearchRequest request,
-      final Collection<? super SearchResultEntry> entries,
-      final Collection<? super SearchResultReference> references)
-      throws ErrorResultException, InterruptedException,
+  public SearchResultEntry readEntry(DN baseObject,
+      String... attributeDescriptions) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    SearchRequest request = Requests.newSearchRequest(baseObject,
+        SearchScope.BASE_OBJECT, Filter.getObjectClassPresentFilter(),
+        attributeDescriptions);
+    return searchSingleEntry(request);
+  }
+
+
+
+  public SearchResultEntry readEntry(String baseObject,
+      String... attributeDescriptions) throws ErrorResultException,
+      InterruptedException, LocalizedIllegalArgumentException,
       UnsupportedOperationException, IllegalStateException,
       NullPointerException
   {
-    Validator.ensureNotNull(request, entries);
-
-    // FIXME: does this need to be thread safe?
-    SearchResultHandler<Void> handler = new SearchResultHandler<Void>()
-    {
-
-      public void handleReference(Void p,
-          SearchResultReference reference)
-      {
-        if (references != null)
-        {
-          references.add(reference);
-        }
-      }
+    return readEntry(DN.valueOf(baseObject));
+  }
 
 
 
-      public void handleEntry(Void p, SearchResultEntry entry)
-      {
-        entries.add(entry);
-      }
-    };
+  /**
+   * {@inheritDoc}
+   */
+  public RootDSE readRootDSE() throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException
+  {
+    return RootDSE.readRootDSE(this);
+  }
 
-    return search(request, handler, null);
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Schema readSchema(DN name) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException
+  {
+    return Schema.readSchema(this, name);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Schema readSchema(String name) throws ErrorResultException,
+      InterruptedException, LocalizedIllegalArgumentException,
+      UnsupportedOperationException, IllegalStateException
+  {
+    return readSchema(DN.valueOf(name));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Schema readSchemaForEntry(DN name)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException
+  {
+    return Schema.readSchemaForEntry(this, name);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Schema readSchemaForEntry(String name)
+      throws ErrorResultException, InterruptedException,
+      LocalizedIllegalArgumentException, UnsupportedOperationException,
+      IllegalStateException
+  {
+    return readSchemaForEntry(DN.valueOf(name));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Schema readSchemaForRootDSE() throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException
+  {
+    return readSchemaForEntry(DN.rootDN());
   }
 
 
@@ -227,6 +289,41 @@
 
 
 
+  public Result search(SearchRequest request,
+      final Collection<? super SearchResultEntry> entries,
+      final Collection<? super SearchResultReference> references)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(request, entries);
+
+    // FIXME: does this need to be thread safe?
+    SearchResultHandler<Void> handler = new SearchResultHandler<Void>()
+    {
+
+      public void handleEntry(Void p, SearchResultEntry entry)
+      {
+        entries.add(entry);
+      }
+
+
+
+      public void handleReference(Void p,
+          SearchResultReference reference)
+      {
+        if (references != null)
+        {
+          references.add(reference);
+        }
+      }
+    };
+
+    return search(request, handler, null);
+  }
+
+
+
   public List<SearchResultEntry> search(String baseObject,
       SearchScope scope, String filter, String... attributeDescriptions)
       throws ErrorResultException, InterruptedException,
@@ -249,23 +346,35 @@
   {
     SingleEntryHandler handler = new SingleEntryHandler();
     search(request, handler, null);
-    if (handler.entryCount > 1)
+
+    if (handler.entryCount == 0)
+    {
+      // Did not find any entries.
+      Result result = Responses.newResult(
+          ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED)
+          .setDiagnosticMessage(
+              ERR_NO_SEARCH_RESULT_ENTRIES.get().toString());
+      throw ErrorResultException.wrap(result);
+    }
+    else if (handler.entryCount > 1)
     {
       // Got more entries than expected.
       Result result = Responses.newResult(
-          ResultCode.CLIENT_SIDE_MORE_RESULTS_TO_RETURN).setDiagnosticMessage(
-          ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(handler.entryCount)
-              .toString());
+          ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED)
+          .setDiagnosticMessage(
+              ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(
+                  handler.entryCount).toString());
       throw ErrorResultException.wrap(result);
     }
     else if (handler.firstReference != null)
     {
       // Got an unexpected search result reference.
       Result result = Responses.newResult(
-          ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
-          ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get(
-              handler.firstReference.getURIs().iterator().next())
-              .toString());
+          ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED)
+          .setDiagnosticMessage(
+              ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get(
+                  handler.firstReference.getURIs().iterator().next())
+                  .toString());
       throw ErrorResultException.wrap(result);
     }
     else
@@ -287,28 +396,4 @@
     return searchSingleEntry(request);
   }
 
-
-
-  public SearchResultEntry readEntry(String baseObject,
-      String... attributeDescriptions) throws ErrorResultException,
-      InterruptedException, LocalizedIllegalArgumentException,
-      UnsupportedOperationException, IllegalStateException,
-      NullPointerException
-  {
-    return readEntry(DN.valueOf(baseObject));
-  }
-
-
-
-  public SearchResultEntry readEntry(DN baseObject,
-      String... attributeDescriptions) throws ErrorResultException,
-      InterruptedException, UnsupportedOperationException,
-      IllegalStateException, NullPointerException
-  {
-    SearchRequest request = Requests.newSearchRequest(baseObject,
-        SearchScope.BASE_OBJECT, Filter.getObjectClassPresentFilter(),
-        attributeDescriptions);
-    return searchSingleEntry(request);
-  }
-
 }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/AbstractFilterVisitor.java b/opendj-sdk/sdk/src/org/opends/sdk/AbstractFilterVisitor.java
index c1cffda..7f14f15 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/AbstractFilterVisitor.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/AbstractFilterVisitor.java
@@ -83,7 +83,7 @@
    * {@link #visitDefaultFilter(Object)}.
    */
   public R visitApproxMatchFilter(P p, String attributeDescription,
-      ByteSequence assertionValue)
+      ByteString assertionValue)
   {
     return visitDefaultFilter(p);
   }
@@ -114,7 +114,7 @@
    * {@link #visitDefaultFilter(Object)}.
    */
   public R visitEqualityMatchFilter(P p, String attributeDescription,
-      ByteSequence assertionValue)
+      ByteString assertionValue)
   {
     return visitDefaultFilter(p);
   }
@@ -128,7 +128,7 @@
    * {@link #visitDefaultFilter(Object)}.
    */
   public R visitExtensibleMatchFilter(P p, String matchingRule,
-      String attributeDescription, ByteSequence assertionValue,
+      String attributeDescription, ByteString assertionValue,
       boolean dnAttributes)
   {
     return visitDefaultFilter(p);
@@ -143,7 +143,7 @@
    * {@link #visitDefaultFilter(Object)}.
    */
   public R visitGreaterOrEqualFilter(P p, String attributeDescription,
-      ByteSequence assertionValue)
+      ByteString assertionValue)
   {
     return visitDefaultFilter(p);
   }
@@ -157,7 +157,7 @@
    * {@link #visitDefaultFilter(Object)}.
    */
   public R visitLessOrEqualFilter(P p, String attributeDescription,
-      ByteSequence assertionValue)
+      ByteString assertionValue)
   {
     return visitDefaultFilter(p);
   }
@@ -210,8 +210,8 @@
    * {@link #visitDefaultFilter(Object)}.
    */
   public R visitSubstringsFilter(P p, String attributeDescription,
-      ByteSequence initialSubstring, List<ByteSequence> anySubstrings,
-      ByteSequence finalSubstring)
+      ByteString initialSubstring, List<ByteString> anySubstrings,
+      ByteString finalSubstring)
   {
     return visitDefaultFilter(p);
   }
@@ -225,7 +225,7 @@
    * {@link #visitDefaultFilter(Object)}.
    */
   public R visitUnrecognizedFilter(P p, byte filterTag,
-      ByteSequence filterBytes)
+      ByteString filterBytes)
   {
     return visitDefaultFilter(p);
   }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/AsynchronousConnection.java b/opendj-sdk/sdk/src/org/opends/sdk/AsynchronousConnection.java
index b0d8041..1091574 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/AsynchronousConnection.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/AsynchronousConnection.java
@@ -30,11 +30,14 @@
 
 
 import java.io.Closeable;
+import java.util.Collection;
 
 import org.opends.sdk.requests.*;
 import org.opends.sdk.responses.BindResult;
 import org.opends.sdk.responses.CompareResult;
 import org.opends.sdk.responses.Result;
+import org.opends.sdk.responses.SearchResultEntry;
+import org.opends.sdk.schema.Schema;
 
 
 
@@ -190,6 +193,25 @@
 
 
   /**
+   * Registers the provided connection event listener so that it will be
+   * notified when this connection is closed by the application,
+   * receives an unsolicited notification, or experiences a fatal error.
+   *
+   * @param listener
+   *          The listener which wants to be notified when events occur
+   *          on this connection.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code listener} was {@code null}.
+   */
+  void addConnectionEventListener(ConnectionEventListener listener)
+      throws IllegalStateException, NullPointerException;
+
+
+
+  /**
    * Authenticates to the Directory Server using the provided bind
    * request.
    *
@@ -367,6 +389,19 @@
 
 
   /**
+   * Indicates whether or not this connection has been explicitly closed
+   * by calling {@code close}. This method will not return {@code true}
+   * if a fatal error has occurred on the connection unless {@code
+   * close} has been called.
+   *
+   * @return {@code true} if this connection has been explicitly closed
+   *         by calling {@code close}, or {@code false} otherwise.
+   */
+  boolean isClosed();
+
+
+
+  /**
    * Modifies an entry in the Directory Server using the provided modify
    * request.
    *
@@ -429,6 +464,174 @@
 
 
   /**
+   * Reads the named entry from the Directory Server.
+   * <p>
+   * If the requested entry is not returned by the Directory Server then
+   * the request will fail with an {@link EntryNotFoundException}. More
+   * specifically, the returned future will never return {@code null}.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * SearchRequest request = new SearchRequest(name,
+   *     SearchScope.BASE_OBJECT, &quot;(objectClass=*)&quot;, attributeDescriptions);
+   * connection.searchSingleEntry(request, resultHandler, p);
+   * </pre>
+   *
+   * @param <P>
+   *          The type of the additional parameter to the handler's
+   *          methods.
+   * @param name
+   *          The distinguished name of the entry to be read.
+   * @param attributeDescriptions
+   *          The names of the attributes to be included with the entry,
+   *          which may be {@code null} or empty indicating that all
+   *          user attributes should be returned.
+   * @param handler
+   *          A result handler which can be used to asynchronously
+   *          process the operation result when it is received, may be
+   *          {@code null}.
+   * @param p
+   *          Optional additional handler parameter.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code name} was {@code null}.
+   */
+  <P> ResultFuture<SearchResultEntry> readEntry(DN name,
+      Collection<String> attributeDescriptions,
+      ResultHandler<? super SearchResultEntry, P> handler, P p)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Reads the Root DSE from the Directory Server.
+   * <p>
+   * If the Root DSE is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, the returned future will never return {@code null}.
+   *
+   * @param <P>
+   *          The type of the additional parameter to the handler's
+   *          methods.
+   * @param handler
+   *          A result handler which can be used to asynchronously
+   *          process the operation result when it is received, may be
+   *          {@code null}.
+   * @param p
+   *          Optional additional handler parameter.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   */
+  <P> ResultFuture<RootDSE> readRootDSE(
+      ResultHandler<RootDSE, P> handler, P p)
+      throws UnsupportedOperationException, IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server contained in the named
+   * subschema sub-entry.
+   * <p>
+   * If the requested schema is not returned by the Directory Server
+   * then the request will fail with an {@link EntryNotFoundException}.
+   * More specifically, the returned future will never return {@code
+   * null}.
+   * <p>
+   * Implementations may choose to perform optimizations such as
+   * caching.
+   *
+   * @param <P>
+   *          The type of the additional parameter to the handler's
+   *          methods.
+   * @param name
+   *          The distinguished name of the subschema sub-entry.
+   * @param handler
+   *          A result handler which can be used to asynchronously
+   *          process the operation result when it is received, may be
+   *          {@code null}.
+   * @param p
+   *          Optional additional handler parameter.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   */
+  <P> ResultFuture<Schema> readSchema(DN name,
+      ResultHandler<Schema, P> handler, P p)
+      throws UnsupportedOperationException, IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server which applies to the
+   * named entry.
+   * <p>
+   * If the requested entry or its associated schema are not returned by
+   * the Directory Server then the request will fail with an
+   * {@link EntryNotFoundException}. More specifically, the returned
+   * future will never return {@code null}.
+   * <p>
+   * A typical implementation will first read the {@code
+   * subschemaSubentry} attribute of the entry in order to locate the
+   * schema. However, implementations may choose to perform other
+   * optimizations, such as caching.
+   *
+   * @param <P>
+   *          The type of the additional parameter to the handler's
+   *          methods.
+   * @param name
+   *          The distinguished name of the entry whose schema is to be
+   *          located.
+   * @param handler
+   *          A result handler which can be used to asynchronously
+   *          process the operation result when it is received, may be
+   *          {@code null}.
+   * @param p
+   *          Optional additional handler parameter.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   */
+  <P> ResultFuture<Schema> readSchemaForEntry(DN name,
+      ResultHandler<Schema, P> handler, P p)
+      throws UnsupportedOperationException, IllegalStateException;
+
+
+
+  /**
+   * Removes the provided connection event listener from this connection
+   * so that it will no longer be notified when this connection is
+   * closed by the application, receives an unsolicited notification, or
+   * experiences a fatal error.
+   *
+   * @param listener
+   *          The listener which no longer wants to be notified when
+   *          events occur on this connection.
+   * @throws NullPointerException
+   *           If the {@code listener} was {@code null}.
+   */
+  void removeConnectionEventListener(ConnectionEventListener listener)
+      throws NullPointerException;
+
+
+
+  /**
    * Searches the Directory Server using the provided search request.
    *
    * @param <P>
@@ -464,49 +667,39 @@
 
 
   /**
-   * Registers the provided connection event listener so that it will be
-   * notified when this connection is closed by the application,
-   * receives an unsolicited notification, or experiences a fatal error.
+   * Searches the Directory Server for a single entry using the provided
+   * search request.
+   * <p>
+   * If the requested entry is not returned by the Directory Server then
+   * the request will fail with an {@link EntryNotFoundException}. More
+   * specifically, the returned future will never return {@code null}.
+   * If multiple matching entries are returned by the Directory Server
+   * then the request will fail with an
+   * {@link MultipleEntriesFoundException}.
    *
-   * @param listener
-   *          The listener which wants to be notified when events occur
-   *          on this connection.
+   * @param <P>
+   *          The type of the additional parameter to the handler's
+   *          methods.
+   * @param request
+   *          The search request.
+   * @param handler
+   *          A result handler which can be used to asynchronously
+   *          process the operation result when it is received, may be
+   *          {@code null}.
+   * @param p
+   *          Optional additional handler parameter.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
    * @throws IllegalStateException
    *           If this connection has already been closed, i.e. if
    *           {@code isClosed() == true}.
    * @throws NullPointerException
-   *           If the {@code listener} was {@code null}.
+   *           If the {@code request} was {@code null}.
    */
-  void addConnectionEventListener(ConnectionEventListener listener)
-      throws IllegalStateException, NullPointerException;
-
-
-
-  /**
-   * Removes the provided connection event listener from this connection
-   * so that it will no longer be notified when this connection is
-   * closed by the application, receives an unsolicited notification, or
-   * experiences a fatal error.
-   *
-   * @param listener
-   *          The listener which no longer wants to be notified when
-   *          events occur on this connection.
-   * @throws NullPointerException
-   *           If the {@code listener} was {@code null}.
-   */
-  void removeConnectionEventListener(ConnectionEventListener listener)
-      throws NullPointerException;
-
-
-
-  /**
-   * Indicates whether or not this connection has been explicitly closed
-   * by calling {@code close}. This method will not return {@code true}
-   * if a fatal error has occurred on the connection unless {@code
-   * close} has been called.
-   *
-   * @return {@code true} if this connection has been explicitly closed
-   *         by calling {@code close}, or {@code false} otherwise.
-   */
-  boolean isClosed();
+  <P> ResultFuture<SearchResultEntry> searchSingleEntry(
+      SearchRequest request,
+      ResultHandler<? super SearchResultEntry, P> handler, P p)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
 }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/AuthenticatedConnectionFactory.java b/opendj-sdk/sdk/src/org/opends/sdk/AuthenticatedConnectionFactory.java
index a56df5f..953fe56 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/AuthenticatedConnectionFactory.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/AuthenticatedConnectionFactory.java
@@ -29,6 +29,7 @@
 
 
 
+import java.util.Collection;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -38,6 +39,8 @@
 import org.opends.sdk.responses.BindResult;
 import org.opends.sdk.responses.CompareResult;
 import org.opends.sdk.responses.Result;
+import org.opends.sdk.responses.SearchResultEntry;
+import org.opends.sdk.schema.Schema;
 
 import com.sun.opends.sdk.util.Validator;
 
@@ -106,7 +109,8 @@
         ConnectionResultHandler<? super AuthenticatedAsynchronousConnection, P> handler,
         P p)
     {
-      // TODO: bug here? if allowRebind= false then bind will never happen
+      // TODO: bug here? if allowRebind= false then bind will never
+      // happen
       ConnectionFutureImpl<P> future = new ConnectionFutureImpl<P>(
           allowRebinds ? request : null, handler, p);
       future.connectFuture = parentFactory.getAsynchronousConnection(
@@ -465,6 +469,8 @@
           searchResulthandler, p);
     }
 
+
+
     /**
      * {@inheritDoc}
      */
@@ -472,6 +478,72 @@
     {
       return connection.isClosed();
     }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<RootDSE> readRootDSE(
+        ResultHandler<RootDSE, P> handler, P p)
+        throws UnsupportedOperationException, IllegalStateException
+    {
+      return connection.readRootDSE(handler, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<SearchResultEntry> readEntry(DN name,
+        Collection<String> attributeDescriptions,
+        ResultHandler<? super SearchResultEntry, P> resultHandler, P p)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      return connection.readEntry(name, attributeDescriptions,
+          resultHandler, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<SearchResultEntry> searchSingleEntry(
+        SearchRequest request,
+        ResultHandler<? super SearchResultEntry, P> resultHandler, P p)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      return connection.searchSingleEntry(request, resultHandler, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<Schema> readSchemaForEntry(DN name,
+        ResultHandler<Schema, P> handler, P p)
+        throws UnsupportedOperationException, IllegalStateException
+    {
+      return connection.readSchemaForEntry(name, handler, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<Schema> readSchema(DN name,
+        ResultHandler<Schema, P> handler, P p)
+        throws UnsupportedOperationException, IllegalStateException
+    {
+      return connection.readSchema(name, handler, p);
+    }
+
   }
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/CancelledException.java b/opendj-sdk/sdk/src/org/opends/sdk/CancelledResultException.java
similarity index 73%
rename from opendj-sdk/sdk/src/org/opends/sdk/CancelledException.java
rename to opendj-sdk/sdk/src/org/opends/sdk/CancelledResultException.java
index 0119704..5c4f80c 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/CancelledException.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/CancelledResultException.java
@@ -35,12 +35,19 @@
 
 /**
  * Thrown when the result code returned in a Result indicates that the
- * Request was cancelled.
+ * Request was cancelled. More specifically, this exception is used for
+ * the following error result codes:
+ * <ul>
+ * <li>{@link ResultCode#CANCELLED} - the requested operation was
+ * cancelled.
+ * <li>{@link ResultCode#CLIENT_SIDE_USER_CANCELLED} - the requested
+ * operation was cancelled by the user.
+ * </ul>
  */
 @SuppressWarnings("serial")
-public class CancelledException extends ErrorResultException
+public class CancelledResultException extends ErrorResultException
 {
-  CancelledException(Result result)
+  CancelledResultException(Result result)
   {
     super(result);
   }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/Connection.java b/opendj-sdk/sdk/src/org/opends/sdk/Connection.java
index 9aa99ea..cf2cfaf 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/Connection.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/Connection.java
@@ -35,6 +35,7 @@
 
 import org.opends.sdk.requests.*;
 import org.opends.sdk.responses.*;
+import org.opends.sdk.schema.Schema;
 
 
 
@@ -123,6 +124,38 @@
 
 
   /**
+   * Adds the provided entry to the Directory Server.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * AddRequest request = new AddRequest(entry);
+   * connection.add(request);
+   * </pre>
+   *
+   * @param entry
+   *          The entry to be added.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for
+   *           some reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support add operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null} .
+   */
+  Result add(Entry entry) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+
+  /**
    * Adds an entry to the Directory Server using the provided lines of
    * LDIF.
    * <p>
@@ -161,34 +194,21 @@
 
 
   /**
-   * Adds the provided entry to the Directory Server.
-   * <p>
-   * This method is equivalent to the following code:
+   * Registers the provided connection event listener so that it will be
+   * notified when this connection is closed by the application,
+   * receives an unsolicited notification, or experiences a fatal error.
    *
-   * <pre>
-   * AddRequest request = new AddRequest(entry);
-   * connection.add(request);
-   * </pre>
-   *
-   * @param entry
-   *          The entry to be added.
-   * @return The result of the operation.
-   * @throws ErrorResultException
-   *           If the result code indicates that the request failed for
-   *           some reason.
-   * @throws InterruptedException
-   *           If the current thread was interrupted while waiting.
-   * @throws UnsupportedOperationException
-   *           If this connection does not support add operations.
+   * @param listener
+   *          The listener which wants to be notified when events occur
+   *          on this connection.
    * @throws IllegalStateException
    *           If this connection has already been closed, i.e. if
    *           {@code isClosed() == true}.
    * @throws NullPointerException
-   *           If {@code entry} was {@code null} .
+   *           If the {@code listener} was {@code null}.
    */
-  Result add(Entry entry) throws ErrorResultException,
-      InterruptedException, UnsupportedOperationException,
-      IllegalStateException, NullPointerException;
+  void addConnectionEventListener(ConnectionEventListener listener)
+      throws IllegalStateException, NullPointerException;
 
 
 
@@ -513,19 +533,6 @@
 
 
 
-  /**
-   * Indicates whether or not this connection has been explicitly closed
-   * by calling {@code close}. This method will not return {@code true}
-   * if a fatal error has occurred on the connection unless {@code
-   * close} has been called.
-   *
-   * @return {@code true} if this connection has been explicitly closed
-   *         by calling {@code close}, or {@code false} otherwise.
-   */
-  boolean isClosed();
-
-
-
   //
   //
   //
@@ -581,6 +588,19 @@
   // throws InterruptedException, TimeoutException;
 
   /**
+   * Indicates whether or not this connection has been explicitly closed
+   * by calling {@code close}. This method will not return {@code true}
+   * if a fatal error has occurred on the connection unless {@code
+   * close} has been called.
+   *
+   * @return {@code true} if this connection has been explicitly closed
+   *         by calling {@code close}, or {@code false} otherwise.
+   */
+  boolean isClosed();
+
+
+
+  /**
    * Modifies an entry in the Directory Server using the provided modify
    * request.
    *
@@ -710,23 +730,27 @@
 
 
   /**
-   * Searches the Directory Server using the provided search request.
-   * Any matching entries returned by the search as well as any search
-   * result references will be passed to the provided search result
-   * handler.
+   * Reads the named entry from the Directory Server.
+   * <p>
+   * If the requested entry is not returned by the Directory Server then
+   * the request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}.
+   * <p>
+   * This method is equivalent to the following code:
    *
-   * @param <P>
-   *          The type of the additional parameter to the handler's
-   *          methods.
-   * @param request
-   *          The search request.
-   * @param handler
-   *          A search result handler which can be used to process the
-   *          search result entries and references as they are received,
-   *          may be {@code null}.
-   * @param p
-   *          Optional additional handler parameter.
-   * @return The result of the operation.
+   * <pre>
+   * SearchRequest request = new SearchRequest(name,
+   *     SearchScope.BASE_OBJECT, &quot;(objectClass=*)&quot;, attributeDescriptions);
+   * connection.searchSingleEntry(request);
+   * </pre>
+   *
+   * @param name
+   *          The distinguished name of the entry to be read.
+   * @param attributeDescriptions
+   *          The names of the attributes to be included with the entry,
+   *          which may be {@code null} or empty indicating that all
+   *          user attributes should be returned.
+   * @return The single search result entry returned from the search.
    * @throws ErrorResultException
    *           If the result code indicates that the request failed for
    *           some reason.
@@ -738,12 +762,276 @@
    *           If this connection has already been closed, i.e. if
    *           {@code isClosed() == true}.
    * @throws NullPointerException
-   *           If {@code request} was {@code null}.
+   *           If the {@code name} was {@code null}.
    */
-  <P> Result search(SearchRequest request,
-      SearchResultHandler<P> handler, P p) throws ErrorResultException,
+  SearchResultEntry readEntry(DN name, String... attributeDescriptions)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Reads the named entry from the Directory Server.
+   * <p>
+   * If the requested entry is not returned by the Directory Server then
+   * the request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * SearchRequest request = new SearchRequest(name,
+   *     SearchScope.BASE_OBJECT, &quot;(objectClass=*)&quot;, attributeDescriptions);
+   * connection.searchSingleEntry(request);
+   * </pre>
+   *
+   * @param name
+   *          The distinguished name of the entry to be read.
+   * @param attributeDescriptions
+   *          The names of the attributes to be included with the entry.
+   * @return The single search result entry returned from the search.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for
+   *           some reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code baseObject} could not be decoded using the
+   *           default schema.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code name} was {@code null}.
+   */
+  SearchResultEntry readEntry(String name,
+      String... attributeDescriptions) throws ErrorResultException,
+      InterruptedException, LocalizedIllegalArgumentException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Reads the Root DSE from the Directory Server.
+   * <p>
+   * If the Root DSE is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}.
+   *
+   * @return The Directory Server's Root DSE.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for
+   *           some reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   */
+  RootDSE readRootDSE() throws ErrorResultException,
       InterruptedException, UnsupportedOperationException,
-      IllegalStateException, NullPointerException;
+      IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server contained in the named
+   * subschema sub-entry.
+   * <p>
+   * If the requested schema is not returned by the Directory Server
+   * then the request will fail with an {@link EntryNotFoundException}.
+   * More specifically, this method will never return {@code null}.
+   * <p>
+   * Implementations may choose to perform optimizations such as
+   * caching.
+   *
+   * @param name
+   *          The distinguished name of the subschema sub-entry.
+   * @return The schema from the Directory Server.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for
+   *           some reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   */
+  Schema readSchema(DN name) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server contained in the named
+   * subschema sub-entry.
+   * <p>
+   * If the requested schema is not returned by the Directory Server
+   * then the request will fail with an {@link EntryNotFoundException}.
+   * More specifically, this method will never return {@code null}.
+   * <p>
+   * Implementations may choose to perform optimizations such as
+   * caching.
+   *
+   * @param name
+   *          The distinguished name of the subschema sub-entry.
+   * @return The schema from the Directory Server.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for
+   *           some reason.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} could not be decoded using the default
+   *           schema.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   */
+  Schema readSchema(String name) throws ErrorResultException,
+      InterruptedException, LocalizedIllegalArgumentException,
+      UnsupportedOperationException, IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server which applies to the
+   * named entry.
+   * <p>
+   * If the requested entry or its associated schema are not returned by
+   * the Directory Server then the request will fail with an
+   * {@link EntryNotFoundException}. More specifically, this method will
+   * never return {@code null}.
+   * <p>
+   * A typical implementation will first read the {@code
+   * subschemaSubentry} attribute of the entry in order to locate the
+   * schema. However, implementations may choose to perform other
+   * optimizations, such as caching.
+   *
+   * @param name
+   *          The distinguished name of the entry whose schema is to be
+   *          located.
+   * @return The schema from the Directory Server which applies to the
+   *         named entry.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for
+   *           some reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   */
+  Schema readSchemaForEntry(DN name) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server which applies to the
+   * named entry.
+   * <p>
+   * If the requested entry or its associated schema are not returned by
+   * the Directory Server then the request will fail with an
+   * {@link EntryNotFoundException}. More specifically, this method will
+   * never return {@code null}.
+   * <p>
+   * A typical implementation will first read the {@code
+   * subschemaSubentry} attribute of the entry in order to locate the
+   * schema. However, implementations may choose to perform other
+   * optimizations, such as caching.
+   *
+   * @param name
+   *          The distinguished name of the entry whose schema is to be
+   *          located.
+   * @return The schema from the Directory Server which applies to the
+   *         named entry.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for
+   *           some reason.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} could not be decoded using the default
+   *           schema.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   */
+  Schema readSchemaForEntry(String name) throws ErrorResultException,
+      InterruptedException, LocalizedIllegalArgumentException,
+      UnsupportedOperationException, IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server which applies to the
+   * Root DSE.
+   * <p>
+   * If the requested schema is not returned by the Directory Server
+   * then the request will fail with an {@link EntryNotFoundException}.
+   * More specifically, this method will never return {@code null}.
+   * <p>
+   * A typical implementation will first read the {@code
+   * subschemaSubentry} attribute of the Root DSE in order to locate the
+   * schema. However, implementations may choose to perform other
+   * optimizations, such as caching.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * connection.readSchemaForEntry(DN.rootDN());
+   * </pre>
+   *
+   * @return The schema from the Directory Server which applies to the
+   *         named entry.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for
+   *           some reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   */
+  Schema readSchemaForRootDSE() throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException;
+
+
+
+  /**
+   * Removes the provided connection event listener from this connection
+   * so that it will no longer be notified when this connection is
+   * closed by the application, receives an unsolicited notification, or
+   * experiences a fatal error.
+   *
+   * @param listener
+   *          The listener which no longer wants to be notified when
+   *          events occur on this connection.
+   * @throws NullPointerException
+   *           If the {@code listener} was {@code null}.
+   */
+  void removeConnectionEventListener(ConnectionEventListener listener)
+      throws NullPointerException;
 
 
 
@@ -833,6 +1121,44 @@
 
 
   /**
+   * Searches the Directory Server using the provided search request.
+   * Any matching entries returned by the search as well as any search
+   * result references will be passed to the provided search result
+   * handler.
+   *
+   * @param <P>
+   *          The type of the additional parameter to the handler's
+   *          methods.
+   * @param request
+   *          The search request.
+   * @param handler
+   *          A search result handler which can be used to process the
+   *          search result entries and references as they are received,
+   *          may be {@code null}.
+   * @param p
+   *          Optional additional handler parameter.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for
+   *           some reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  <P> Result search(SearchRequest request,
+      SearchResultHandler<P> handler, P p) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+
+  /**
    * Searches the Directory Server using the provided search parameters.
    * Any matching entries returned by the search will be added to a
    * {@code List} which is returned if the search succeeds. Search
@@ -892,9 +1218,13 @@
 
   /**
    * Searches the Directory Server for a single entry using the provided
-   * search request. If the search returns more than one entry then an
-   * {@code ErrorResultException} is thrown. If no entry is found then
-   * this method returns {@code null}.
+   * search request.
+   * <p>
+   * If the requested entry is not returned by the Directory Server then
+   * the request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}. If
+   * multiple matching entries are returned by the Directory Server then
+   * the request will fail with an {@link MultipleEntriesFoundException}.
    *
    * @param request
    *          The search request.
@@ -921,9 +1251,13 @@
 
   /**
    * Searches the Directory Server for a single entry using the provided
-   * search parameters. If the search returns more than one entry then
-   * an {@code ErrorResultException} is thrown. If no entry is found
-   * then this method returns {@code null}.
+   * search parameters.
+   * <p>
+   * If the requested entry is not returned by the Directory Server then
+   * the request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}. If
+   * multiple matching entries are returned by the Directory Server then
+   * the request will fail with an {@link MultipleEntriesFoundException}.
    * <p>
    * This method is equivalent to the following code:
    *
@@ -968,118 +1302,4 @@
       throws ErrorResultException, InterruptedException,
       LocalizedIllegalArgumentException, UnsupportedOperationException,
       IllegalStateException, NullPointerException;
-
-
-
-  /**
-   * Reads the named entry from the Directory Server. If no entry is
-   * found then this method returns {@code null}.
-   * <p>
-   * This method is equivalent to the following code:
-   *
-   * <pre>
-   * SearchRequest request = new SearchRequest(baseObject,
-   *     SearchScope.BASE_OBJECT, &quot;(objectClass=*)&quot;, attributeDescriptions);
-   * connection.searchSingleEntry(request);
-   * </pre>
-   *
-   * @param baseObject
-   *          The distinguished name of the entry to be read.
-   * @param attributeDescriptions
-   *          The names of the attributes to be included with the entry.
-   * @return The single search result entry returned from the search.
-   * @throws ErrorResultException
-   *           If the result code indicates that the request failed for
-   *           some reason.
-   * @throws InterruptedException
-   *           If the current thread was interrupted while waiting.
-   * @throws LocalizedIllegalArgumentException
-   *           If {@code baseObject} could not be decoded using the
-   *           default schema.
-   * @throws UnsupportedOperationException
-   *           If this connection does not support search operations.
-   * @throws IllegalStateException
-   *           If this connection has already been closed, i.e. if
-   *           {@code isClosed() == true}.
-   * @throws NullPointerException
-   *           If the {@code baseObject} was {@code null}.
-   */
-  SearchResultEntry readEntry(String baseObject,
-      String... attributeDescriptions) throws ErrorResultException,
-      InterruptedException, LocalizedIllegalArgumentException,
-      UnsupportedOperationException, IllegalStateException,
-      NullPointerException;
-
-
-
-  /**
-   * Reads the named entry from the Directory Server. If no entry is
-   * found then this method returns {@code null}.
-   * <p>
-   * This method is equivalent to the following code:
-   *
-   * <pre>
-   * SearchRequest request = new SearchRequest(baseObject,
-   *     SearchScope.BASE_OBJECT, &quot;(objectClass=*)&quot;, attributeDescriptions);
-   * connection.searchSingleEntry(request);
-   * </pre>
-   *
-   * @param baseObject
-   *          The distinguished name of the entry to be read.
-   * @param attributeDescriptions
-   *          The names of the attributes to be included with the entry.
-   * @return The single search result entry returned from the search.
-   * @throws ErrorResultException
-   *           If the result code indicates that the request failed for
-   *           some reason.
-   * @throws InterruptedException
-   *           If the current thread was interrupted while waiting.
-   * @throws UnsupportedOperationException
-   *           If this connection does not support search operations.
-   * @throws IllegalStateException
-   *           If this connection has already been closed, i.e. if
-   *           {@code isClosed() == true}.
-   * @throws NullPointerException
-   *           If the {@code baseObject} was {@code null}.
-   */
-  SearchResultEntry readEntry(DN baseObject,
-      String... attributeDescriptions) throws ErrorResultException,
-      InterruptedException, UnsupportedOperationException,
-      IllegalStateException, NullPointerException;
-
-
-
-  /**
-   * Registers the provided connection event listener so that it will be
-   * notified when this connection is closed by the application,
-   * receives an unsolicited notification, or experiences a fatal error.
-   *
-   * @param listener
-   *          The listener which wants to be notified when events occur
-   *          on this connection.
-   * @throws IllegalStateException
-   *           If this connection has already been closed, i.e. if
-   *           {@code isClosed() == true}.
-   * @throws NullPointerException
-   *           If the {@code listener} was {@code null}.
-   */
-  void addConnectionEventListener(ConnectionEventListener listener)
-      throws IllegalStateException, NullPointerException;
-
-
-
-  /**
-   * Removes the provided connection event listener from this connection
-   * so that it will no longer be notified when this connection is
-   * closed by the application, receives an unsolicited notification, or
-   * experiences a fatal error.
-   *
-   * @param listener
-   *          The listener which no longer wants to be notified when
-   *          events occur on this connection.
-   * @throws NullPointerException
-   *           If the {@code listener} was {@code null}.
-   */
-  void removeConnectionEventListener(ConnectionEventListener listener)
-      throws NullPointerException;
 }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/ConnectionPool.java b/opendj-sdk/sdk/src/org/opends/sdk/ConnectionPool.java
index 5d4adba..e8c9504 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/ConnectionPool.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/ConnectionPool.java
@@ -27,6 +27,9 @@
 
 package org.opends.sdk;
 
+
+
+import java.util.Collection;
 import java.util.Stack;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.CountDownLatch;
@@ -35,95 +38,128 @@
 import java.util.logging.Level;
 
 import org.opends.sdk.requests.*;
-import org.opends.sdk.responses.BindResult;
-import org.opends.sdk.responses.CompareResult;
-import org.opends.sdk.responses.GenericExtendedResult;
-import org.opends.sdk.responses.Result;
+import org.opends.sdk.responses.*;
+import org.opends.sdk.schema.Schema;
 
 import com.sun.opends.sdk.util.StaticUtils;
 
+
+
 /**
  * A simple connection pool implementation.
  */
-public class ConnectionPool
-    extends AbstractConnectionFactory<AsynchronousConnection> {
+public class ConnectionPool extends
+    AbstractConnectionFactory<AsynchronousConnection>
+{
   private final ConnectionFactory<?> connectionFactory;
+
   private volatile int numConnections;
+
   private final int poolSize;
 
   // FIXME: should use a better collection than this - CLQ?
   private final Stack<AsynchronousConnection> pool;
 
   private final ConcurrentLinkedQueue<PendingConnectionFuture<?>> pendingFutures;
+
   private final Object lock = new Object();
 
-  private final class PooledConnectionWapper
-      implements AsynchronousConnection, ConnectionEventListener {
+
+
+  private final class PooledConnectionWapper implements
+      AsynchronousConnection, ConnectionEventListener
+  {
     private AsynchronousConnection connection;
 
-    private PooledConnectionWapper(AsynchronousConnection connection) {
+
+
+    private PooledConnectionWapper(AsynchronousConnection connection)
+    {
       this.connection = connection;
       this.connection.addConnectionEventListener(this);
     }
 
+
+
     public void abandon(AbandonRequest request)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
-      if (connection == null) {
+        NullPointerException
+    {
+      if (connection == null)
+      {
         throw new IllegalStateException();
       }
       connection.abandon(request);
     }
 
-    public <P> ResultFuture<Result> add(
-        AddRequest request,
+
+
+    public <P> ResultFuture<Result> add(AddRequest request,
         ResultHandler<Result, P> handler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
-      if (connection == null) {
+        NullPointerException
+    {
+      if (connection == null)
+      {
         throw new IllegalStateException();
       }
       return connection.add(request, handler, p);
     }
 
-    public <P> ResultFuture<BindResult> bind(
-        BindRequest request, ResultHandler<? super BindResult, P> handler, P p)
+
+
+    public <P> ResultFuture<BindResult> bind(BindRequest request,
+        ResultHandler<? super BindResult, P> handler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
-      if (connection == null) {
+        NullPointerException
+    {
+      if (connection == null)
+      {
         throw new IllegalStateException();
       }
       return connection.bind(request, handler, p);
     }
 
-    public void close() {
-      synchronized (lock) {
-        try {
+
+
+    public void close()
+    {
+      synchronized (lock)
+      {
+        try
+        {
           // Don't put closed connections back in the pool.
-          if (connection.isClosed()) {
+          if (connection.isClosed())
+          {
             if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
             {
-              StaticUtils.DEBUG_LOG.finest(String
-                  .format("Dead connection released to pool. " +
-                  "numConnections: %d, poolSize: %d, pendingFutures: %d",
-                  numConnections, pool.size(), pendingFutures.size()));
+              StaticUtils.DEBUG_LOG
+                  .finest(String
+                      .format(
+                          "Dead connection released to pool. "
+                              + "numConnections: %d, poolSize: %d, pendingFutures: %d",
+                          numConnections, pool.size(), pendingFutures
+                              .size()));
             }
             return;
           }
 
           // See if there waiters pending
           PendingConnectionFuture<?> future = pendingFutures.poll();
-          if (future != null) {
-            PooledConnectionWapper pooledConnection =
-                new PooledConnectionWapper(connection);
+          if (future != null)
+          {
+            PooledConnectionWapper pooledConnection = new PooledConnectionWapper(
+                connection);
             future.connection(pooledConnection);
             if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
             {
-              StaticUtils.DEBUG_LOG.finest(String
-                  .format("Connection released to pool and directly " +
-                  "given to waiter. numConnections: %d, poolSize: %d, " +
-                  "pendingFutures: %d", numConnections, pool.size(),
-                  pendingFutures.size()));
+              StaticUtils.DEBUG_LOG
+                  .finest(String
+                      .format(
+                          "Connection released to pool and directly "
+                              + "given to waiter. numConnections: %d, poolSize: %d, "
+                              + "pendingFutures: %d", numConnections,
+                          pool.size(), pendingFutures.size()));
             }
             return;
           }
@@ -132,99 +168,229 @@
           pool.push(connection);
           if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
           {
-            StaticUtils.DEBUG_LOG.finest(String
-                .format("Connection released to pool. " +
-                "numConnections: %d, poolSize: %d, pendingFutures: %d",
-                numConnections, pool.size(), pendingFutures.size()));
+            StaticUtils.DEBUG_LOG
+                .finest(String
+                    .format(
+                        "Connection released to pool. "
+                            + "numConnections: %d, poolSize: %d, pendingFutures: %d",
+                        numConnections, pool.size(), pendingFutures
+                            .size()));
           }
         }
-        finally {
+        finally
+        {
           // Null out the underlying connection to prevent further use.
           connection = null;
         }
       }
     }
 
+
+
     public void close(UnbindRequest request, String reason)
-        throws NullPointerException {
+        throws NullPointerException
+    {
       close();
     }
 
+
+
     public <P> ResultFuture<CompareResult> compare(
-        CompareRequest request, ResultHandler<? super CompareResult, P> handler,
-        P p) throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
-      if (connection == null) {
+        CompareRequest request,
+        ResultHandler<? super CompareResult, P> handler, P p)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (connection == null)
+      {
         throw new IllegalStateException();
       }
       return connection.compare(request, handler, p);
     }
 
-    public <P> ResultFuture<Result> delete(
-        DeleteRequest request, ResultHandler<Result, P> handler, P p)
+
+
+    public <P> ResultFuture<Result> delete(DeleteRequest request,
+        ResultHandler<Result, P> handler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
-      if (connection == null) {
+        NullPointerException
+    {
+      if (connection == null)
+      {
         throw new IllegalStateException();
       }
       return connection.delete(request, handler, p);
     }
 
+
+
     public <R extends Result, P> ResultFuture<R> extendedRequest(
-        ExtendedRequest<R> request, ResultHandler<? super R, P> handler, P p)
+        ExtendedRequest<R> request,
+        ResultHandler<? super R, P> handler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
-      if (connection == null) {
+        NullPointerException
+    {
+      if (connection == null)
+      {
         throw new IllegalStateException();
       }
       return connection.extendedRequest(request, handler, p);
     }
 
-    public <P> ResultFuture<Result> modify(
-        ModifyRequest request, ResultHandler<Result, P> handler, P p)
+
+
+    public <P> ResultFuture<Result> modify(ModifyRequest request,
+        ResultHandler<Result, P> handler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
-      if (connection == null) {
+        NullPointerException
+    {
+      if (connection == null)
+      {
         throw new IllegalStateException();
       }
       return connection.modify(request, handler, p);
     }
 
-    public <P> ResultFuture<Result> modifyDN(
-        ModifyDNRequest request, ResultHandler<Result, P> handler, P p)
+
+
+    public <P> ResultFuture<Result> modifyDN(ModifyDNRequest request,
+        ResultHandler<Result, P> handler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
-      if (connection == null) {
+        NullPointerException
+    {
+      if (connection == null)
+      {
         throw new IllegalStateException();
       }
       return connection.modifyDN(request, handler, p);
     }
 
-    public <P> ResultFuture<Result> search(
-        SearchRequest request, ResultHandler<Result, P> resultHandler,
+
+
+    public <P> ResultFuture<Result> search(SearchRequest request,
+        ResultHandler<Result, P> resultHandler,
         SearchResultHandler<P> searchResulthandler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
-      if (connection == null) {
+        NullPointerException
+    {
+      if (connection == null)
+      {
         throw new IllegalStateException();
       }
-      return connection.search(request, resultHandler, searchResulthandler, p);
+      return connection.search(request, resultHandler,
+          searchResulthandler, p);
     }
 
-    public void addConnectionEventListener(ConnectionEventListener listener)
-        throws IllegalStateException, NullPointerException {
-      if (connection == null) {
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<SearchResultEntry> readEntry(DN name,
+        Collection<String> attributeDescriptions,
+        ResultHandler<? super SearchResultEntry, P> resultHandler, P p)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (connection == null)
+      {
+        throw new IllegalStateException();
+      }
+      return connection.readEntry(name, attributeDescriptions,
+          resultHandler, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<SearchResultEntry> searchSingleEntry(
+        SearchRequest request,
+        ResultHandler<? super SearchResultEntry, P> resultHandler, P p)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (connection == null)
+      {
+        throw new IllegalStateException();
+      }
+      return connection.searchSingleEntry(request, resultHandler, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<RootDSE> readRootDSE(
+        ResultHandler<RootDSE, P> handler, P p)
+        throws UnsupportedOperationException, IllegalStateException
+    {
+      if (connection == null)
+      {
+        throw new IllegalStateException();
+      }
+      return connection.readRootDSE(handler, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<Schema> readSchemaForEntry(DN name,
+        ResultHandler<Schema, P> handler, P p)
+        throws UnsupportedOperationException, IllegalStateException
+    {
+      if (connection == null)
+      {
+        throw new IllegalStateException();
+      }
+      return connection.readSchemaForEntry(name, handler, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<Schema> readSchema(DN name,
+        ResultHandler<Schema, P> handler, P p)
+        throws UnsupportedOperationException, IllegalStateException
+    {
+      if (connection == null)
+      {
+        throw new IllegalStateException();
+      }
+      return connection.readSchema(name, handler, p);
+    }
+
+
+
+    public void addConnectionEventListener(
+        ConnectionEventListener listener) throws IllegalStateException,
+        NullPointerException
+    {
+      if (connection == null)
+      {
         throw new IllegalStateException();
       }
     }
 
-    public void removeConnectionEventListener(ConnectionEventListener listener)
-        throws NullPointerException {
-      if (connection == null) {
+
+
+    public void removeConnectionEventListener(
+        ConnectionEventListener listener) throws NullPointerException
+    {
+      if (connection == null)
+      {
         throw new IllegalStateException();
       }
     }
 
+
+
     /**
      * {@inheritDoc}
      */
@@ -233,14 +399,21 @@
       return connection == null;
     }
 
+
+
     public void connectionReceivedUnsolicitedNotification(
-        GenericExtendedResult notification) {
+        GenericExtendedResult notification)
+    {
       // Ignore
     }
 
+
+
     public void connectionErrorOccurred(
-        boolean isDisconnectNotification, ErrorResultException error) {
-      synchronized (lock) {
+        boolean isDisconnectNotification, ErrorResultException error)
+    {
+      synchronized (lock)
+      {
         // Remove this connection from the pool if its in there
         pool.remove(this);
         numConnections--;
@@ -252,104 +425,166 @@
 
         if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
         {
-          StaticUtils.DEBUG_LOG.finest(String
-              .format("Connection error occured: " + error.getMessage() +
-              " numConnections: %d, poolSize: %d, pendingFutures: %d",
-              numConnections, pool.size(), pendingFutures.size()));
+          StaticUtils.DEBUG_LOG
+              .finest(String
+                  .format(
+                      "Connection error occured: "
+                          + error.getMessage()
+                          + " numConnections: %d, poolSize: %d, pendingFutures: %d",
+                      numConnections, pool.size(), pendingFutures
+                          .size()));
         }
       }
     }
   }
 
-  private static final class CompletedConnectionFuture
-      implements ConnectionFuture<AsynchronousConnection> {
+
+
+  private static final class CompletedConnectionFuture implements
+      ConnectionFuture<AsynchronousConnection>
+  {
     private final PooledConnectionWapper connection;
 
-    private CompletedConnectionFuture(PooledConnectionWapper connection) {
+
+
+    private CompletedConnectionFuture(PooledConnectionWapper connection)
+    {
       this.connection = connection;
     }
 
-    public boolean cancel(boolean mayInterruptIfRunning) {
+
+
+    public boolean cancel(boolean mayInterruptIfRunning)
+    {
       return false;
     }
 
-    public AsynchronousConnection get()
-        throws InterruptedException, ErrorResultException {
+
+
+    public AsynchronousConnection get() throws InterruptedException,
+        ErrorResultException
+    {
       return connection;
     }
 
+
+
     public AsynchronousConnection get(long timeout, TimeUnit unit)
-        throws InterruptedException, TimeoutException, ErrorResultException {
+        throws InterruptedException, TimeoutException,
+        ErrorResultException
+    {
       return connection;
     }
 
-    public boolean isCancelled() {
+
+
+    public boolean isCancelled()
+    {
       return false;
     }
 
-    public boolean isDone() {
+
+
+    public boolean isDone()
+    {
       return true;
     }
   }
 
-  private final class PendingConnectionFuture<P>
-      implements ConnectionFuture<AsynchronousConnection> {
+
+
+  private final class PendingConnectionFuture<P> implements
+      ConnectionFuture<AsynchronousConnection>
+  {
     private volatile boolean isCancelled;
+
     private volatile PooledConnectionWapper connection;
+
     private volatile ErrorResultException err;
-    private final ConnectionResultHandler<? super AsynchronousConnection, P>
-        handler;
+
+    private final ConnectionResultHandler<? super AsynchronousConnection, P> handler;
+
     private final P p;
+
     private final CountDownLatch latch = new CountDownLatch(1);
 
+
+
     private PendingConnectionFuture(
         P p,
-        ConnectionResultHandler<? super AsynchronousConnection, P> handler) {
+        ConnectionResultHandler<? super AsynchronousConnection, P> handler)
+    {
       this.handler = handler;
       this.p = p;
     }
 
-    public synchronized boolean cancel(boolean mayInterruptIfRunning) {
+
+
+    public synchronized boolean cancel(boolean mayInterruptIfRunning)
+    {
       return pendingFutures.remove(this) && (isCancelled = true);
     }
 
-    public AsynchronousConnection get()
-        throws InterruptedException, ErrorResultException {
+
+
+    public AsynchronousConnection get() throws InterruptedException,
+        ErrorResultException
+    {
       latch.await();
-      if (err != null) {
+      if (err != null)
+      {
         throw err;
       }
       return connection;
     }
 
+
+
     public AsynchronousConnection get(long timeout, TimeUnit unit)
-        throws InterruptedException, TimeoutException, ErrorResultException {
+        throws InterruptedException, TimeoutException,
+        ErrorResultException
+    {
       latch.await(timeout, unit);
-      if (err != null) {
+      if (err != null)
+      {
         throw err;
       }
       return connection;
     }
 
-    public synchronized boolean isCancelled() {
+
+
+    public synchronized boolean isCancelled()
+    {
       return isCancelled;
     }
 
-    public boolean isDone() {
+
+
+    public boolean isDone()
+    {
       return latch.getCount() == 0;
     }
 
-    private void connection(PooledConnectionWapper connection) {
+
+
+    private void connection(PooledConnectionWapper connection)
+    {
       this.connection = connection;
-      if (handler != null) {
+      if (handler != null)
+      {
         handler.handleConnection(p, connection);
       }
       latch.countDown();
     }
 
-    private void error(ErrorResultException e) {
+
+
+    private void error(ErrorResultException e)
+    {
       this.err = e;
-      if (handler != null) {
+      if (handler != null)
+      {
         handler.handleConnectionError(p, e);
       }
       latch.countDown();
@@ -368,83 +603,115 @@
    * @param poolSize
    *          The maximum size of the connection pool.
    */
-  public ConnectionPool(ConnectionFactory<?> connectionFactory, int poolSize) {
+  public ConnectionPool(ConnectionFactory<?> connectionFactory,
+      int poolSize)
+  {
     this.connectionFactory = connectionFactory;
     this.poolSize = poolSize;
     this.pool = new Stack<AsynchronousConnection>();
     this.pendingFutures = new ConcurrentLinkedQueue<PendingConnectionFuture<?>>();
   }
 
-  private final class WrapConnectionResultHandler
-      implements ConnectionResultHandler<AsynchronousConnection, Void> {
+
+
+  private final class WrapConnectionResultHandler implements
+      ConnectionResultHandler<AsynchronousConnection, Void>
+  {
     private final PendingConnectionFuture<?> future;
 
-    private WrapConnectionResultHandler(PendingConnectionFuture<?> future) {
+
+
+    private WrapConnectionResultHandler(
+        PendingConnectionFuture<?> future)
+    {
       this.future = future;
     }
 
-    public void handleConnection(
-        java.lang.Void p,
-        AsynchronousConnection connection) {
-      PooledConnectionWapper pooledConnection =
-          new PooledConnectionWapper(connection);
+
+
+    public void handleConnection(java.lang.Void p,
+        AsynchronousConnection connection)
+    {
+      PooledConnectionWapper pooledConnection = new PooledConnectionWapper(
+          connection);
       future.connection(pooledConnection);
     }
 
-    public void handleConnectionError(
-        java.lang.Void p,
-        ErrorResultException error) {
+
+
+    public void handleConnectionError(java.lang.Void p,
+        ErrorResultException error)
+    {
       future.error(error);
     }
   }
 
+
+
   public <P> ConnectionFuture<AsynchronousConnection> getAsynchronousConnection(
-      ConnectionResultHandler<? super AsynchronousConnection, P> handler, P p) {
-    synchronized (lock) {
+      ConnectionResultHandler<? super AsynchronousConnection, P> handler,
+      P p)
+  {
+    synchronized (lock)
+    {
       // Check to see if we have a connection in the pool
 
-
-      if (!pool.isEmpty()) {
+      if (!pool.isEmpty())
+      {
         AsynchronousConnection conn = pool.pop();
         if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
         {
-          StaticUtils.DEBUG_LOG.finest(String
-              .format("Connection aquired from pool. " +
-              "numConnections: %d, poolSize: %d, pendingFutures: %d",
-              numConnections, pool.size(), pendingFutures.size()));
+          StaticUtils.DEBUG_LOG
+              .finest(String
+                  .format(
+                      "Connection aquired from pool. "
+                          + "numConnections: %d, poolSize: %d, pendingFutures: %d",
+                      numConnections, pool.size(), pendingFutures
+                          .size()));
         }
-        PooledConnectionWapper pooledConnection =
-            new PooledConnectionWapper(conn);
-        if (handler != null) {
+        PooledConnectionWapper pooledConnection = new PooledConnectionWapper(
+            conn);
+        if (handler != null)
+        {
           handler.handleConnection(p, pooledConnection);
         }
         return new CompletedConnectionFuture(pooledConnection);
       }
 
-      PendingConnectionFuture<P> pendingFuture =
-          new PendingConnectionFuture<P>(p, handler);
-      // Pool was empty. Maybe a new connection if pool size is not reached
-      if (numConnections < poolSize) {
+      PendingConnectionFuture<P> pendingFuture = new PendingConnectionFuture<P>(
+          p, handler);
+      // Pool was empty. Maybe a new connection if pool size is not
+      // reached
+      if (numConnections < poolSize)
+      {
         numConnections++;
-        WrapConnectionResultHandler wrapHandler =
-            new WrapConnectionResultHandler(pendingFuture);
+        WrapConnectionResultHandler wrapHandler = new WrapConnectionResultHandler(
+            pendingFuture);
         connectionFactory.getAsynchronousConnection(wrapHandler, null);
         if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
         {
-          StaticUtils.DEBUG_LOG.finest(String
-              .format("New connection established and aquired. " +
-              "numConnections: %d, poolSize: %d, pendingFutures: %d",
-              numConnections, pool.size(), pendingFutures.size()));
+          StaticUtils.DEBUG_LOG
+              .finest(String
+                  .format(
+                      "New connection established and aquired. "
+                          + "numConnections: %d, poolSize: %d, pendingFutures: %d",
+                      numConnections, pool.size(), pendingFutures
+                          .size()));
         }
-      } else {
+      }
+      else
+      {
         // Have to wait
         pendingFutures.add(pendingFuture);
         if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
         {
-          StaticUtils.DEBUG_LOG.finest(String
-              .format("No connections available. Wait-listed" +
-              "numConnections: %d, poolSize: %d, pendingFutures: %d",
-              numConnections, pool.size(), pendingFutures.size()));
+          StaticUtils.DEBUG_LOG
+              .finest(String
+                  .format(
+                      "No connections available. Wait-listed"
+                          + "numConnections: %d, poolSize: %d, pendingFutures: %d",
+                      numConnections, pool.size(), pendingFutures
+                          .size()));
         }
       }
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/CancelledException.java b/opendj-sdk/sdk/src/org/opends/sdk/EntryNotFoundException.java
similarity index 65%
copy from opendj-sdk/sdk/src/org/opends/sdk/CancelledException.java
copy to opendj-sdk/sdk/src/org/opends/sdk/EntryNotFoundException.java
index 0119704..87493d5 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/CancelledException.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/EntryNotFoundException.java
@@ -35,12 +35,21 @@
 
 /**
  * Thrown when the result code returned in a Result indicates that the
- * Request was cancelled.
+ * Request failed because the target entry was not found by the
+ * Directory Server. More specifically, this exception is used for the
+ * following error result codes:
+ * <ul>
+ * <li>{@link ResultCode#NO_SUCH_OBJECT} - the requested operation
+ * failed because it referenced an entry that does not exist.
+ * <li>{@link ResultCode#CLIENT_SIDE_NO_RESULTS_RETURNED} - the
+ * requested single entry search operation or read operation failed
+ * because the Directory Server did not return any matching entries.
+ * </ul>
  */
 @SuppressWarnings("serial")
-public class CancelledException extends ErrorResultException
+public class EntryNotFoundException extends ErrorResultException
 {
-  CancelledException(Result result)
+  EntryNotFoundException(Result result)
   {
     super(result);
   }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/ErrorResultException.java b/opendj-sdk/sdk/src/org/opends/sdk/ErrorResultException.java
index 9eee0d5..89af186 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/ErrorResultException.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/ErrorResultException.java
@@ -70,22 +70,34 @@
 
     // TODO: choose type of exception based on result code (e.g.
     // referral).
-    if(result.getResultCode() == ResultCode.CLIENT_SIDE_SERVER_DOWN ||
-        result.getResultCode() == ResultCode.CLIENT_SIDE_CONNECT_ERROR ||
-        result.getResultCode() == ResultCode.CLIENT_SIDE_DECODING_ERROR ||
-        result.getResultCode() == ResultCode.CLIENT_SIDE_ENCODING_ERROR)
+    if (result.getResultCode() == ResultCode.CLIENT_SIDE_SERVER_DOWN
+        || result.getResultCode() == ResultCode.CLIENT_SIDE_CONNECT_ERROR
+        || result.getResultCode() == ResultCode.CLIENT_SIDE_DECODING_ERROR
+        || result.getResultCode() == ResultCode.CLIENT_SIDE_ENCODING_ERROR)
     {
       return new ConnectionException(result);
     }
 
-    if(result.getResultCode() == ResultCode.CLIENT_SIDE_TIMEOUT)
+    if (result.getResultCode() == ResultCode.CLIENT_SIDE_TIMEOUT)
     {
-      return new OperationTimeoutException(result);
+      return new TimeoutResultException(result);
     }
 
-    if(result.getResultCode() == ResultCode.CLIENT_SIDE_USER_CANCELLED)
+    if (result.getResultCode() == ResultCode.CLIENT_SIDE_USER_CANCELLED
+        || result.getResultCode() == ResultCode.CANCELLED)
     {
-      return new CancelledException(result);
+      return new CancelledResultException(result);
+    }
+
+    if (result.getResultCode() == ResultCode.NO_SUCH_OBJECT
+        || result.getResultCode() == ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED)
+    {
+      return new EntryNotFoundException(result);
+    }
+
+    if (result.getResultCode() == ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED)
+    {
+      return new MultipleEntriesFoundException(result);
     }
 
     return new ErrorResultException(result);
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/Filter.java b/opendj-sdk/sdk/src/org/opends/sdk/Filter.java
index cc4c7fe..996f348 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/Filter.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/Filter.java
@@ -90,14 +90,14 @@
   private static final class ApproxMatchImpl extends Impl
   {
 
-    private final ByteSequence assertionValue;
+    private final ByteString assertionValue;
 
     private final String attributeDescription;
 
 
 
     public ApproxMatchImpl(String attributeDescription,
-        ByteSequence assertionValue)
+        ByteString assertionValue)
     {
       this.attributeDescription = attributeDescription;
       this.assertionValue = assertionValue;
@@ -119,14 +119,14 @@
   private static final class EqualityMatchImpl extends Impl
   {
 
-    private final ByteSequence assertionValue;
+    private final ByteString assertionValue;
 
     private final String attributeDescription;
 
 
 
     public EqualityMatchImpl(String attributeDescription,
-        ByteSequence assertionValue)
+        ByteString assertionValue)
     {
       this.attributeDescription = attributeDescription;
       this.assertionValue = assertionValue;
@@ -153,12 +153,12 @@
 
     private final String matchingRule;
 
-    private final ByteSequence matchValue;
+    private final ByteString matchValue;
 
 
 
     public ExtensibleMatchImpl(String matchingRule,
-        String attributeDescription, ByteSequence matchValue,
+        String attributeDescription, ByteString matchValue,
         boolean dnAttributes)
     {
       this.matchingRule = matchingRule;
@@ -183,14 +183,14 @@
   private static final class GreaterOrEqualImpl extends Impl
   {
 
-    private final ByteSequence assertionValue;
+    private final ByteString assertionValue;
 
     private final String attributeDescription;
 
 
 
     public GreaterOrEqualImpl(String attributeDescription,
-        ByteSequence assertionValue)
+        ByteString assertionValue)
     {
       this.attributeDescription = attributeDescription;
       this.assertionValue = assertionValue;
@@ -226,14 +226,14 @@
   private static final class LessOrEqualImpl extends Impl
   {
 
-    private final ByteSequence assertionValue;
+    private final ByteString assertionValue;
 
     private final String attributeDescription;
 
 
 
     public LessOrEqualImpl(String attributeDescription,
-        ByteSequence assertionValue)
+        ByteString assertionValue)
     {
       this.attributeDescription = attributeDescription;
       this.assertionValue = assertionValue;
@@ -325,19 +325,19 @@
   private static final class SubstringsImpl extends Impl
   {
 
-    private final List<ByteSequence> anyStrings;
+    private final List<ByteString> anyStrings;
 
     private final String attributeDescription;
 
-    private final ByteSequence finalString;
+    private final ByteString finalString;
 
-    private final ByteSequence initialString;
+    private final ByteString initialString;
 
 
 
     public SubstringsImpl(String attributeDescription,
-        ByteSequence initialString, List<ByteSequence> anyStrings,
-        ByteSequence finalString)
+        ByteString initialString, List<ByteString> anyStrings,
+        ByteString finalString)
     {
       this.attributeDescription = attributeDescription;
       this.initialString = initialString;
@@ -362,13 +362,13 @@
   private static final class UnrecognizedImpl extends Impl
   {
 
-    private final ByteSequence filterBytes;
+    private final ByteString filterBytes;
 
     private final byte filterTag;
 
 
 
-    public UnrecognizedImpl(byte filterTag, ByteSequence filterBytes)
+    public UnrecognizedImpl(byte filterTag, ByteString filterBytes)
     {
       this.filterTag = filterTag;
       this.filterBytes = filterBytes;
@@ -412,7 +412,7 @@
 
 
     public StringBuilder visitApproxMatchFilter(StringBuilder builder,
-        String attributeDescription, ByteSequence assertionValue)
+        String attributeDescription, ByteString assertionValue)
     {
       builder.append('(');
       builder.append(attributeDescription);
@@ -426,7 +426,7 @@
 
     public StringBuilder visitEqualityMatchFilter(
         StringBuilder builder, String attributeDescription,
-        ByteSequence assertionValue)
+        ByteString assertionValue)
     {
       builder.append('(');
       builder.append(attributeDescription);
@@ -440,7 +440,7 @@
 
     public StringBuilder visitExtensibleMatchFilter(
         StringBuilder builder, String matchingRule,
-        String attributeDescription, ByteSequence assertionValue,
+        String attributeDescription, ByteString assertionValue,
         boolean dnAttributes)
     {
       builder.append('(');
@@ -471,7 +471,7 @@
 
     public StringBuilder visitGreaterOrEqualFilter(
         StringBuilder builder, String attributeDescription,
-        ByteSequence assertionValue)
+        ByteString assertionValue)
     {
       builder.append('(');
       builder.append(attributeDescription);
@@ -484,7 +484,7 @@
 
 
     public StringBuilder visitLessOrEqualFilter(StringBuilder builder,
-        String attributeDescription, ByteSequence assertionValue)
+        String attributeDescription, ByteString assertionValue)
     {
       builder.append('(');
       builder.append(attributeDescription);
@@ -533,8 +533,8 @@
 
 
     public StringBuilder visitSubstringsFilter(StringBuilder builder,
-        String attributeDescription, ByteSequence initialSubstring,
-        List<ByteSequence> anySubstrings, ByteSequence finalSubstring)
+        String attributeDescription, ByteString initialSubstring,
+        List<ByteString> anySubstrings, ByteString finalSubstring)
     {
       builder.append('(');
       builder.append(attributeDescription);
@@ -543,7 +543,7 @@
       {
         valueToFilterString(builder, initialSubstring);
       }
-      for (ByteSequence anySubstring : anySubstrings)
+      for (ByteString anySubstring : anySubstrings)
       {
         builder.append('*');
         valueToFilterString(builder, anySubstring);
@@ -560,7 +560,7 @@
 
 
     public StringBuilder visitUnrecognizedFilter(StringBuilder builder,
-        byte filterTag, ByteSequence filterBytes)
+        byte filterTag, ByteString filterBytes)
     {
       // Fake up a representation.
       builder.append('(');
@@ -723,10 +723,9 @@
    * @return The newly created {@code approximate match} filter.
    */
   public static Filter newApproxMatchFilter(
-      String attributeDescription, ByteSequence assertionValue)
+      String attributeDescription, ByteString assertionValue)
   {
-    Validator.ensureNotNull(attributeDescription);
-    Validator.ensureNotNull(assertionValue);
+    Validator.ensureNotNull(attributeDescription, assertionValue);
     return new Filter(new ApproxMatchImpl(attributeDescription,
         assertionValue));
   }
@@ -734,6 +733,30 @@
 
 
   /**
+   * Creates a new {@code approximate match} filter using the provided
+   * attribute description and assertion value.
+   * <p>
+   * If {@code assertionValue} is not an instance of {@code ByteString}
+   * then it will be converted using the
+   * {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return The newly created {@code approximate match} filter.
+   */
+  public static Filter newApproxMatchFilter(
+      String attributeDescription, Object assertionValue)
+  {
+    Validator.ensureNotNull(attributeDescription, assertionValue);
+    return new Filter(new ApproxMatchImpl(attributeDescription,
+        ByteString.valueOf(assertionValue)));
+  }
+
+
+
+  /**
    * Creates a new {@code equality match} filter using the provided
    * attribute description and assertion value.
    *
@@ -744,10 +767,9 @@
    * @return The newly created {@code equality match} filter.
    */
   public static Filter newEqualityMatchFilter(
-      String attributeDescription, ByteSequence assertionValue)
+      String attributeDescription, ByteString assertionValue)
   {
-    Validator.ensureNotNull(attributeDescription);
-    Validator.ensureNotNull(assertionValue);
+    Validator.ensureNotNull(attributeDescription, assertionValue);
     return new Filter(new EqualityMatchImpl(attributeDescription,
         assertionValue));
   }
@@ -755,6 +777,30 @@
 
 
   /**
+   * Creates a new {@code equality match} filter using the provided
+   * attribute description and assertion value.
+   * <p>
+   * If {@code assertionValue} is not an instance of {@code ByteString}
+   * then it will be converted using the
+   * {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return The newly created {@code equality match} filter.
+   */
+  public static Filter newEqualityMatchFilter(
+      String attributeDescription, Object assertionValue)
+  {
+    Validator.ensureNotNull(attributeDescription, assertionValue);
+    return new Filter(new EqualityMatchImpl(attributeDescription,
+        ByteString.valueOf(assertionValue)));
+  }
+
+
+
+  /**
    * Creates a new {@code extensible match} filter.
    *
    * @param matchingRule
@@ -770,7 +816,7 @@
    * @return The newly created {@code extensible match} filter.
    */
   public static Filter newExtensibleMatchFilter(String matchingRule,
-      String attributeDescription, ByteSequence assertionValue,
+      String attributeDescription, ByteString assertionValue,
       boolean dnAttributes)
   {
     Validator.ensureTrue((matchingRule != null)
@@ -784,6 +830,40 @@
 
 
   /**
+   * Creates a new {@code extensible match} filter.
+   * <p>
+   * If {@code assertionValue} is not an instance of {@code ByteString}
+   * then it will be converted using the
+   * {@link ByteString#valueOf(Object)} method.
+   *
+   * @param matchingRule
+   *          The matching rule name, may be {@code null} if {@code
+   *          attributeDescription} is specified.
+   * @param attributeDescription
+   *          The attribute description, may be {@code null} if {@code
+   *          matchingRule} is specified.
+   * @param assertionValue
+   *          The assertion value.
+   * @param dnAttributes
+   *          Indicates whether DN matching should be performed.
+   * @return The newly created {@code extensible match} filter.
+   */
+  public static Filter newExtensibleMatchFilter(String matchingRule,
+      String attributeDescription, Object assertionValue,
+      boolean dnAttributes)
+  {
+    Validator.ensureTrue((matchingRule != null)
+        || (attributeDescription != null), "matchingRule and/or "
+        + "attributeDescription must not be null");
+    Validator.ensureNotNull(assertionValue);
+    return new Filter(new ExtensibleMatchImpl(matchingRule,
+        attributeDescription, ByteString.valueOf(assertionValue),
+        dnAttributes));
+  }
+
+
+
+  /**
    * Creates a new {@code greater or equal} filter using the provided
    * attribute description and assertion value.
    *
@@ -794,10 +874,9 @@
    * @return The newly created {@code greater or equal} filter.
    */
   public static Filter newGreaterOrEqualFilter(
-      String attributeDescription, ByteSequence assertionValue)
+      String attributeDescription, ByteString assertionValue)
   {
-    Validator.ensureNotNull(attributeDescription);
-    Validator.ensureNotNull(assertionValue);
+    Validator.ensureNotNull(attributeDescription, assertionValue);
     return new Filter(new GreaterOrEqualImpl(attributeDescription,
         assertionValue));
   }
@@ -805,6 +884,30 @@
 
 
   /**
+   * Creates a new {@code greater or equal} filter using the provided
+   * attribute description and assertion value.
+   * <p>
+   * If {@code assertionValue} is not an instance of {@code ByteString}
+   * then it will be converted using the
+   * {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return The newly created {@code greater or equal} filter.
+   */
+  public static Filter newGreaterOrEqualFilter(
+      String attributeDescription, Object assertionValue)
+  {
+    Validator.ensureNotNull(attributeDescription, assertionValue);
+    return new Filter(new GreaterOrEqualImpl(attributeDescription,
+        ByteString.valueOf(assertionValue)));
+  }
+
+
+
+  /**
    * Creates a new {@code less or equal} filter using the provided
    * attribute description and assertion value.
    *
@@ -815,10 +918,9 @@
    * @return The newly created {@code less or equal} filter.
    */
   public static Filter newLessOrEqualFilter(
-      String attributeDescription, ByteSequence assertionValue)
+      String attributeDescription, ByteString assertionValue)
   {
-    Validator.ensureNotNull(attributeDescription);
-    Validator.ensureNotNull(assertionValue);
+    Validator.ensureNotNull(attributeDescription, assertionValue);
     return new Filter(new LessOrEqualImpl(attributeDescription,
         assertionValue));
   }
@@ -826,6 +928,30 @@
 
 
   /**
+   * Creates a new {@code less or equal} filter using the provided
+   * attribute description and assertion value.
+   * <p>
+   * If {@code assertionValue} is not an instance of {@code ByteString}
+   * then it will be converted using the
+   * {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return The newly created {@code less or equal} filter.
+   */
+  public static Filter newLessOrEqualFilter(
+      String attributeDescription, Object assertionValue)
+  {
+    Validator.ensureNotNull(attributeDescription, assertionValue);
+    return new Filter(new LessOrEqualImpl(attributeDescription,
+        ByteString.valueOf(assertionValue)));
+  }
+
+
+
+  /**
    * Creates a new {@code not} filter using the provided sub-filter.
    *
    * @param subFilter
@@ -965,31 +1091,31 @@
    * @return The newly created {@code substrings} filter.
    */
   public static Filter newSubstringsFilter(String attributeDescription,
-      ByteSequence initialSubstring, ByteSequence[] anySubstrings,
-      ByteSequence finalSubstring)
+      ByteString initialSubstring,
+      Collection<ByteString> anySubstrings, ByteString finalSubstring)
   {
     Validator.ensureNotNull(attributeDescription);
     Validator.ensureTrue((initialSubstring != null)
         || (finalSubstring != null)
-        || ((anySubstrings != null) && (anySubstrings.length > 0)),
+        || ((anySubstrings != null) && (anySubstrings.size() > 0)),
         "at least one substring (initial, any or final)"
             + " must be specified");
 
-    List<ByteSequence> anySubstringList;
-    if ((anySubstrings == null) || (anySubstrings.length == 0))
+    List<ByteString> anySubstringList;
+    if ((anySubstrings == null) || (anySubstrings.size() == 0))
     {
       anySubstringList = Collections.emptyList();
     }
-    else if (anySubstrings.length == 1)
+    else if (anySubstrings.size() == 1)
     {
-      Validator.ensureNotNull(anySubstrings[0]);
-      anySubstringList = Collections.singletonList(anySubstrings[0]);
+      ByteString anySubstring = anySubstrings.iterator().next();
+      Validator.ensureNotNull(anySubstring);
+      anySubstringList = Collections.singletonList(anySubstring);
     }
     else
     {
-      anySubstringList = new ArrayList<ByteSequence>(
-          anySubstrings.length);
-      for (ByteSequence anySubstring : anySubstrings)
+      anySubstringList = new ArrayList<ByteString>(anySubstrings.size());
+      for (ByteString anySubstring : anySubstrings)
       {
         Validator.ensureNotNull(anySubstring);
 
@@ -1008,6 +1134,9 @@
    * Creates a new {@code substrings} filter using the provided
    * attribute description, {@code initial}, {@code final}, and {@code
    * any} sub-strings.
+   * <p>
+   * Any substrings which are not instances of {@code ByteString} will
+   * be converted using the {@link ByteString#valueOf(Object)} method.
    *
    * @param attributeDescription
    *          The attribute description.
@@ -1026,9 +1155,8 @@
    * @return The newly created {@code substrings} filter.
    */
   public static Filter newSubstringsFilter(String attributeDescription,
-      ByteSequence initialSubstring,
-      Collection<ByteSequence> anySubstrings,
-      ByteSequence finalSubstring)
+      Object initialSubstring, Collection<?> anySubstrings,
+      Object finalSubstring)
   {
     Validator.ensureNotNull(attributeDescription);
     Validator.ensureTrue((initialSubstring != null)
@@ -1037,32 +1165,33 @@
         "at least one substring (initial, any or final)"
             + " must be specified");
 
-    List<ByteSequence> anySubstringList;
+    List<ByteString> anySubstringList;
     if ((anySubstrings == null) || (anySubstrings.size() == 0))
     {
       anySubstringList = Collections.emptyList();
     }
     else if (anySubstrings.size() == 1)
     {
-      ByteSequence anySubstring = anySubstrings.iterator().next();
+      Object anySubstring = anySubstrings.iterator().next();
       Validator.ensureNotNull(anySubstring);
-      anySubstringList = Collections.singletonList(anySubstring);
+      anySubstringList = Collections.singletonList(ByteString
+          .valueOf(anySubstring));
     }
     else
     {
-      anySubstringList = new ArrayList<ByteSequence>(anySubstrings
-          .size());
-      for (ByteSequence anySubstring : anySubstrings)
+      anySubstringList = new ArrayList<ByteString>(anySubstrings.size());
+      for (Object anySubstring : anySubstrings)
       {
         Validator.ensureNotNull(anySubstring);
 
-        anySubstringList.add(anySubstring);
+        anySubstringList.add(ByteString.valueOf(anySubstring));
       }
       anySubstringList = Collections.unmodifiableList(anySubstringList);
     }
 
     return new Filter(new SubstringsImpl(attributeDescription,
-        initialSubstring, anySubstringList, finalSubstring));
+        ByteString.valueOf(initialSubstring), anySubstringList,
+        ByteString.valueOf(finalSubstring)));
   }
 
 
@@ -1079,7 +1208,7 @@
    * @return The newly created {@code unrecognized} filter.
    */
   public static Filter newUnrecognizedFilter(byte filterTag,
-      ByteSequence filterBytes)
+      ByteString filterBytes)
   {
     Validator.ensureNotNull(filterBytes);
     return new Filter(new UnrecognizedImpl(filterTag, filterBytes));
@@ -1121,8 +1250,8 @@
       }
       else
       {
-        LocalizableMessage message = ERR_LDAP_FILTER_MISMATCHED_PARENTHESES.get(
-            string, 1, string.length());
+        LocalizableMessage message = ERR_LDAP_FILTER_MISMATCHED_PARENTHESES
+            .get(string, 1, string.length());
         throw new LocalizedIllegalArgumentException(message);
       }
     }
@@ -1205,7 +1334,7 @@
       // Look at the character immediately before the equal sign,
       // because it may help determine the filter type.
       String attributeDescription;
-      ByteSequence assertionValue;
+      ByteString assertionValue;
 
       switch (string.charAt(equalPos - 1))
       {
@@ -1244,7 +1373,7 @@
 
 
 
-  private static ByteSequence valueOfAssertionValue(String string,
+  private static ByteString valueOfAssertionValue(String string,
       int startIndex, int endIndex)
       throws LocalizedIllegalArgumentException
   {
@@ -1271,8 +1400,8 @@
           // the binary value.
           if ((i + 2) >= valueBytes.length)
           {
-            LocalizableMessage message = ERR_LDAP_FILTER_INVALID_ESCAPED_BYTE.get(
-                string, startIndex + i + 1);
+            LocalizableMessage message = ERR_LDAP_FILTER_INVALID_ESCAPED_BYTE
+                .get(string, startIndex + i + 1);
             throw new LocalizedIllegalArgumentException(message);
           }
 
@@ -1333,8 +1462,8 @@
             byteValue = (byte) 0xF0;
             break;
           default:
-            LocalizableMessage message = ERR_LDAP_FILTER_INVALID_ESCAPED_BYTE.get(
-                string, startIndex + i + 1);
+            LocalizableMessage message = ERR_LDAP_FILTER_INVALID_ESCAPED_BYTE
+                .get(string, startIndex + i + 1);
             throw new LocalizedIllegalArgumentException(message);
           }
 
@@ -1394,8 +1523,8 @@
             byteValue |= (byte) 0x0F;
             break;
           default:
-            LocalizableMessage message = ERR_LDAP_FILTER_INVALID_ESCAPED_BYTE.get(
-                string, startIndex + i + 1);
+            LocalizableMessage message = ERR_LDAP_FILTER_INVALID_ESCAPED_BYTE
+                .get(string, startIndex + i + 1);
             throw new LocalizedIllegalArgumentException(message);
           }
 
@@ -1596,7 +1725,7 @@
     }
 
     // Parse out the attribute value.
-    ByteSequence matchValue = valueOfAssertionValue(string,
+    ByteString matchValue = valueOfAssertionValue(string,
         equalIndex + 1, endIndex);
 
     // Make sure that the filter has at least one of an attribute
@@ -1733,12 +1862,12 @@
     else
     {
       // Either an equality or substring filter.
-      ByteSequence assertionValue = valueOfAssertionValue(string,
+      ByteString assertionValue = valueOfAssertionValue(string,
           startIndex, endIndex);
 
-      ByteSequence initialString = null;
-      ByteSequence finalString = null;
-      LinkedList<ByteSequence> anyStrings = null;
+      ByteString initialString = null;
+      ByteString finalString = null;
+      LinkedList<ByteString> anyStrings = null;
 
       int lastAsteriskIndex = -1;
       int length = assertionValue.length();
@@ -1760,15 +1889,15 @@
             // Got an any substring.
             if (anyStrings == null)
             {
-              anyStrings = new LinkedList<ByteSequence>();
+              anyStrings = new LinkedList<ByteString>();
             }
 
             int s = lastAsteriskIndex + 1;
             if (s == i)
             {
               // A zero length substring.
-              LocalizableMessage message = ERR_LDAP_FILTER_BAD_SUBSTRING.get(
-                  string, string.subSequence(startIndex, endIndex));
+              LocalizableMessage message = ERR_LDAP_FILTER_BAD_SUBSTRING
+                  .get(string, string.subSequence(startIndex, endIndex));
               throw new LocalizedIllegalArgumentException(message);
             }
 
@@ -1793,7 +1922,7 @@
       }
       else
       {
-        List<ByteSequence> tmp;
+        List<ByteString> tmp;
 
         if (anyStrings == null)
         {
@@ -1830,7 +1959,7 @@
    *          The value to be appended to the builder.
    */
   private static void valueToFilterString(StringBuilder builder,
-      ByteSequence value)
+      ByteString value)
   {
     // Get the binary representation of the value and iterate through
     // it to see if there are any unsafe characters. If there are,
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/FilterVisitor.java b/opendj-sdk/sdk/src/org/opends/sdk/FilterVisitor.java
index dcf85e8..486318c 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/FilterVisitor.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/FilterVisitor.java
@@ -82,7 +82,7 @@
    * @return Returns a visitor specified result.
    */
   R visitApproxMatchFilter(P p, String attributeDescription,
-      ByteSequence assertionValue);
+      ByteString assertionValue);
 
 
 
@@ -98,7 +98,7 @@
    * @return Returns a visitor specified result.
    */
   R visitEqualityMatchFilter(P p, String attributeDescription,
-      ByteSequence assertionValue);
+      ByteString assertionValue);
 
 
 
@@ -120,7 +120,7 @@
    * @return Returns a visitor specified result.
    */
   R visitExtensibleMatchFilter(P p, String matchingRule,
-      String attributeDescription, ByteSequence assertionValue,
+      String attributeDescription, ByteString assertionValue,
       boolean dnAttributes);
 
 
@@ -137,7 +137,7 @@
    * @return Returns a visitor specified result.
    */
   R visitGreaterOrEqualFilter(P p, String attributeDescription,
-      ByteSequence assertionValue);
+      ByteString assertionValue);
 
 
 
@@ -153,7 +153,7 @@
    * @return Returns a visitor specified result.
    */
   R visitLessOrEqualFilter(P p, String attributeDescription,
-      ByteSequence assertionValue);
+      ByteString assertionValue);
 
 
 
@@ -216,8 +216,8 @@
    * @return Returns a visitor specified result.
    */
   R visitSubstringsFilter(P p, String attributeDescription,
-      ByteSequence initialSubstring, List<ByteSequence> anySubstrings,
-      ByteSequence finalSubstring);
+      ByteString initialSubstring, List<ByteString> anySubstrings,
+      ByteString finalSubstring);
 
 
 
@@ -232,6 +232,6 @@
    *          The filter content.
    * @return Returns a visitor specified result.
    */
-  R visitUnrecognizedFilter(P p, byte filterTag, ByteSequence filterBytes);
+  R visitUnrecognizedFilter(P p, byte filterTag, ByteString filterBytes);
 
 }
\ No newline at end of file
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/HeartBeatConnectionFactory.java b/opendj-sdk/sdk/src/org/opends/sdk/HeartBeatConnectionFactory.java
index bf237a3..498d486 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/HeartBeatConnectionFactory.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/HeartBeatConnectionFactory.java
@@ -27,6 +27,9 @@
 
 package org.opends.sdk;
 
+
+
+import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.CancellationException;
@@ -35,46 +38,89 @@
 import java.util.concurrent.TimeoutException;
 
 import org.opends.sdk.requests.*;
-import org.opends.sdk.responses.BindResult;
-import org.opends.sdk.responses.CompareResult;
-import org.opends.sdk.responses.GenericExtendedResult;
-import org.opends.sdk.responses.Result;
+import org.opends.sdk.responses.*;
+import org.opends.sdk.schema.Schema;
 
 import com.sun.opends.sdk.util.Validator;
 
+
+
 /**
- * An heart beat connection factory can be used to create
- * connections that sends a periodic search request to a Directory Server.
+ * An heart beat connection factory can be used to create connections
+ * that sends a periodic search request to a Directory Server.
  */
-public class HeartBeatConnectionFactory
-    extends AbstractConnectionFactory<
-    HeartBeatConnectionFactory.HeartBeatAsynchronousConnection> {
+public class HeartBeatConnectionFactory extends
+    AbstractConnectionFactory<AsynchronousConnection>
+{
   private final SearchRequest heartBeat;
+
   private final int interval;
-  private final List<HeartBeatAsynchronousConnection> activeConnections;
+
+  private final List<AsynchronousConnectionImpl> activeConnections;
+
   private final ConnectionFactory<?> parentFactory;
 
-  private boolean stopRequested;
+  private volatile boolean stopRequested;
 
+
+
+  // FIXME: use a single global scheduler?
+
+  // FIXME: change timeout parameters to long+TimeUnit.
+
+  /**
+   * Creates a new heart-beat connection factory which will create
+   * connections using the provided connection factory and periodically
+   * ping any created connections in order to detect that they are still
+   * alive.
+   *
+   * @param connectionFactory
+   *          The connection factory to use for creating connections.
+   * @param interval
+   *          The period between keepalive pings.
+   */
   public HeartBeatConnectionFactory(
-      ConnectionFactory<?> parentFactory,
-      int interval) {
-    this(parentFactory, Requests.newSearchRequest("", SearchScope.BASE_OBJECT,
-        "(objectClass=*)", "1.1"), interval);
+      ConnectionFactory<?> connectionFactory, int interval)
+  {
+    this(connectionFactory, DEFAULT_SEARCH, interval);
   }
 
+
+
+  private static final SearchRequest DEFAULT_SEARCH = Requests
+      .newSearchRequest("", SearchScope.BASE_OBJECT, "(objectClass=*)",
+          "1.1");
+
+
+
+  /**
+   * Creates a new heart-beat connection factory which will create
+   * connections using the provided connection factory and periodically
+   * ping any created connections using the specified search request in
+   * order to detect that they are still alive.
+   *
+   * @param connectionFactory
+   *          The connection factory to use for creating connections.
+   * @param heartBeat
+   *          The search request to use when pinging connections.
+   * @param interval
+   *          The period between keepalive pings.
+   */
   public HeartBeatConnectionFactory(
-      ConnectionFactory<?> parentFactory,
-      SearchRequest heartBeat, int interval) {
-    Validator.ensureNotNull(parentFactory, heartBeat);
+      ConnectionFactory<?> connectionFactory, SearchRequest heartBeat,
+      int interval)
+  {
+    Validator.ensureNotNull(connectionFactory, heartBeat);
     this.heartBeat = heartBeat;
     this.interval = interval;
-    this.activeConnections = new LinkedList<HeartBeatAsynchronousConnection>();
-    this.parentFactory = parentFactory;
+    this.activeConnections = new LinkedList<AsynchronousConnectionImpl>();
+    this.parentFactory = connectionFactory;
 
-    Runtime.getRuntime().addShutdownHook(new Thread() {
+    Runtime.getRuntime().addShutdownHook(new Thread()
+    {
       @Override
-      public void run() {
+      public void run()
+      {
         stopRequested = true;
       }
     });
@@ -82,116 +128,227 @@
     new HeartBeatThread().start();
   }
 
+
+
   /**
    * An asynchronous connection that sends heart beats and supports all
    * operations.
    */
-  public final class HeartBeatAsynchronousConnection
-      implements AsynchronousConnection, ConnectionEventListener,
-      ResultHandler<Result, Void> {
+  private final class AsynchronousConnectionImpl implements
+      AsynchronousConnection, ConnectionEventListener,
+      ResultHandler<Result, Void>
+  {
     private final AsynchronousConnection connection;
 
-    public HeartBeatAsynchronousConnection(AsynchronousConnection connection) {
+
+
+    private AsynchronousConnectionImpl(AsynchronousConnection connection)
+    {
       this.connection = connection;
     }
 
+
+
     public void abandon(AbandonRequest request)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
+        NullPointerException
+    {
       connection.abandon(request);
     }
 
-    public <P> ResultFuture<Result> add(
-        AddRequest request,
+
+
+    public <P> ResultFuture<Result> add(AddRequest request,
         ResultHandler<Result, P> handler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
+        NullPointerException
+    {
       return connection.add(request, handler, p);
     }
 
-    public <P> ResultFuture<BindResult> bind(
-        BindRequest request, ResultHandler<? super BindResult, P> handler, P p)
+
+
+    public <P> ResultFuture<BindResult> bind(BindRequest request,
+        ResultHandler<? super BindResult, P> handler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
+        NullPointerException
+    {
       return connection.bind(request, handler, p);
     }
 
-    public void close() {
-      synchronized (activeConnections) {
+
+
+    public void close()
+    {
+      synchronized (activeConnections)
+      {
         connection.removeConnectionEventListener(this);
         activeConnections.remove(this);
       }
       connection.close();
     }
 
+
+
     public void close(UnbindRequest request, String reason)
-        throws NullPointerException {
-      synchronized (activeConnections) {
+        throws NullPointerException
+    {
+      synchronized (activeConnections)
+      {
         connection.removeConnectionEventListener(this);
         activeConnections.remove(this);
       }
       connection.close(request, reason);
     }
 
+
+
     public <P> ResultFuture<CompareResult> compare(
-        CompareRequest request, ResultHandler<? super CompareResult, P> handler,
-        P p) throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
+        CompareRequest request,
+        ResultHandler<? super CompareResult, P> handler, P p)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
       return connection.compare(request, handler, p);
     }
 
-    public <P> ResultFuture<Result> delete(
-        DeleteRequest request,
-        ResultHandler<Result, P> handler,
-        P p)
+
+
+    public <P> ResultFuture<Result> delete(DeleteRequest request,
+        ResultHandler<Result, P> handler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
+        NullPointerException
+    {
       return connection.delete(request, handler, p);
     }
 
+
+
     public <R extends Result, P> ResultFuture<R> extendedRequest(
-        ExtendedRequest<R> request, ResultHandler<? super R, P> handler, P p)
+        ExtendedRequest<R> request,
+        ResultHandler<? super R, P> handler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
+        NullPointerException
+    {
       return connection.extendedRequest(request, handler, p);
     }
 
-    public <P> ResultFuture<Result> modify(
-        ModifyRequest request,
-        ResultHandler<Result, P> handler,
-        P p)
+
+
+    public <P> ResultFuture<Result> modify(ModifyRequest request,
+        ResultHandler<Result, P> handler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
+        NullPointerException
+    {
       return connection.modify(request, handler, p);
     }
 
-    public <P> ResultFuture<Result> modifyDN(
-        ModifyDNRequest request,
-        ResultHandler<Result, P> handler,
-        P p)
+
+
+    public <P> ResultFuture<Result> modifyDN(ModifyDNRequest request,
+        ResultHandler<Result, P> handler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
+        NullPointerException
+    {
       return connection.modifyDN(request, handler, p);
     }
 
-    public <P> ResultFuture<Result> search(
-        SearchRequest request, ResultHandler<Result, P> resultHandler,
+
+
+    public <P> ResultFuture<Result> search(SearchRequest request,
+        ResultHandler<Result, P> resultHandler,
         SearchResultHandler<P> searchResultHandler, P p)
         throws UnsupportedOperationException, IllegalStateException,
-        NullPointerException {
-      return connection.search(request, resultHandler, searchResultHandler, p);
+        NullPointerException
+    {
+      return connection.search(request, resultHandler,
+          searchResultHandler, p);
     }
 
-    public void addConnectionEventListener(ConnectionEventListener listener)
-        throws IllegalStateException, NullPointerException {
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<SearchResultEntry> readEntry(DN name,
+        Collection<String> attributeDescriptions,
+        ResultHandler<? super SearchResultEntry, P> resultHandler, P p)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      return connection.readEntry(name, attributeDescriptions,
+          resultHandler, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<SearchResultEntry> searchSingleEntry(
+        SearchRequest request,
+        ResultHandler<? super SearchResultEntry, P> resultHandler, P p)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      return connection.searchSingleEntry(request, resultHandler, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<RootDSE> readRootDSE(
+        ResultHandler<RootDSE, P> handler, P p)
+        throws UnsupportedOperationException, IllegalStateException
+    {
+      return connection.readRootDSE(handler, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<Schema> readSchemaForEntry(DN name,
+        ResultHandler<Schema, P> handler, P p)
+        throws UnsupportedOperationException, IllegalStateException
+    {
+      return connection.readSchemaForEntry(name, handler, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public <P> ResultFuture<Schema> readSchema(DN name,
+        ResultHandler<Schema, P> handler, P p)
+        throws UnsupportedOperationException, IllegalStateException
+    {
+      return connection.readSchema(name, handler, p);
+    }
+
+
+
+    public void addConnectionEventListener(
+        ConnectionEventListener listener) throws IllegalStateException,
+        NullPointerException
+    {
       connection.addConnectionEventListener(listener);
     }
 
-    public void removeConnectionEventListener(ConnectionEventListener listener)
-        throws NullPointerException {
+
+
+    public void removeConnectionEventListener(
+        ConnectionEventListener listener) throws NullPointerException
+    {
       connection.removeConnectionEventListener(listener);
     }
 
+
+
     /**
      * {@inheritDoc}
      */
@@ -200,62 +357,93 @@
       return connection.isClosed();
     }
 
+
+
     public void connectionReceivedUnsolicitedNotification(
-        GenericExtendedResult notification) {
+        GenericExtendedResult notification)
+    {
       // Do nothing
     }
 
+
+
     public void connectionErrorOccurred(
-        boolean isDisconnectNotification,
-        ErrorResultException error) {
-      synchronized (activeConnections) {
+        boolean isDisconnectNotification, ErrorResultException error)
+    {
+      synchronized (activeConnections)
+      {
         connection.removeConnectionEventListener(this);
         activeConnections.remove(this);
       }
     }
 
-    public void handleErrorResult(Void aVoid, ErrorResultException error) {
+
+
+    public void handleErrorResult(Void aVoid, ErrorResultException error)
+    {
       // TODO: I18N
-      if(error instanceof OperationTimeoutException)
+      if (error instanceof TimeoutResultException)
       {
         close(Requests.newUnbindRequest(), "Heart beat timed out");
       }
     }
 
-    public void handleResult(Void aVoid, Result result) {
+
+
+    public void handleResult(Void aVoid, Result result)
+    {
       // Do nothing
     }
 
-    private void sendHeartBeat() {
+
+
+    private void sendHeartBeat()
+    {
       search(heartBeat, this, null, null);
     }
   }
 
-  private final class HeartBeatThread extends Thread {
-    private HeartBeatThread() {
+
+
+  private final class HeartBeatThread extends Thread
+  {
+    private HeartBeatThread()
+    {
       super("Heart Beat Thread");
     }
 
-    public void run() {
-      while (!stopRequested) {
-        synchronized (activeConnections) {
-          for (HeartBeatAsynchronousConnection connection : activeConnections) {
+
+
+    public void run()
+    {
+      while (!stopRequested)
+      {
+        synchronized (activeConnections)
+        {
+          for (AsynchronousConnectionImpl connection : activeConnections)
+          {
             connection.sendHeartBeat();
           }
         }
-        try {
+        try
+        {
           sleep(interval);
-        } catch (InterruptedException e) {
+        }
+        catch (InterruptedException e)
+        {
           // Ignore
         }
       }
     }
   }
 
+
+
   private final class ConnectionFutureImpl<P> implements
-      ConnectionFuture<HeartBeatAsynchronousConnection>,
-      ConnectionResultHandler<AsynchronousConnection, Void> {
-    private volatile HeartBeatAsynchronousConnection heartBeatConnection;
+      ConnectionFuture<AsynchronousConnection>,
+      ConnectionResultHandler<AsynchronousConnection, Void>
+  {
+    private volatile AsynchronousConnectionImpl heartBeatConnection;
 
     private volatile ErrorResultException exception;
 
@@ -263,102 +451,124 @@
 
     private final CountDownLatch latch = new CountDownLatch(1);
 
-    private final
-    ConnectionResultHandler<? super HeartBeatAsynchronousConnection, P> handler;
+    private final ConnectionResultHandler<? super AsynchronousConnectionImpl, P> handler;
 
     private final P p;
 
     private boolean cancelled;
 
 
+
     private ConnectionFutureImpl(
-        ConnectionResultHandler<
-            ? super HeartBeatAsynchronousConnection, P> handler,
-        P p) {
+        ConnectionResultHandler<? super AsynchronousConnectionImpl, P> handler,
+        P p)
+    {
       this.handler = handler;
       this.p = p;
     }
 
 
-    public boolean cancel(boolean mayInterruptIfRunning) {
+
+    public boolean cancel(boolean mayInterruptIfRunning)
+    {
       cancelled = connectFuture.cancel(mayInterruptIfRunning);
-      if (cancelled) {
+      if (cancelled)
+      {
         latch.countDown();
       }
       return cancelled;
     }
 
 
-    public HeartBeatAsynchronousConnection get()
-        throws InterruptedException, ErrorResultException {
+
+    public AsynchronousConnectionImpl get()
+        throws InterruptedException, ErrorResultException
+    {
       latch.await();
-      if (cancelled) {
+      if (cancelled)
+      {
         throw new CancellationException();
       }
-      if (exception != null) {
+      if (exception != null)
+      {
         throw exception;
       }
       return heartBeatConnection;
     }
 
 
-    public HeartBeatAsynchronousConnection get(
-        long timeout,
-        TimeUnit unit) throws InterruptedException, TimeoutException,
-        ErrorResultException {
+
+    public AsynchronousConnectionImpl get(long timeout, TimeUnit unit)
+        throws InterruptedException, TimeoutException,
+        ErrorResultException
+    {
       latch.await(timeout, unit);
-      if (cancelled) {
+      if (cancelled)
+      {
         throw new CancellationException();
       }
-      if (exception != null) {
+      if (exception != null)
+      {
         throw exception;
       }
       return heartBeatConnection;
     }
 
 
-    public boolean isCancelled() {
+
+    public boolean isCancelled()
+    {
       return cancelled;
     }
 
 
-    public boolean isDone() {
+
+    public boolean isDone()
+    {
       return latch.getCount() == 0;
     }
 
 
-    public void handleConnection(
-        Void v,
-        AsynchronousConnection connection) {
-      heartBeatConnection = new HeartBeatAsynchronousConnection(connection);
-      synchronized (activeConnections) {
+
+    public void handleConnection(Void v,
+        AsynchronousConnection connection)
+    {
+      heartBeatConnection = new AsynchronousConnectionImpl(connection);
+      synchronized (activeConnections)
+      {
         connection.addConnectionEventListener(heartBeatConnection);
         activeConnections.add(heartBeatConnection);
       }
-      if (handler != null) {
+      if (handler != null)
+      {
         handler.handleConnection(p, heartBeatConnection);
       }
       latch.countDown();
     }
 
 
-    public void handleConnectionError(Void v, ErrorResultException error) {
+
+    public void handleConnectionError(Void v, ErrorResultException error)
+    {
       exception = error;
-      if (handler != null) {
+      if (handler != null)
+      {
         handler.handleConnectionError(p, error);
       }
       latch.countDown();
     }
   }
 
-  public <P> ConnectionFuture<? extends HeartBeatAsynchronousConnection>
-  getAsynchronousConnection(
-      ConnectionResultHandler<? super
-          HeartBeatAsynchronousConnection, P> pConnectionResultHandler, P p) {
-    ConnectionFutureImpl<P> future =
-        new ConnectionFutureImpl<P>(pConnectionResultHandler, p);
-    future.connectFuture =
-        parentFactory.getAsynchronousConnection(future, null);
+
+
+  public <P> ConnectionFuture<AsynchronousConnection> getAsynchronousConnection(
+      ConnectionResultHandler<? super AsynchronousConnection, P> handler,
+      P p)
+  {
+    ConnectionFutureImpl<P> future = new ConnectionFutureImpl<P>(
+        handler, p);
+    future.connectFuture = parentFactory.getAsynchronousConnection(
+        future, null);
     return future;
   }
 }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/Matcher.java b/opendj-sdk/sdk/src/org/opends/sdk/Matcher.java
index 2a9f488..4d99111 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/Matcher.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/Matcher.java
@@ -43,6 +43,7 @@
 import com.sun.opends.sdk.util.StaticUtils;
 
 
+
 /**
  * An interface for determining whether entries match a {@code Filter}.
  */
@@ -83,9 +84,13 @@
   private static class AssertionMatcherImpl extends MatcherImpl
   {
     private final Assertion assertion;
+
     private final AttributeDescription attributeDescription;
+
     private final boolean dnAttributes;
+
     private final MatchingRule rule;
+
     private final MatchingRuleUse ruleUse;
 
 
@@ -117,8 +122,8 @@
         // If the type field is present and the matchingRule is present,
         // the matchValue is compared against the specified attribute
         // type and its subtypes.
-        final ConditionResult p = Matcher.matches(
-            entry.getAttribute(attributeDescription), rule, assertion);
+        final ConditionResult p = Matcher.matches(entry
+            .getAttribute(attributeDescription), rule, assertion);
         if (p == ConditionResult.TRUE)
         {
           return p;
@@ -135,7 +140,8 @@
           if (ruleUse.hasAttribute(a.getAttributeDescription()
               .getAttributeType()))
           {
-            final ConditionResult p = Matcher.matches(a, rule, assertion);
+            final ConditionResult p = Matcher.matches(a, rule,
+                assertion);
             if (p == ConditionResult.TRUE)
             {
               return p;
@@ -160,8 +166,8 @@
           {
             if (ruleUse.hasAttribute(ava.getAttributeType()))
             {
-              final ConditionResult p =
-                  Matcher.matches(ava.getAttributeValue(), rule, assertion);
+              final ConditionResult p = Matcher.matches(ava
+                  .getAttributeValue(), rule, assertion);
               if (p == ConditionResult.TRUE)
               {
                 return p;
@@ -266,7 +272,7 @@
     public ConditionResult matches(Entry entry)
     {
       return entry.getAttribute(attribute) == null ? ConditionResult.FALSE
-                                                   : ConditionResult.TRUE;
+          : ConditionResult.TRUE;
     }
   }
 
@@ -298,23 +304,23 @@
    * A visitor which is used to transform a filter into a matcher.
    */
   private static final class Visitor implements
-                                     FilterVisitor<MatcherImpl, Schema>
+      FilterVisitor<MatcherImpl, Schema>
   {
     public MatcherImpl visitAndFilter(Schema schema,
-                                      List<Filter> subFilters)
+        List<Filter> subFilters)
     {
       if (subFilters.isEmpty())
       {
-        if(DEBUG_LOG.isLoggable(Level.FINER))
+        if (DEBUG_LOG.isLoggable(Level.FINER))
         {
-          DEBUG_LOG.finer("Empty add filter component. " +
-                          "Will always return TRUE");
+          DEBUG_LOG.finer("Empty add filter component. "
+              + "Will always return TRUE");
         }
         return TRUE;
       }
 
-      final List<MatcherImpl> subMatchers =
-          new ArrayList<MatcherImpl>(subFilters.size());
+      final List<MatcherImpl> subMatchers = new ArrayList<MatcherImpl>(
+          subFilters.size());
       for (final Filter f : subFilters)
       {
         subMatchers.add(f.accept(this, schema));
@@ -325,7 +331,7 @@
 
 
     public MatcherImpl visitApproxMatchFilter(Schema schema,
-                                              String attributeDescription, ByteSequence assertionValue)
+        String attributeDescription, ByteString assertionValue)
     {
       AttributeDescription ad;
       MatchingRule rule;
@@ -337,22 +343,22 @@
       }
       catch (final LocalizedIllegalArgumentException e)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "Attribute description " + attributeDescription  +
-              " is not recognized: " + e.toString());
+          DEBUG_LOG.warning("Attribute description "
+              + attributeDescription + " is not recognized: "
+              + e.toString());
         }
         return UNDEFINED;
       }
 
       if ((rule = ad.getAttributeType().getApproximateMatchingRule()) == null)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "The attribute type " + attributeDescription +
-              " does not define an approximate matching rule");
+          DEBUG_LOG.warning("The attribute type "
+              + attributeDescription
+              + " does not define an approximate matching rule");
         }
         return UNDEFINED;
       }
@@ -363,11 +369,10 @@
       }
       catch (final DecodeException de)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "The assertion value " + assertionValue + " is invalid: " +
-              de.toString());
+          DEBUG_LOG.warning("The assertion value " + assertionValue
+              + " is invalid: " + de.toString());
         }
         return UNDEFINED;
       }
@@ -377,7 +382,7 @@
 
 
     public MatcherImpl visitEqualityMatchFilter(Schema schema,
-                                                String attributeDescription, ByteSequence assertionValue)
+        String attributeDescription, ByteString assertionValue)
     {
       AttributeDescription ad;
       MatchingRule rule;
@@ -389,22 +394,22 @@
       }
       catch (final LocalizedIllegalArgumentException e)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "Attribute description " + attributeDescription  +
-              " is not recognized: " + e.toString());
+          DEBUG_LOG.warning("Attribute description "
+              + attributeDescription + " is not recognized: "
+              + e.toString());
         }
         return UNDEFINED;
       }
 
       if ((rule = ad.getAttributeType().getEqualityMatchingRule()) == null)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "The attribute type " + attributeDescription +
-              " does not define an equality matching rule");
+          DEBUG_LOG.warning("The attribute type "
+              + attributeDescription
+              + " does not define an equality matching rule");
         }
         return UNDEFINED;
       }
@@ -415,11 +420,10 @@
       }
       catch (final DecodeException de)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "The assertion value " + assertionValue + " is invalid: " +
-              de.toString());
+          DEBUG_LOG.warning("The assertion value " + assertionValue
+              + " is invalid: " + de.toString());
         }
         return UNDEFINED;
       }
@@ -429,10 +433,8 @@
 
 
     public MatcherImpl visitExtensibleMatchFilter(Schema schema,
-                                                  String matchingRule,
-                                                  String attributeDescription,
-                                                  ByteSequence assertionValue,
-                                                  boolean dnAttributes)
+        String matchingRule, String attributeDescription,
+        ByteString assertionValue, boolean dnAttributes)
     {
       AttributeDescription ad = null;
       MatchingRule rule = null;
@@ -445,13 +447,12 @@
         {
           rule = schema.getMatchingRule(matchingRule);
         }
-        catch(final UnknownSchemaElementException e)
+        catch (final UnknownSchemaElementException e)
         {
-          if(DEBUG_LOG.isLoggable(Level.WARNING))
+          if (DEBUG_LOG.isLoggable(Level.WARNING))
           {
-            DEBUG_LOG.warning(
-                "Matching rule " + matchingRule  + " is not recognized: " +
-                e.toString());
+            DEBUG_LOG.warning("Matching rule " + matchingRule
+                + " is not recognized: " + e.toString());
           }
           return UNDEFINED;
         }
@@ -461,17 +462,16 @@
       {
         try
         {
-          ad =
-              AttributeDescription
-                  .valueOf(attributeDescription, schema);
+          ad = AttributeDescription.valueOf(attributeDescription,
+              schema);
         }
         catch (final LocalizedIllegalArgumentException e)
         {
-          if(DEBUG_LOG.isLoggable(Level.WARNING))
+          if (DEBUG_LOG.isLoggable(Level.WARNING))
           {
-            DEBUG_LOG.warning(
-                "Attribute description " + attributeDescription  +
-                " is not recognized: " + e.toString());
+            DEBUG_LOG.warning("Attribute description "
+                + attributeDescription + " is not recognized: "
+                + e.toString());
           }
           return UNDEFINED;
         }
@@ -480,11 +480,11 @@
         {
           if ((rule = ad.getAttributeType().getEqualityMatchingRule()) == null)
           {
-            if(DEBUG_LOG.isLoggable(Level.WARNING))
+            if (DEBUG_LOG.isLoggable(Level.WARNING))
             {
-              DEBUG_LOG.warning(
-                  "The attribute type " + attributeDescription +
-                  " does not define an equality matching rule");
+              DEBUG_LOG.warning("The attribute type "
+                  + attributeDescription
+                  + " does not define an equality matching rule");
             }
             return UNDEFINED;
           }
@@ -495,22 +495,22 @@
           {
             ruleUse = schema.getMatchingRuleUse(rule);
           }
-          catch(final UnknownSchemaElementException e)
+          catch (final UnknownSchemaElementException e)
           {
-            if(DEBUG_LOG.isLoggable(Level.WARNING))
+            if (DEBUG_LOG.isLoggable(Level.WARNING))
             {
-              DEBUG_LOG.warning("No matching rule use is defined for " +
-                                "matching rule " + matchingRule);
+              DEBUG_LOG.warning("No matching rule use is defined for "
+                  + "matching rule " + matchingRule);
               return UNDEFINED;
             }
           }
-          if(!ruleUse.hasAttribute(ad.getAttributeType()))
+          if (!ruleUse.hasAttribute(ad.getAttributeType()))
           {
-            if(DEBUG_LOG.isLoggable(Level.WARNING))
+            if (DEBUG_LOG.isLoggable(Level.WARNING))
             {
-              DEBUG_LOG.warning("The matching rule " + matchingRule +
-                                " is not valid for attribute type " +
-                                attributeDescription);
+              DEBUG_LOG.warning("The matching rule " + matchingRule
+                  + " is not valid for attribute type "
+                  + attributeDescription);
             }
             return UNDEFINED;
           }
@@ -522,12 +522,12 @@
         {
           ruleUse = schema.getMatchingRuleUse(rule);
         }
-        catch(final UnknownSchemaElementException e)
+        catch (final UnknownSchemaElementException e)
         {
-          if(DEBUG_LOG.isLoggable(Level.WARNING))
+          if (DEBUG_LOG.isLoggable(Level.WARNING))
           {
-            DEBUG_LOG.warning("No matching rule use is defined for " +
-                              "matching rule " + matchingRule);
+            DEBUG_LOG.warning("No matching rule use is defined for "
+                + "matching rule " + matchingRule);
           }
           return UNDEFINED;
         }
@@ -539,23 +539,21 @@
       }
       catch (final DecodeException de)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "The assertion value " + assertionValue + " is invalid: " +
-              de.toString());
+          DEBUG_LOG.warning("The assertion value " + assertionValue
+              + " is invalid: " + de.toString());
         }
         return UNDEFINED;
       }
       return new AssertionMatcherImpl(ad, rule, ruleUse, assertion,
-                                      dnAttributes);
+          dnAttributes);
     }
 
 
 
     public MatcherImpl visitGreaterOrEqualFilter(Schema schema,
-                                                 String attributeDescription,
-                                                 ByteSequence assertionValue)
+        String attributeDescription, ByteString assertionValue)
     {
       AttributeDescription ad;
       MatchingRule rule;
@@ -567,22 +565,22 @@
       }
       catch (final LocalizedIllegalArgumentException e)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "Attribute description " + attributeDescription  +
-              " is not recognized: " + e.toString());
+          DEBUG_LOG.warning("Attribute description "
+              + attributeDescription + " is not recognized: "
+              + e.toString());
         }
         return UNDEFINED;
       }
 
       if ((rule = ad.getAttributeType().getOrderingMatchingRule()) == null)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "The attribute type " + attributeDescription +
-              " does not define an ordering matching rule");
+          DEBUG_LOG.warning("The attribute type "
+              + attributeDescription
+              + " does not define an ordering matching rule");
         }
         return UNDEFINED;
       }
@@ -593,11 +591,10 @@
       }
       catch (final DecodeException de)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "The assertion value " + assertionValue + " is invalid: " +
-              de.toString());
+          DEBUG_LOG.warning("The assertion value " + assertionValue
+              + " is invalid: " + de.toString());
         }
         return UNDEFINED;
       }
@@ -607,8 +604,7 @@
 
 
     public MatcherImpl visitLessOrEqualFilter(Schema schema,
-                                              String attributeDescription,
-                                              ByteSequence assertionValue)
+        String attributeDescription, ByteString assertionValue)
     {
       AttributeDescription ad;
       MatchingRule rule;
@@ -620,22 +616,22 @@
       }
       catch (final LocalizedIllegalArgumentException e)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "Attribute description " + attributeDescription  +
-              " is not recognized: " + e.toString());
+          DEBUG_LOG.warning("Attribute description "
+              + attributeDescription + " is not recognized: "
+              + e.toString());
         }
         return UNDEFINED;
       }
 
       if ((rule = ad.getAttributeType().getOrderingMatchingRule()) == null)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "The attribute type " + attributeDescription +
-              " does not define an ordering matching rule");
+          DEBUG_LOG.warning("The attribute type "
+              + attributeDescription
+              + " does not define an ordering matching rule");
         }
         return UNDEFINED;
       }
@@ -646,11 +642,10 @@
       }
       catch (final DecodeException de)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "The assertion value " + assertionValue + " is invalid: " +
-              de.toString());
+          DEBUG_LOG.warning("The assertion value " + assertionValue
+              + " is invalid: " + de.toString());
         }
         return UNDEFINED;
       }
@@ -668,20 +663,20 @@
 
 
     public MatcherImpl visitOrFilter(Schema schema,
-                                     List<Filter> subFilters)
+        List<Filter> subFilters)
     {
       if (subFilters.isEmpty())
       {
-        if(DEBUG_LOG.isLoggable(Level.FINER))
+        if (DEBUG_LOG.isLoggable(Level.FINER))
         {
-          DEBUG_LOG.finer("Empty or filter component. " +
-                          "Will always return FALSE");
+          DEBUG_LOG.finer("Empty or filter component. "
+              + "Will always return FALSE");
         }
         return FALSE;
       }
 
-      final List<MatcherImpl> subMatchers =
-          new ArrayList<MatcherImpl>(subFilters.size());
+      final List<MatcherImpl> subMatchers = new ArrayList<MatcherImpl>(
+          subFilters.size());
       for (final Filter f : subFilters)
       {
         subMatchers.add(f.accept(this, schema));
@@ -692,7 +687,7 @@
 
 
     public MatcherImpl visitPresentFilter(Schema schema,
-                                          String attributeDescription)
+        String attributeDescription)
     {
       AttributeDescription ad;
       try
@@ -701,11 +696,11 @@
       }
       catch (final LocalizedIllegalArgumentException e)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "Attribute description " + attributeDescription  +
-              " is not recognized: " + e.toString());
+          DEBUG_LOG.warning("Attribute description "
+              + attributeDescription + " is not recognized: "
+              + e.toString());
         }
         return UNDEFINED;
       }
@@ -716,10 +711,8 @@
 
 
     public MatcherImpl visitSubstringsFilter(Schema schema,
-                                             String attributeDescription,
-                                             ByteSequence initialSubstring,
-                                             List<ByteSequence> anySubstrings,
-                                             ByteSequence finalSubstring)
+        String attributeDescription, ByteString initialSubstring,
+        List<ByteString> anySubstrings, ByteString finalSubstring)
     {
       AttributeDescription ad;
       MatchingRule rule;
@@ -731,39 +724,38 @@
       }
       catch (final LocalizedIllegalArgumentException e)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "Attribute description " + attributeDescription  +
-              " is not recognized: " + e.toString());
+          DEBUG_LOG.warning("Attribute description "
+              + attributeDescription + " is not recognized: "
+              + e.toString());
         }
         return UNDEFINED;
       }
 
       if ((rule = ad.getAttributeType().getSubstringMatchingRule()) == null)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "The attribute type " + attributeDescription +
-              " does not define an substring matching rule");
+          DEBUG_LOG.warning("The attribute type "
+              + attributeDescription
+              + " does not define an substring matching rule");
         }
         return UNDEFINED;
       }
 
       try
       {
-        assertion =
-            rule.getAssertion(initialSubstring, anySubstrings,
-                              finalSubstring);
+        assertion = rule.getAssertion(initialSubstring, anySubstrings,
+            finalSubstring);
       }
       catch (final DecodeException de)
       {
-        if(DEBUG_LOG.isLoggable(Level.WARNING))
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
         {
-          DEBUG_LOG.warning(
-              "The substring assertion values contain an invalid value: " +
-              de.toString());
+          DEBUG_LOG
+              .warning("The substring assertion values contain an invalid value: "
+                  + de.toString());
         }
         return UNDEFINED;
       }
@@ -773,33 +765,31 @@
 
 
     public MatcherImpl visitUnrecognizedFilter(Schema schema,
-                                               byte filterTag,
-                                               ByteSequence filterBytes)
+        byte filterTag, ByteString filterBytes)
     {
-      if(DEBUG_LOG.isLoggable(Level.WARNING))
+      if (DEBUG_LOG.isLoggable(Level.WARNING))
       {
-        DEBUG_LOG.warning("The type of filtering requested with tag " +
-                          StaticUtils.byteToHex(filterTag) +
-                          " is not implemented");
+        DEBUG_LOG.warning("The type of filtering requested with tag "
+            + StaticUtils.byteToHex(filterTag) + " is not implemented");
       }
       return UNDEFINED;
     }
   }
 
+
+
   private static final MatcherImpl FALSE = new FalseMatcherImpl();
 
   private static final MatcherImpl TRUE = new TrueMatcherImpl();
 
-  private static final MatcherImpl UNDEFINED =
-      new UndefinedMatcherImpl();
+  private static final MatcherImpl UNDEFINED = new UndefinedMatcherImpl();
 
-  private static final FilterVisitor<MatcherImpl, Schema> VISITOR =
-      new Visitor();
+  private static final FilterVisitor<MatcherImpl, Schema> VISITOR = new Visitor();
 
 
 
   private static ConditionResult matches(Attribute a,
-                                         MatchingRule rule, Assertion assertion)
+      MatchingRule rule, Assertion assertion)
   {
 
     ConditionResult r = ConditionResult.FALSE;
@@ -809,10 +799,10 @@
       {
         switch (matches(v, rule, assertion))
         {
-          case TRUE:
-            return ConditionResult.TRUE;
-          case UNDEFINED:
-            r = ConditionResult.UNDEFINED;
+        case TRUE:
+          return ConditionResult.TRUE;
+        case UNDEFINED:
+          r = ConditionResult.UNDEFINED;
         }
       }
     }
@@ -822,26 +812,29 @@
 
 
   private static ConditionResult matches(ByteString v,
-                                         MatchingRule rule, Assertion assertion)
+      MatchingRule rule, Assertion assertion)
   {
     try
     {
-      final ByteString normalizedValue =
-          rule.normalizeAttributeValue(v);
+      final ByteString normalizedValue = rule
+          .normalizeAttributeValue(v);
       return assertion.matches(normalizedValue);
     }
     catch (final DecodeException de)
     {
-      if(DEBUG_LOG.isLoggable(Level.WARNING))
+      if (DEBUG_LOG.isLoggable(Level.WARNING))
       {
-        DEBUG_LOG.warning("The attribute value " + v.toString() + " is " +
-                         "invalid for matching rule " + rule.getNameOrOID() +
-                         ". Possible schema error? : " + de.toString());
+        DEBUG_LOG.warning("The attribute value " + v.toString()
+            + " is " + "invalid for matching rule "
+            + rule.getNameOrOID() + ". Possible schema error? : "
+            + de.toString());
       }
       return ConditionResult.UNDEFINED;
     }
   }
 
+
+
   private final MatcherImpl impl;
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/CancelledException.java b/opendj-sdk/sdk/src/org/opends/sdk/MultipleEntriesFoundException.java
similarity index 71%
copy from opendj-sdk/sdk/src/org/opends/sdk/CancelledException.java
copy to opendj-sdk/sdk/src/org/opends/sdk/MultipleEntriesFoundException.java
index 0119704..17f4f3c 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/CancelledException.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/MultipleEntriesFoundException.java
@@ -35,12 +35,17 @@
 
 /**
  * Thrown when the result code returned in a Result indicates that the
- * Request was cancelled.
+ * requested single entry search operation or read operation failed
+ * because the Directory Server returned multiple matching entries (or
+ * search references) when only a single matching entry was expected.
+ * More specifically, this exception is used for the
+ * {@link ResultCode#CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED} error
+ * result codes.
  */
 @SuppressWarnings("serial")
-public class CancelledException extends ErrorResultException
+public class MultipleEntriesFoundException extends ErrorResultException
 {
-  CancelledException(Result result)
+  MultipleEntriesFoundException(Result result)
   {
     super(result);
   }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/ResultCode.java b/opendj-sdk/sdk/src/org/opends/sdk/ResultCode.java
index a8453b4..33e4d8c 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/ResultCode.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/ResultCode.java
@@ -37,7 +37,6 @@
 
 
 
-
 /**
  * An operation result code as defined in RFC 4511 section 4.1.9 is used
  * to indicate the final status of an operation. If a server detects
@@ -483,22 +482,23 @@
       93, INFO_RESULT_CLIENT_SIDE_CONTROL_NOT_FOUND.get());
 
   /**
-   * The client-side result code that indicates that the server did not
-   * return any results for a search operation that was expected to
-   * match at least one entry. This is for client-side use only and
-   * should never be transferred over protocol.
+   * The client-side result code that indicates that the requested
+   * single entry search operation or read operation failed because the
+   * Directory Server did not return any matching entries. This is for
+   * client-side use only and should never be transferred over protocol.
    */
   public static final ResultCode CLIENT_SIDE_NO_RESULTS_RETURNED = registerErrorResultCode(
       94, INFO_RESULT_CLIENT_SIDE_NO_RESULTS_RETURNED.get());
 
   /**
-   * The client-side result code that indicates that the server has
-   * returned more matching entries for a search operation than have
-   * been processed so far. This is for client-side use only and should
-   * never be transferred over protocol.
+   * The client-side result code that the requested single entry search
+   * operation or read operation failed because the Directory Server
+   * returned multiple matching entries (or search references) when only
+   * a single matching entry was expected. This is for client-side use
+   * only and should never be transferred over protocol.
    */
-  public static final ResultCode CLIENT_SIDE_MORE_RESULTS_TO_RETURN = registerErrorResultCode(
-      95, INFO_RESULT_CLIENT_SIDE_MORE_RESULTS_TO_RETURN.get());
+  public static final ResultCode CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED = registerErrorResultCode(
+      95, INFO_RESULT_CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED.get());
 
   /**
    * The client-side result code that indicates that the client detected
@@ -523,7 +523,7 @@
    * The result code that indicates that a cancel request was
    * successful, or that the specified operation was canceled.
    */
-  public static final ResultCode CANCELED = registerErrorResultCode(
+  public static final ResultCode CANCELLED = registerErrorResultCode(
       118, INFO_RESULT_CANCELED.get());
 
   /**
@@ -637,8 +637,8 @@
 
     if (resultCode == null)
     {
-      resultCode = new ResultCode(intValue, LocalizableMessage.raw("undefined("
-          + intValue + ")"), true);
+      resultCode = new ResultCode(intValue, LocalizableMessage
+          .raw("undefined(" + intValue + ")"), true);
     }
 
     return resultCode;
@@ -670,7 +670,8 @@
 
 
   // Prevent direct instantiation.
-  private ResultCode(int intValue, LocalizableMessage name, boolean exceptional)
+  private ResultCode(int intValue, LocalizableMessage name,
+      boolean exceptional)
   {
     this.intValue = intValue;
     this.name = name;
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/ResultFuture.java b/opendj-sdk/sdk/src/org/opends/sdk/ResultFuture.java
index 63a8a09..e3a933f 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/ResultFuture.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/ResultFuture.java
@@ -34,18 +34,16 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-import org.opends.sdk.responses.Result;
-
 
 
 /**
  * A handle which can be used to retrieve the Result of an asynchronous
  * Request.
- * 
+ *
  * @param <S>
  *          The type of result returned by this future.
  */
-public interface ResultFuture<S extends Result> extends Future<S>
+public interface ResultFuture<S> extends Future<S>
 {
   /**
    * Attempts to cancel the request. This attempt will fail if the
@@ -57,7 +55,7 @@
    * always return {@code true}. Subsequent calls to
    * {@link #isCancelled} will always return {@code true} if this method
    * returned {@code true}.
-   * 
+   *
    * @param mayInterruptIfRunning
    *          {@code true} if the thread executing executing the
    *          response handler should be interrupted; otherwise,
@@ -75,19 +73,20 @@
    * the result if the request succeeded. If the request failed (i.e. a
    * non-successful result code was obtained) then the result is thrown
    * as an {@link ErrorResultException}.
-   * 
+   *
    * @return The result, but only if the result code indicates that the
    *         request succeeded.
-   * @throws CancellationException
-   *           If the request was cancelled using a call to
-   *           {@link #cancel}.
    * @throws ErrorResultException
    *           If the result code indicates that the request failed for
    *           some reason.
+   * @throws CancellationException
+   *           If the request was cancelled using a call to
+   *           {@link #cancel}.
    * @throws InterruptedException
    *           If the current thread was interrupted while waiting.
    */
-  S get() throws InterruptedException, ErrorResultException;
+  S get() throws ErrorResultException, CancellationException,
+      InterruptedException;
 
 
 
@@ -96,32 +95,32 @@
    * complete, and then returns the result if the request succeeded. If
    * the request failed (i.e. a non-successful result code was obtained)
    * then the result is thrown as an {@link ErrorResultException}.
-   * 
+   *
    * @param timeout
    *          The maximum time to wait.
    * @param unit
    *          The time unit of the timeout argument.
    * @return The result, but only if the result code indicates that the
    *         request succeeded.
-   * @throws CancellationException
-   *           If the request was cancelled using a call to
-   *           {@link #cancel}.
    * @throws ErrorResultException
    *           If the result code indicates that the request failed for
    *           some reason.
-   * @throws InterruptedException
-   *           If the current thread was interrupted while waiting.
    * @throws TimeoutException
    *           If the wait timed out.
+   * @throws CancellationException
+   *           If the request was cancelled using a call to
+   *           {@link #cancel}.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
    */
-  S get(long timeout, TimeUnit unit) throws InterruptedException,
-      TimeoutException, ErrorResultException;
+  S get(long timeout, TimeUnit unit) throws ErrorResultException,
+      TimeoutException, CancellationException, InterruptedException;
 
 
 
   /**
    * Returns the message ID of the request.
-   * 
+   *
    * @return The message ID.
    */
   int getMessageID();
@@ -131,7 +130,7 @@
   /**
    * Returns {@code true} if the request was cancelled before it
    * completed normally.
-   * 
+   *
    * @return {@code true} if the request was cancelled before it
    *         completed normally, otherwise {@code false}.
    */
@@ -145,7 +144,7 @@
    * Completion may be due to normal termination, an exception, or
    * cancellation. In all of these cases, this method will return
    * {@code true}.
-   * 
+   *
    * @return {@code true} if the request has completed, otherwise
    *         {@code false}.
    */
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/ResultHandler.java b/opendj-sdk/sdk/src/org/opends/sdk/ResultHandler.java
index 8433352..84d638b 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/ResultHandler.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/ResultHandler.java
@@ -27,12 +27,6 @@
 
 package org.opends.sdk;
 
-
-
-import org.opends.sdk.responses.Result;
-
-
-
 /**
  * A completion handler for consuming the result of an asynchronous
  * operation.
@@ -46,7 +40,7 @@
  * Implementations of these methods should complete in a timely manner
  * so as to avoid keeping the invoking thread from dispatching to other
  * completion handlers.
- * 
+ *
  * @param <S>
  *          The type of result handled by this result handler.
  * @param <P>
@@ -54,11 +48,11 @@
  *          methods. Use {@link java.lang.Void} for visitors that do not
  *          need an additional parameter.
  */
-public interface ResultHandler<S extends Result, P>
+public interface ResultHandler<S, P>
 {
   /**
    * Invoked when the asynchronous operation has failed.
-   * 
+   *
    * @param p
    *          A handler specified parameter.
    * @param error
@@ -71,7 +65,7 @@
 
   /**
    * Invoked when the asynchronous operation has completed successfully.
-   * 
+   *
    * @param p
    *          A handler specified parameter.
    * @param result
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java b/opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java
index 0e9a032..d9b579f 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java
@@ -32,432 +32,476 @@
 import java.util.Collection;
 import java.util.Collections;
 
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.SearchRequest;
 import org.opends.sdk.responses.SearchResultEntry;
-import org.opends.sdk.schema.SchemaNotFoundException;
+import org.opends.sdk.schema.CoreSchema;
 
-import com.sun.opends.sdk.util.Functions;
-import com.sun.opends.sdk.util.Iterables;
-import com.sun.opends.sdk.util.Validator;
+import com.sun.opends.sdk.util.*;
 
 
 
 /**
- * Root DSE Entry.
+ * The root DSE is a DSA-specific Entry (DSE) and not part of any naming
+ * context (or any subtree), and which is uniquely identified by the
+ * empty DN.
+ * <p>
+ * A Directory Server uses the root DSE to provide information about
+ * itself using the following set of attributes:
+ * <ul>
+ * <li>{@code altServer}: alternative Directory Servers
+ * <li>{@code namingContexts}: naming contexts
+ * <li>{@code supportedControl}: recognized LDAP controls
+ * <li>{@code supportedExtension}: recognized LDAP extended operations
+ * <li>{@code supportedFeatures}: recognized LDAP features
+ * <li>{@code supportedLDAPVersion}: LDAP versions supported
+ * <li>{@code supportedSASLMechanisms}: recognized SASL authentication
+ * mechanisms
+ * <li>{@code supportedAuthPasswordSchemes}: recognized authentication
+ * password schemes
+ * <li>{@code subschemaSubentry}: the name of the subschema subentry
+ * holding the schema controlling the Root DSE
+ * <li>{@code vendorName}: the name of the Directory Server implementer
+ * <li>{@code vendorVersion}: the version of the Directory Server
+ * implementation.
+ * </ul>
+ * The values provided for these attributes may depend on session-
+ * specific and other factors. For example, a server supporting the SASL
+ * EXTERNAL mechanism might only list "EXTERNAL" when the client's
+ * identity has been established by a lower level.
+ * <p>
+ * The root DSE may also include a {@code subschemaSubentry} attribute.
+ * If it does, the attribute refers to the subschema (sub)entry holding
+ * the schema controlling the root DSE. Clients SHOULD NOT assume that
+ * this subschema (sub)entry controls other entries held by the server.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4512">RFC 4512 -
+ *      Lightweight Directory Access Protocol (LDAP): Directory
+ *      Information Models </a>
+ * @see <a href="http://tools.ietf.org/html/rfc3045">RFC 3045 - Storing
+ *      Vendor Information in the LDAP Root DSE </a>
+ * @see <a href="http://tools.ietf.org/html/rfc3112">RFC 3112 - LDAP
+ *      Authentication Password Schema </a>
  */
-public class RootDSE extends AbstractEntry
+public final class RootDSE
 {
   private static final AttributeDescription ATTR_ALT_SERVER = AttributeDescription
-      .valueOf("altServer");
+      .create(CoreSchema.getAltServerAttributeType());
 
   private static final AttributeDescription ATTR_NAMING_CONTEXTS = AttributeDescription
-      .valueOf("namingContexts");
+      .create(CoreSchema.getNamingContextsAttributeType());
 
   private static final AttributeDescription ATTR_SUPPORTED_CONTROL = AttributeDescription
-      .valueOf("supportedControl");
+      .create(CoreSchema.getSupportedControlAttributeType());
 
   private static final AttributeDescription ATTR_SUPPORTED_EXTENSION = AttributeDescription
-      .valueOf("supportedExtension");
+      .create(CoreSchema.getSupportedExtensionAttributeType());
 
   private static final AttributeDescription ATTR_SUPPORTED_FEATURE = AttributeDescription
-      .valueOf("supportedFeatures");
+      .create(CoreSchema.getSupportedFeaturesAttributeType());
 
   private static final AttributeDescription ATTR_SUPPORTED_LDAP_VERSION = AttributeDescription
-      .valueOf("supportedLDAPVersion");
+      .create(CoreSchema.getSupportedLDAPVersionAttributeType());
 
   private static final AttributeDescription ATTR_SUPPORTED_SASL_MECHANISMS = AttributeDescription
-      .valueOf("supportedSASLMechanisms");
+      .create(CoreSchema.getSupportedSASLMechanismsAttributeType());
 
   private static final AttributeDescription ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES = AttributeDescription
-      .valueOf("supportedAuthPasswordSchemes");
+      .create(CoreSchema.getSupportedAuthPasswordSchemesAttributeType());
+
+  private static final AttributeDescription ATTR_SUBSCHEMA_SUBENTRY = AttributeDescription
+      .create(CoreSchema.getSubschemaSubentryAttributeType());
 
   private static final AttributeDescription ATTR_VENDOR_NAME = AttributeDescription
-      .valueOf("vendorName");
+      .create(CoreSchema.getVendorNameAttributeType());
 
   private static final AttributeDescription ATTR_VENDOR_VERSION = AttributeDescription
-      .valueOf("vendorVersion");
+      .create(CoreSchema.getVendorNameAttributeType());
 
-  private static String[] ROOTDSE_ATTRS = new String[] {
-      ATTR_ALT_SERVER.toString(), ATTR_NAMING_CONTEXTS.toString(),
-      ATTR_SUPPORTED_CONTROL.toString(),
-      ATTR_SUPPORTED_EXTENSION.toString(),
-      ATTR_SUPPORTED_FEATURE.toString(),
-      ATTR_SUPPORTED_LDAP_VERSION.toString(),
-      ATTR_SUPPORTED_SASL_MECHANISMS.toString(),
-      ATTR_VENDOR_NAME.toString(), ATTR_VENDOR_VERSION.toString(),
-      ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES.toString(), "*" };
+  private static final SearchRequest SEARCH_REQUEST = Requests
+      .newSearchRequest(DN.rootDN(), SearchScope.BASE_OBJECT, Filter
+          .getObjectClassPresentFilter(), ATTR_ALT_SERVER.toString(),
+          ATTR_NAMING_CONTEXTS.toString(), ATTR_SUPPORTED_CONTROL
+              .toString(), ATTR_SUPPORTED_EXTENSION.toString(),
+          ATTR_SUPPORTED_FEATURE.toString(),
+          ATTR_SUPPORTED_LDAP_VERSION.toString(),
+          ATTR_SUPPORTED_SASL_MECHANISMS.toString(), ATTR_VENDOR_NAME
+              .toString(), ATTR_VENDOR_VERSION.toString(),
+          ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES.toString(),
+          ATTR_SUBSCHEMA_SUBENTRY.toString(), "*");
+
+
+
+  /**
+   * Reads the Root DSE from the Directory Server using the provided
+   * connection.
+   * <p>
+   * If the Root DSE is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, the returned future will never return {@code null}.
+   *
+   * @param <P>
+   *          The type of the additional parameter to the handler's
+   *          methods.
+   * @param connection
+   *          A connection to the Directory Server whose Root DSE is to
+   *          be read.
+   * @param handler
+   *          A result handler which can be used to asynchronously
+   *          process the operation result when it is received, may be
+   *          {@code null}.
+   * @param p
+   *          Optional additional handler parameter.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If the connection does not support search operations.
+   * @throws IllegalStateException
+   *           If the connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} was {@code null}.
+   */
+  public static <P> ResultFuture<RootDSE> readRootDSE(
+      AsynchronousConnection connection,
+      ResultHandler<RootDSE, P> handler, P p)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final ResultTransformer<SearchResultEntry, RootDSE, P> future =
+      new ResultTransformer<SearchResultEntry, RootDSE, P>(handler)
+    {
+
+      protected RootDSE transformResult(SearchResultEntry result)
+          throws ErrorResultException
+      {
+        return new RootDSE(result);
+      }
+
+    };
+
+    ResultFuture<SearchResultEntry> innerFuture = connection
+        .searchSingleEntry(SEARCH_REQUEST, future, p);
+    future.setResultFuture(innerFuture);
+    return future;
+  }
+
+
+
+  /**
+   * Reads the Root DSE from the Directory Server using the provided
+   * connection.
+   * <p>
+   * If the Root DSE is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}.
+   *
+   * @param connection
+   *          A connection to the Directory Server whose Root DSE is to
+   *          be read.
+   * @return The Directory Server's Root DSE.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for
+   *           some reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If the connection does not support search operations.
+   * @throws IllegalStateException
+   *           If the connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} was {@code null}.
+   */
+  public static RootDSE readRootDSE(Connection connection)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final Entry entry = connection.searchSingleEntry(SEARCH_REQUEST);
+    return new RootDSE(entry);
+  }
+
+
 
   private final Entry entry;
 
-  private final Iterable<String> altServers;
-
-  private final Iterable<DN> namingContexts;
-
-  private final Iterable<String> supportedControls;
-
-  private final Iterable<String> supportedExtensions;
-
-  private final Iterable<String> supportedFeatures;
-
-  private final Iterable<Integer> supportedLDAPVerions;
-
-  private final Iterable<String> supportedSASLMechanisms;
-
-  private final Iterable<String> supportedAuthPasswordSchemes;
-
-  private final String vendorName;
-
-  private final String vendorVersion;
 
 
-
-  private RootDSE(Entry entry) throws IllegalArgumentException
+  /**
+   * Creates a new Root DSE instance backed by the provided entry.
+   * Modifications made to {@code entry} will be reflected in the
+   * returned Root DSE. The returned Root DSE instance is unmodifiable
+   * and attempts to use modify any of the returned collections will
+   * result in a {@code UnsupportedOperationException}.
+   *
+   * @param entry
+   *          The Root DSE entry.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null} .
+   */
+  public RootDSE(Entry entry) throws NullPointerException
   {
-    this.entry = Types.unmodifiableEntry(entry);
-
-    Attribute attr = getAttribute(ATTR_ALT_SERVER);
-    if (attr == null)
-    {
-      altServers = Collections.emptyList();
-    }
-    else
-    {
-      altServers = Iterables.unmodifiable(Iterables.transform(attr,
-          Functions.valueToString()));
-    }
-
-    attr = getAttribute(ATTR_NAMING_CONTEXTS);
-    if (attr == null)
-    {
-      namingContexts = Collections.emptyList();
-    }
-    else
-    {
-      namingContexts = Iterables.unmodifiable(Iterables.transform(attr,
-          Functions.valueToDN()));
-    }
-
-    attr = getAttribute(ATTR_SUPPORTED_CONTROL);
-    if (attr == null)
-    {
-      supportedControls = Collections.emptyList();
-    }
-    else
-    {
-      supportedControls = Iterables.unmodifiable(Iterables.transform(
-          attr, Functions.valueToString()));
-    }
-
-    attr = getAttribute(ATTR_SUPPORTED_EXTENSION);
-    if (attr == null)
-    {
-      supportedExtensions = Collections.emptyList();
-    }
-    else
-    {
-      supportedExtensions = Iterables.unmodifiable(Iterables.transform(
-          attr, Functions.valueToString()));
-    }
-
-    attr = getAttribute(ATTR_SUPPORTED_FEATURE);
-    if (attr == null)
-    {
-      supportedFeatures = Collections.emptyList();
-    }
-    else
-    {
-      supportedFeatures = Iterables.unmodifiable(Iterables.transform(
-          attr, Functions.valueToString()));
-    }
-
-    attr = getAttribute(ATTR_SUPPORTED_LDAP_VERSION);
-    if (attr == null)
-    {
-      supportedLDAPVerions = Collections.emptyList();
-    }
-    else
-    {
-      supportedLDAPVerions = Iterables.unmodifiable(Iterables
-          .transform(attr, Functions.valueToInteger()));
-    }
-
-    attr = getAttribute(ATTR_SUPPORTED_SASL_MECHANISMS);
-    if (attr == null)
-    {
-      supportedSASLMechanisms = Collections.emptyList();
-    }
-    else
-    {
-      supportedSASLMechanisms = Iterables.unmodifiable(Iterables
-          .transform(attr, Functions.valueToString()));
-    }
-
-    attr = getAttribute(ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES);
-    if (attr == null)
-    {
-      supportedAuthPasswordSchemes = Collections.emptyList();
-    }
-    else
-    {
-      supportedAuthPasswordSchemes = Iterables.unmodifiable(Iterables
-          .transform(attr, Functions.valueToString()));
-    }
-
-    attr = getAttribute(ATTR_VENDOR_NAME);
-    vendorName = attr == null ? "" : attr.firstValueAsString();
-
-    attr = getAttribute(ATTR_VENDOR_VERSION);
-    vendorVersion = attr == null ? "" : attr.firstValueAsString();
+    Validator.ensureNotNull(entry);
+    this.entry = entry;
   }
 
 
 
-  public static RootDSE getRootDSE(Connection connection)
-      throws ErrorResultException, InterruptedException,
-      DecodeException, SchemaNotFoundException
+  /**
+   * Returns an unmodifiable list of URIs referring to alternative
+   * Directory Servers that may be contacted when the Directory Server
+   * becomes unavailable.
+   * <p>
+   * URIs for Directory Servers implementing the LDAP protocol are
+   * written according to RFC 4516. Other kinds of URIs may be provided.
+   * <p>
+   * If the Directory Server does not know of any other Directory
+   * Servers that could be used, the returned list will be empty.
+   *
+   * @return An unmodifiable list of URIs referring to alternative
+   *         Directory Servers, which may be empty.
+   * @see <a href="http://tools.ietf.org/html/rfc4516">RFC 4516 -
+   *      Lightweight Directory Access Protocol (LDAP): Uniform Resource
+   *      Locator </a>
+   */
+  public Collection<String> getAlternativeServers()
   {
-    SearchResultEntry result = connection.readEntry(DN.rootDN(),
-        ROOTDSE_ATTRS);
-    return new RootDSE(result);
+    return getMultiValuedAttribute(ATTR_ALT_SERVER, Functions
+        .valueToString());
   }
 
 
 
-  public Iterable<String> getAltServers()
+  /**
+   * Returns an unmodifiable list of DNs identifying the context
+   * prefixes of the naming contexts that the Directory Server masters
+   * or shadows (in part or in whole).
+   * <p>
+   * If the Directory Server does not master or shadow any naming
+   * contexts, the returned list will be empty.
+   *
+   * @return An unmodifiable list of DNs identifying the context
+   *         prefixes of the naming contexts, which may be empty.
+   */
+  public Collection<String> getNamingContexts()
   {
-    return altServers;
+    return getMultiValuedAttribute(
+        ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES, Functions.valueToString());
   }
 
 
 
-  public Iterable<DN> getNamingContexts()
+  /**
+   * Returns a string which represents the DN of the subschema subentry
+   * holding the schema controlling the Root DSE.
+   * <p>
+   * Clients SHOULD NOT assume that this subschema (sub)entry controls
+   * other entries held by the Directory Server.
+   *
+   * @return The DN of the subschema subentry holding the schema
+   *         controlling the Root DSE, or {@code null} if the DN is not
+   *         provided.
+   */
+  public String getSubschemaSubentry()
   {
-    return namingContexts;
+    return getSingleValuedAttribute(ATTR_SUBSCHEMA_SUBENTRY);
   }
 
 
 
-  public Iterable<String> getSupportedControls()
+  /**
+   * Returns an unmodifiable list of supported authentication password
+   * schemes which the Directory Server supports.
+   * <p>
+   * If the Directory Server does not support any authentication
+   * password schemes, the returned list will be empty.
+   *
+   * @return An unmodifiable list of supported authentication password
+   *         schemes, which may be empty.
+   * @see <a href="http://tools.ietf.org/html/rfc3112">RFC 3112 - LDAP
+   *      Authentication Password Schema </a>
+   */
+  public Collection<String> getSupportedAuthenticationPasswordSchemes()
   {
-    return supportedControls;
+    return getMultiValuedAttribute(
+        ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES, Functions.valueToString());
   }
 
 
 
-  public boolean supportsControl(String oid)
+  /**
+   * Returns an unmodifiable list of object identifiers identifying the
+   * request controls that the Directory Server supports.
+   * <p>
+   * If the Directory Server does not support any request controls, the
+   * returned list will be empty. Object identifiers identifying
+   * response controls may not be listed.
+   *
+   * @return An unmodifiable list of object identifiers identifying the
+   *         request controls, which may be empty.
+   */
+  public Collection<String> getSupportedControls()
   {
-    Validator.ensureNotNull(oid);
-    for (String supported : supportedControls)
-    {
-      if (supported.equals(oid))
-      {
-        return true;
-      }
-    }
-    return false;
+    return getMultiValuedAttribute(ATTR_SUPPORTED_CONTROL, Functions
+        .valueToString());
   }
 
 
 
-  public Iterable<String> getSupportedExtendedOperations()
+  /**
+   * Returns an unmodifiable list of object identifiers identifying the
+   * extended operations that the Directory Server supports.
+   * <p>
+   * If the Directory Server does not support any extended operations,
+   * the returned list will be empty.
+   * <p>
+   * An extended operation generally consists of an extended request and
+   * an extended response but may also include other protocol data units
+   * (such as intermediate responses). The object identifier assigned to
+   * the extended request is used to identify the extended operation.
+   * Other object identifiers used in the extended operation may not be
+   * listed as values of this attribute.
+   *
+   * @return An unmodifiable list of object identifiers identifying the
+   *         extended operations, which may be empty.
+   */
+  public Collection<String> getSupportedExtendedOperations()
   {
-    return supportedExtensions;
+    return getMultiValuedAttribute(ATTR_SUPPORTED_EXTENSION, Functions
+        .valueToString());
   }
 
 
 
-  public boolean supportsExtendedOperation(String oid)
+  /**
+   * Returns an unmodifiable list of object identifiers identifying
+   * elective features that the Directory Server supports.
+   * <p>
+   * If the server does not support any discoverable elective features,
+   * the returned list will be empty.
+   *
+   * @return An unmodifiable list of object identifiers identifying the
+   *         elective features, which may be empty.
+   */
+  public Collection<String> getSupportedFeatures()
   {
-    Validator.ensureNotNull(oid);
-    for (String supported : supportedExtensions)
-    {
-      if (supported.equals(oid))
-      {
-        return true;
-      }
-    }
-    return false;
+    return getMultiValuedAttribute(ATTR_SUPPORTED_FEATURE, Functions
+        .valueToString());
   }
 
 
 
-  public Iterable<String> getSupportedFeatures()
+  /**
+   * Returns an unmodifiable list of the versions of LDAP that the
+   * Directory Server supports.
+   *
+   * @return An unmodifiable list of the versions.
+   */
+  public Collection<Integer> getSupportedLDAPVersions()
   {
-    return supportedFeatures;
+    return getMultiValuedAttribute(ATTR_SUPPORTED_LDAP_VERSION,
+        Functions.valueToInteger());
   }
 
 
 
-  public boolean supportsFeature(String oid)
+  /**
+   * Returns an unmodifiable list of the SASL mechanisms that the
+   * Directory Server recognizes and/or supports.
+   * <p>
+   * The contents of the returned list may depend on the current session
+   * state and may be empty if the Directory Server does not support any
+   * SASL mechanisms.
+   *
+   * @return An unmodifiable list of the SASL mechanisms, which may be
+   *         empty.
+   * @see <a href="http://tools.ietf.org/html/rfc4513">RFC 4513 -
+   *      Lightweight Directory Access Protocol (LDAP): Authentication
+   *      Methods and Security Mechanisms </a>
+   * @see <a href="http://tools.ietf.org/html/rfc4422">RFC 4422 - Simple
+   *      Authentication and Security Layer (SASL) </a>
+   */
+  public Collection<String> getSupportedSASLMechanisms()
   {
-    Validator.ensureNotNull(oid);
-    for (String supported : supportedFeatures)
-    {
-      if (supported.equals(oid))
-      {
-        return true;
-      }
-    }
-    return false;
+    return getMultiValuedAttribute(ATTR_SUPPORTED_SASL_MECHANISMS,
+        Functions.valueToString());
   }
 
 
 
-  public Iterable<Integer> getSupportedLDAPVersions()
-  {
-    return supportedLDAPVerions;
-  }
-
-
-
-  public boolean supportsLDAPVersion(int version)
-  {
-    for (int supported : supportedLDAPVerions)
-    {
-      if (supported == version)
-      {
-        return true;
-      }
-    }
-    return false;
-  }
-
-
-
-  public Iterable<String> getSupportedSASLMechanismNames()
-  {
-    return supportedSASLMechanisms;
-  }
-
-
-
-  public boolean supportsSASLMechanism(String name)
-  {
-    Validator.ensureNotNull(name);
-    for (String supported : supportedSASLMechanisms)
-    {
-      if (supported.equals(name))
-      {
-        return true;
-      }
-    }
-    return false;
-  }
-
-
-
-  public Iterable<String> getSupportedAuthPasswordSchemes()
-  {
-    return supportedSASLMechanisms;
-  }
-
-
-
-  public boolean supportsAuthPasswordScheme(String name)
-  {
-    Validator.ensureNotNull(name);
-    for (String supported : supportedAuthPasswordSchemes)
-    {
-      if (supported.equals(name))
-      {
-        return true;
-      }
-    }
-    return false;
-  }
-
-
-
+  /**
+   * Returns a string which represents the name of the Directory Server
+   * implementer.
+   *
+   * @return The name of the Directory Server implementer, or {@code
+   *         null} if the vendor name is not provided.
+   * @see <a href="http://tools.ietf.org/html/rfc3045">RFC 3045 -
+   *      Storing Vendor Information in the LDAP Root DSE </a>
+   */
   public String getVendorName()
   {
-    return vendorName;
+    return getSingleValuedAttribute(ATTR_VENDOR_NAME);
   }
 
 
 
+  /**
+   * Returns a string which represents the version of the Directory
+   * Server implementation.
+   * <p>
+   * Note that this value is typically a release value comprised of a
+   * string and/or a string of numbers used by the developer of the LDAP
+   * server product. The returned string will be unique between two
+   * versions of the Directory Server, but there are no other syntactic
+   * restrictions on the value or the way it is formatted.
+   *
+   * @return The version of the Directory Server implementation, or
+   *         {@code null} if the vendor version is not provided.
+   * @see <a href="http://tools.ietf.org/html/rfc3045">RFC 3045 -
+   *      Storing Vendor Information in the LDAP Root DSE </a>
+   */
   public String getVendorVersion()
   {
-    return vendorVersion;
+    return getSingleValuedAttribute(ATTR_VENDOR_VERSION);
   }
 
 
 
-  /**
-   * {@inheritDoc}
-   */
-  public boolean addAttribute(Attribute attribute,
-      Collection<ByteString> duplicateValues)
-      throws UnsupportedOperationException, NullPointerException
+  private <N> Collection<N> getMultiValuedAttribute(
+      AttributeDescription attributeDescription,
+      Function<ByteString, N, Void> function)
   {
-    throw new UnsupportedOperationException();
+    // The returned collection is unmodifiable because we may need to
+    // return an empty collection if the attribute does not exist in the
+    // underlying entry. If a value is then added to the returned empty
+    // collection it would require that an attribute is created in the
+    // underlying entry in order to maintain consistency.
+    final Attribute attr = entry.getAttribute(attributeDescription);
+    if (attr != null)
+    {
+      return Collections.unmodifiableCollection(Collections2.transform(
+          attr, function, Functions.objectToByteString()));
+    }
+    else
+    {
+      return Collections.emptySet();
+    }
   }
 
 
 
-  public Entry clearAttributes() throws UnsupportedOperationException
-  {
-    throw new UnsupportedOperationException();
-  }
-
-
-
-  public boolean containsAttribute(
+  private String getSingleValuedAttribute(
       AttributeDescription attributeDescription)
-      throws NullPointerException
   {
-    Validator.ensureNotNull(attributeDescription);
-
-    return entry.containsAttribute(attributeDescription);
+    final Attribute attr = entry.getAttribute(attributeDescription);
+    if (attr == null || attr.isEmpty())
+    {
+      return null;
+    }
+    else
+    {
+      return attr.firstValueAsString();
+    }
   }
 
-
-
-  public Attribute getAttribute(
-      AttributeDescription attributeDescription)
-      throws NullPointerException
-  {
-    Validator.ensureNotNull(attributeDescription);
-
-    return entry.getAttribute(attributeDescription);
-  }
-
-
-
-  public int getAttributeCount()
-  {
-    return entry.getAttributeCount();
-  }
-
-
-
-  public Iterable<Attribute> getAttributes()
-  {
-    return entry.getAttributes();
-  }
-
-
-
-  public DN getName()
-  {
-    return DN.rootDN();
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public boolean removeAttribute(Attribute attribute,
-      Collection<ByteString> missingValues)
-      throws UnsupportedOperationException, NullPointerException
-  {
-    throw new UnsupportedOperationException();
-  }
-
-
-
-  public Entry setName(DN dn) throws UnsupportedOperationException,
-      NullPointerException
-  {
-    throw new UnsupportedOperationException();
-  }
 }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/SynchronousConnection.java b/opendj-sdk/sdk/src/org/opends/sdk/SynchronousConnection.java
index d1bd6ef..3ebef74 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/SynchronousConnection.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/SynchronousConnection.java
@@ -33,6 +33,7 @@
 import org.opends.sdk.responses.BindResult;
 import org.opends.sdk.responses.CompareResult;
 import org.opends.sdk.responses.Result;
+import org.opends.sdk.schema.Schema;
 
 import com.sun.opends.sdk.util.Validator;
 
@@ -270,4 +271,26 @@
     return connection.isClosed();
   }
 
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Schema readSchemaForEntry(DN name)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException
+  {
+    ResultFuture<Schema> future = connection.readSchemaForEntry(name,
+        null, null);
+    try
+    {
+      return future.get();
+    }
+    finally
+    {
+      // Cancel the request if it hasn't completed.
+      future.cancel(false);
+    }
+  }
+
 }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/OperationTimeoutException.java b/opendj-sdk/sdk/src/org/opends/sdk/TimeoutResultException.java
similarity index 91%
rename from opendj-sdk/sdk/src/org/opends/sdk/OperationTimeoutException.java
rename to opendj-sdk/sdk/src/org/opends/sdk/TimeoutResultException.java
index cff5dc9..c7fbe1c 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/OperationTimeoutException.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/TimeoutResultException.java
@@ -39,9 +39,9 @@
  * out period.
  */
 @SuppressWarnings("serial")
-public class OperationTimeoutException extends ErrorResultException
+public class TimeoutResultException extends ErrorResultException
 {
-  OperationTimeoutException(Result result)
+  TimeoutResultException(Result result)
   {
     super(result);
   }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/controls/MatchedValuesControl.java b/opendj-sdk/sdk/src/org/opends/sdk/controls/MatchedValuesControl.java
index 432d3d4..84a175e 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/controls/MatchedValuesControl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/controls/MatchedValuesControl.java
@@ -86,7 +86,7 @@
     @Override
     public LocalizedIllegalArgumentException visitExtensibleMatchFilter(
         Filter p, String matchingRule, String attributeDescription,
-        ByteSequence assertionValue, boolean dnAttributes)
+        ByteString assertionValue, boolean dnAttributes)
     {
       if (dnAttributes)
       {
@@ -123,7 +123,7 @@
 
     @Override
     public LocalizedIllegalArgumentException visitUnrecognizedFilter(
-        Filter p, byte filterTag, ByteSequence filterBytes)
+        Filter p, byte filterTag, ByteString filterBytes)
     {
       LocalizableMessage message = ERR_MVFILTER_BAD_FILTER_UNRECOGNIZED.get(p
           .toString(), filterTag);
@@ -239,7 +239,7 @@
   /**
    * Creates a new matched values control using the default OID and the
    * provided criticality and set of filters.
-   * 
+   *
    * @param isCritical
    *          Indicates whether this control should be considered
    *          critical to the operation processing.
@@ -287,7 +287,7 @@
   /**
    * Returns an {@code Iterable} containing the list of filters
    * associated with this matched values control.
-   * 
+   *
    * @return An {@code Iterable} containing the list of filters.
    */
   public Iterable<Filter> getFilters()
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPUtils.java b/opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPUtils.java
index 48e11b2..872c9da 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPUtils.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/ldap/LDAPUtils.java
@@ -37,6 +37,7 @@
 import java.util.List;
 
 import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
 import org.opends.sdk.Filter;
 import org.opends.sdk.FilterVisitor;
 import org.opends.sdk.asn1.ASN1Reader;
@@ -82,7 +83,7 @@
 
 
     public IOException visitApproxMatchFilter(ASN1Writer writer,
-        String attributeDescription, ByteSequence assertionValue)
+        String attributeDescription, ByteString assertionValue)
     {
       try
       {
@@ -101,7 +102,7 @@
 
 
     public IOException visitEqualityMatchFilter(ASN1Writer writer,
-        String attributeDescription, ByteSequence assertionValue)
+        String attributeDescription, ByteString assertionValue)
     {
       try
       {
@@ -121,7 +122,7 @@
 
     public IOException visitExtensibleMatchFilter(ASN1Writer writer,
         String matchingRule, String attributeDescription,
-        ByteSequence assertionValue, boolean dnAttributes)
+        ByteString assertionValue, boolean dnAttributes)
     {
       try
       {
@@ -158,7 +159,7 @@
 
 
     public IOException visitGreaterOrEqualFilter(ASN1Writer writer,
-        String attributeDescription, ByteSequence assertionValue)
+        String attributeDescription, ByteString assertionValue)
     {
       try
       {
@@ -177,7 +178,7 @@
 
 
     public IOException visitLessOrEqualFilter(ASN1Writer writer,
-        String attributeDescription, ByteSequence assertionValue)
+        String attributeDescription, ByteString assertionValue)
     {
       try
       {
@@ -260,8 +261,8 @@
 
 
     public IOException visitSubstringsFilter(ASN1Writer writer,
-        String attributeDescription, ByteSequence initialSubstring,
-        List<ByteSequence> anySubstrings, ByteSequence finalSubstring)
+        String attributeDescription, ByteString initialSubstring,
+        List<ByteString> anySubstrings, ByteString finalSubstring)
     {
       try
       {
@@ -297,7 +298,7 @@
 
 
     public IOException visitUnrecognizedFilter(ASN1Writer writer,
-        byte filterTag, ByteSequence filterBytes)
+        byte filterTag, ByteString filterBytes)
     {
       try
       {
@@ -481,7 +482,7 @@
       throws IOException
   {
     String attributeDescription;
-    ByteSequence assertionValue;
+    ByteString assertionValue;
 
     reader.readStartSequence(TYPE_FILTER_APPROXIMATE);
     try
@@ -505,7 +506,7 @@
       throws IOException
   {
     String attributeDescription;
-    ByteSequence assertionValue;
+    ByteString assertionValue;
 
     reader.readStartSequence(TYPE_FILTER_EQUALITY);
     try
@@ -531,7 +532,7 @@
     String matchingRule;
     String attributeDescription;
     boolean dnAttributes;
-    ByteSequence assertionValue;
+    ByteString assertionValue;
 
     reader.readStartSequence(TYPE_FILTER_EXTENSIBLE_MATCH);
     try
@@ -572,7 +573,7 @@
       ASN1Reader reader) throws IOException
   {
     String attributeDescription;
-    ByteSequence assertionValue;
+    ByteString assertionValue;
 
     reader.readStartSequence(TYPE_FILTER_GREATER_OR_EQUAL);
     try
@@ -595,7 +596,7 @@
       throws IOException
   {
     String attributeDescription;
-    ByteSequence assertionValue;
+    ByteString assertionValue;
 
     reader.readStartSequence(TYPE_FILTER_LESS_OR_EQUAL);
     try
@@ -673,9 +674,9 @@
   private static Filter decodeSubstringsFilter(ASN1Reader reader)
       throws IOException
   {
-    ByteSequence initialSubstring = null;
-    List<ByteSequence> anySubstrings = null;
-    ByteSequence finalSubstring = null;
+    ByteString initialSubstring = null;
+    List<ByteString> anySubstrings = null;
+    ByteString finalSubstring = null;
     String attributeDescription;
 
     reader.readStartSequence(TYPE_FILTER_SUBSTRING);
@@ -694,7 +695,7 @@
         if (reader.hasNextElement()
             && (reader.peekType() == TYPE_SUBANY))
         {
-          anySubstrings = new LinkedList<ByteSequence>();
+          anySubstrings = new LinkedList<ByteString>();
           do
           {
             anySubstrings.add(reader.readOctetString(TYPE_SUBANY));
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractMatchingRuleImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractMatchingRuleImpl.java
index 1ab9e61..3de718d 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractMatchingRuleImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractMatchingRuleImpl.java
@@ -108,7 +108,7 @@
 
 
   public Assertion getAssertion(Schema schema, ByteSequence subInitial,
-      List<ByteSequence> subAnyElements, ByteSequence subFinal)
+      List<? extends ByteSequence> subAnyElements, ByteSequence subFinal)
       throws DecodeException
   {
     return UNDEFINED_ASSERTION;
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractSubstringMatchingRuleImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractSubstringMatchingRuleImpl.java
index e5d2add..785b730 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractSubstringMatchingRuleImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/schema/AbstractSubstringMatchingRuleImpl.java
@@ -235,7 +235,7 @@
 
   @Override
   public Assertion getAssertion(Schema schema, ByteSequence subInitial,
-      List<ByteSequence> subAnyElements, ByteSequence subFinal)
+      List<? extends ByteSequence> subAnyElements, ByteSequence subFinal)
       throws DecodeException
   {
     final ByteString normInitial =
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/schema/AttributeType.java b/opendj-sdk/sdk/src/org/opends/sdk/schema/AttributeType.java
index 0746859..2914a9b 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/schema/AttributeType.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/schema/AttributeType.java
@@ -37,6 +37,7 @@
 import java.util.List;
 import java.util.Map;
 
+import org.opends.sdk.AttributeDescription;
 import org.opends.sdk.LocalizableMessage;
 
 import com.sun.opends.sdk.util.StaticUtils;
@@ -127,6 +128,10 @@
   // The syntax for this attribute type.
   private Syntax syntax;
 
+  // The attribute description representing this attribute type with no
+  // options.
+  private final AttributeDescription attributeDescription;
+
 
 
   AttributeType(String oid, List<String> names, String description,
@@ -169,6 +174,7 @@
 
     this.isObjectClassType = oid.equals("2.5.4.0");
     this.normalizedName = StaticUtils.toLowerCase(getNameOrOID());
+    this.attributeDescription = AttributeDescription.create(this);
   }
 
 
@@ -200,6 +206,21 @@
 
     this.isObjectClassType = oid.equals("2.5.4.0");
     this.normalizedName = StaticUtils.toLowerCase(getNameOrOID());
+    this.attributeDescription = AttributeDescription.create(this);
+  }
+
+
+
+  /**
+   * Returns an attribute description comprising of this attribute type
+   * and no options.
+   *
+   * @return An attribute description comprising of this attribute type
+   *         and no options.
+   */
+  public AttributeDescription asAttributeDescription()
+  {
+    return attributeDescription;
   }
 
 
@@ -753,8 +774,8 @@
         // never fail since the core schema is non-strict and will
         // substitute the syntax if required.
         syntax = Schema.getCoreSchema().getSyntax(syntaxOID);
-        final LocalizableMessage message = WARN_ATTR_TYPE_NOT_DEFINED.get(
-            getNameOrOID(), syntaxOID, syntax.toString());
+        final LocalizableMessage message = WARN_ATTR_TYPE_NOT_DEFINED
+            .get(getNameOrOID(), syntaxOID, syntax.toString());
         warnings.add(message);
       }
       else
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchema.java b/opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchema.java
index 0117a13..7ebcaa1 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchema.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchema.java
@@ -2269,7 +2269,7 @@
    *
    * @return A reference to the {@code supportedSASLMechanisms} Attribute Type.
    */
-  public static AttributeType getSupportedSaslMechanismsAttributeType()
+  public static AttributeType getSupportedSASLMechanismsAttributeType()
   {
     return SUPPORTED_SASL_MECHANISMS_ATTRIBUTE_TYPE;
   }
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchemaImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchemaImpl.java
index 44aee3f..1140a86 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchemaImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/schema/CoreSchemaImpl.java
@@ -32,51 +32,53 @@
 
 import java.util.*;
 
-import org.opends.sdk.LocalizableMessage;
-
-
 
 
 final class CoreSchemaImpl
 {
-  private static final Map<String, List<String>> X500_ORIGIN =
-      Collections.singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+  private static final Map<String, List<String>> X500_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
           .singletonList("X.500"));
-  private static final Map<String, List<String>> RFC2252_ORIGIN =
-      Collections.singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+
+  private static final Map<String, List<String>> RFC2252_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
           .singletonList("RFC 2252"));
-  private static final Map<String, List<String>> RFC3045_ORIGIN =
-      Collections.singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+
+  private static final Map<String, List<String>> RFC3045_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
           .singletonList("RFC 3045"));
-  private static final Map<String, List<String>> RFC3112_ORIGIN =
-      Collections.singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+
+  private static final Map<String, List<String>> RFC3112_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
           .singletonList("RFC 3112"));
-  private static final Map<String, List<String>> RFC4512_ORIGIN =
-      Collections.singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+
+  private static final Map<String, List<String>> RFC4512_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
           .singletonList("RFC 4512"));
-  private static final Map<String, List<String>> RFC4517_ORIGIN =
-      Collections.singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+
+  private static final Map<String, List<String>> RFC4517_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
           .singletonList("RFC 4517"));
-  private static final Map<String, List<String>> RFC4519_ORIGIN =
-      Collections.singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+
+  private static final Map<String, List<String>> RFC4519_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
           .singletonList("RFC 4519"));
-  private static final Map<String, List<String>> RFC4530_ORIGIN =
-      Collections.singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+
+  private static final Map<String, List<String>> RFC4530_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
           .singletonList("RFC 4530"));
-  static final Map<String, List<String>> OPENDS_ORIGIN =
-      Collections.singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+
+  static final Map<String, List<String>> OPENDS_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
           .singletonList("OpenDS Directory Server"));
+
   private static final String EMPTY_STRING = "".intern();
-  private static final Set<String> EMPTY_STRING_SET =
-      Collections.emptySet();
+
+  private static final Set<String> EMPTY_STRING_SET = Collections
+      .emptySet();
 
   private static final Schema SINGLETON;
 
-  // Package private so that we can check for warnings in the unit
-  // tests.
-  static final List<LocalizableMessage> CORE_SCHEMA_WARNINGS =
-      new LinkedList<LocalizableMessage>();
-
   static
   {
     final SchemaBuilder builder = new SchemaBuilder();
@@ -91,7 +93,7 @@
     addRFC3112(builder);
     addSunProprietary(builder);
 
-    SINGLETON = builder.toSchema(CORE_SCHEMA_WARNINGS).nonStrict();
+    SINGLETON = builder.toSchema().nonStrict();
   }
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/schema/GenerateCoreSchema.java b/opendj-sdk/sdk/src/org/opends/sdk/schema/GenerateCoreSchema.java
index 2928bce..0e2d647 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/schema/GenerateCoreSchema.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/schema/GenerateCoreSchema.java
@@ -43,10 +43,12 @@
     return oid.startsWith(SchemaConstants.OID_OPENDS_SERVER_BASE + ".");
   }
 
-  private static final Set<String> ABBREVIATIONS =
-      new HashSet<String>(Arrays.asList("LDAP", "DN", "DIT", "RDN",
-          "JPEG", "OID", "UUID", "IA5", "UID", "UTC", "X500", "X121",
-          "C", "CN", "O", "OU", "L", "DC", "ISDN", "SN", "ST"));
+
+
+  private static final Set<String> ABBREVIATIONS = new HashSet<String>(
+      Arrays.asList("SASL", "LDAP", "DN", "DIT", "RDN", "JPEG", "OID",
+          "UUID", "IA5", "UID", "UTC", "X500", "X121", "C", "CN", "O",
+          "OU", "L", "DC", "ISDN", "SN", "ST"));
 
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRule.java b/opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRule.java
index 301fc52..daed051 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRule.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRule.java
@@ -151,7 +151,7 @@
    *           if the syntax of the value is not valid.
    */
   public Assertion getAssertion(ByteSequence subInitial,
-      List<ByteSequence> subAnyElements, ByteSequence subFinal)
+      List<? extends ByteSequence> subAnyElements, ByteSequence subFinal)
       throws DecodeException
   {
     return impl.getAssertion(schema, subInitial, subAnyElements,
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRuleImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRuleImpl.java
index bd946b4..2c526d2 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRuleImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/schema/MatchingRuleImpl.java
@@ -97,7 +97,7 @@
    *           if an syntax error occured while parsing the value.
    */
   public Assertion getAssertion(Schema schema, ByteSequence subInitial,
-      List<ByteSequence> subAnyElements, ByteSequence subFinal)
+      List<? extends ByteSequence> subAnyElements, ByteSequence subFinal)
       throws DecodeException;
 
 
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/schema/Schema.java b/opendj-sdk/sdk/src/org/opends/sdk/schema/Schema.java
index d045f88..1dcc5b7 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/schema/Schema.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/schema/Schema.java
@@ -36,10 +36,15 @@
 import java.util.Map;
 
 import org.opends.sdk.*;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.SearchRequest;
+import org.opends.sdk.responses.Responses;
+import org.opends.sdk.responses.Result;
 import org.opends.sdk.responses.SearchResultEntry;
 
+import com.sun.opends.sdk.util.ResultChain;
+import com.sun.opends.sdk.util.ResultTransformer;
 import com.sun.opends.sdk.util.StaticUtils;
-import com.sun.opends.sdk.util.Validator;
 
 
 
@@ -291,6 +296,13 @@
 
 
 
+    public Collection<LocalizableMessage> getWarnings()
+    {
+      return Collections.emptyList();
+    }
+
+
+
     public boolean hasAttributeType(String name)
     {
       // In theory a non-strict schema always contains the requested
@@ -480,6 +492,10 @@
 
 
 
+    Collection<LocalizableMessage> getWarnings();
+
+
+
     boolean hasAttributeType(String name);
 
 
@@ -752,6 +768,13 @@
 
 
 
+    public Collection<LocalizableMessage> getWarnings()
+    {
+      return strictImpl.getWarnings();
+    }
+
+
+
     public boolean hasAttributeType(String name)
     {
       // In theory a non-strict schema always contains the requested
@@ -858,6 +881,8 @@
 
     private final SchemaCompatOptions options;
 
+    private final List<LocalizableMessage> warnings;
+
 
 
     private StrictImpl(Map<String, Syntax> numericOID2Syntaxes,
@@ -877,7 +902,7 @@
         Map<String, List<DITStructureRule>> name2StructureRules,
         Map<String, List<NameForm>> objectClass2NameForms,
         Map<String, List<DITStructureRule>> nameForm2StructureRules,
-        SchemaCompatOptions options)
+        SchemaCompatOptions options, List<LocalizableMessage> warnings)
     {
       this.numericOID2Syntaxes = Collections
           .unmodifiableMap(numericOID2Syntaxes);
@@ -913,6 +938,7 @@
       this.nameForm2StructureRules = Collections
           .unmodifiableMap(nameForm2StructureRules);
       this.options = options;
+      this.warnings = Collections.unmodifiableList(warnings);
     }
 
 
@@ -1315,6 +1341,13 @@
 
 
 
+    public Collection<LocalizableMessage> getWarnings()
+    {
+      return warnings;
+    }
+
+
+
     public boolean hasAttributeType(String name)
     {
       if (numericOID2AttributeTypes.containsKey(name))
@@ -1458,6 +1491,294 @@
       ATTR_MATCHING_RULES.toString(), ATTR_NAME_FORMS.toString(),
       ATTR_OBJECT_CLASSES.toString() };
 
+  private static final Filter SUBSCHEMA_FILTER = Filter
+      .newEqualityMatchFilter(CoreSchema.getObjectClassAttributeType()
+          .getNameOrOID(), CoreSchema.getSubschemaObjectClass()
+          .getNameOrOID());
+
+  private static final String[] SUBSCHEMA_SUBENTRY_ATTRS = new String[] { ATTR_SUBSCHEMA_SUBENTRY
+      .toString() };
+
+
+
+  /**
+   * Reads the schema from the Directory Server contained in the named
+   * subschema sub-entry using the provided connection.
+   * <p>
+   * If the requested schema is not returned by the Directory Server
+   * then the request will fail with an {@link EntryNotFoundException}.
+   * More specifically, this method will never return {@code null}.
+   *
+   * @param connection
+   *          A connection to the Directory Server whose schema is to be
+   *          read.
+   * @param name
+   *          The distinguished name of the subschema sub-entry.
+   * @return The schema from the Directory Server.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for
+   *           some reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If the connection does not support search operations.
+   * @throws IllegalStateException
+   *           If the connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} or {@code name} was {@code
+   *           null}.
+   */
+  public static Schema readSchema(Connection connection, DN name)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final SearchRequest request = getReadSchemaSearchRequest(name);
+    final Entry entry = connection.searchSingleEntry(request);
+    return valueOf(entry);
+  }
+
+
+
+  /**
+   * Reads the schema from the Directory Server which applies to the
+   * named entry using the provided connection.
+   * <p>
+   * If the requested entry or its associated schema are not returned by
+   * the Directory Server then the request will fail with an
+   * {@link EntryNotFoundException}. More specifically, this method will
+   * never return {@code null}.
+   * <p>
+   * A typical implementation will first read the {@code
+   * subschemaSubentry} attribute of the entry in order to locate the
+   * schema. However, implementations may choose to perform other
+   * optimizations, such as caching.
+   *
+   * @param connection
+   *          A connection to the Directory Server whose schema is to be
+   *          read.
+   * @param name
+   *          The distinguished name of the entry whose schema is to be
+   *          located.
+   * @return The schema from the Directory Server which applies to the
+   *         named entry.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for
+   *           some reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If the connection does not support search operations.
+   * @throws IllegalStateException
+   *           If the connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} or {@code name} was {@code
+   *           null}.
+   */
+  public static Schema readSchemaForEntry(Connection connection, DN name)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
+    final Entry entry = connection.searchSingleEntry(request);
+    final DN subschemaDN = getSubschemaSubentryDN(name, entry);
+
+    return readSchema(connection, subschemaDN);
+  }
+
+
+
+  private static DN getSubschemaSubentryDN(DN name, final Entry entry)
+      throws ErrorResultException
+  {
+    final Attribute subentryAttr = entry
+        .getAttribute(ATTR_SUBSCHEMA_SUBENTRY);
+
+    if (subentryAttr == null || subentryAttr.isEmpty())
+    {
+      // Did not get the subschema sub-entry attribute.
+      Result result = Responses.newResult(
+          ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED)
+          .setDiagnosticMessage(
+              ERR_NO_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString())
+                  .toString());
+      throw ErrorResultException.wrap(result);
+    }
+
+    String dnString = subentryAttr.iterator().next().toString();
+    DN subschemaDN;
+    try
+    {
+      subschemaDN = DN.valueOf(dnString);
+    }
+    catch (LocalizedIllegalArgumentException e)
+    {
+      Result result = Responses.newResult(
+          ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED)
+          .setDiagnosticMessage(
+              ERR_INVALID_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString(),
+                  dnString, e.getMessageObject()).toString());
+      throw ErrorResultException.wrap(result);
+    }
+    return subschemaDN;
+  }
+
+
+
+  /**
+   * Reads the schema from the Directory Server contained in the named
+   * subschema sub-entry.
+   * <p>
+   * If the requested schema is not returned by the Directory Server
+   * then the request will fail with an {@link EntryNotFoundException}.
+   * More specifically, the returned future will never return {@code
+   * null}.
+   * <p>
+   * Implementations may choose to perform optimizations such as
+   * caching.
+   *
+   * @param <P>
+   *          The type of the additional parameter to the handler's
+   *          methods.
+   * @param connection
+   *          A connection to the Directory Server whose schema is to be
+   *          read.
+   * @param name
+   *          The distinguished name of the subschema sub-entry.
+   * @param handler
+   *          A result handler which can be used to asynchronously
+   *          process the operation result when it is received, may be
+   *          {@code null}.
+   * @param p
+   *          Optional additional handler parameter.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} or {@code name} was {@code
+   *           null}.
+   */
+  public static <P> ResultFuture<Schema> readSchema(
+      AsynchronousConnection connection, DN name,
+      ResultHandler<? super Schema, P> handler, P p)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final SearchRequest request = getReadSchemaSearchRequest(name);
+
+    final ResultTransformer<SearchResultEntry, Schema, P> future = new ResultTransformer<SearchResultEntry, Schema, P>(
+        handler)
+    {
+
+      protected Schema transformResult(SearchResultEntry result)
+          throws ErrorResultException
+      {
+        return valueOf(result);
+      }
+
+    };
+
+    ResultFuture<SearchResultEntry> innerFuture = connection
+        .searchSingleEntry(request, future, p);
+    future.setResultFuture(innerFuture);
+    return future;
+  }
+
+
+
+  /**
+   * Reads the schema from the Directory Server which applies to the
+   * named entry.
+   * <p>
+   * If the requested entry or its associated schema are not returned by
+   * the Directory Server then the request will fail with an
+   * {@link EntryNotFoundException}. More specifically, the returned
+   * future will never return {@code null}.
+   * <p>
+   * A typical implementation will first read the {@code
+   * subschemaSubentry} attribute of the entry in order to locate the
+   * schema. However, implementations may choose to perform other
+   * optimizations, such as caching.
+   *
+   * @param <P>
+   *          The type of the additional parameter to the handler's
+   *          methods.
+   * @param connection
+   *          A connection to the Directory Server whose schema is to be
+   *          read.
+   * @param name
+   *          The distinguished name of the entry whose schema is to be
+   *          located.
+   * @param handler
+   *          A result handler which can be used to asynchronously
+   *          process the operation result when it is received, may be
+   *          {@code null}.
+   * @param p
+   *          Optional additional handler parameter.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} or {@code name} was {@code
+   *           null}.
+   */
+  public static <P> ResultFuture<Schema> readSchemaForEntry(
+      final AsynchronousConnection connection, final DN name,
+      ResultHandler<Schema, P> handler, final P p)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final ResultChain<SearchResultEntry, Schema, P> future = new ResultChain<SearchResultEntry, Schema, P>(
+        handler)
+    {
+
+      protected ResultFuture<Schema> chainResult(
+          SearchResultEntry innerResult,
+          ResultHandler<? super Schema, P> handler)
+          throws ErrorResultException
+      {
+        final DN subschemaDN = getSubschemaSubentryDN(name, innerResult);
+        return readSchema(connection, subschemaDN, handler, p);
+      }
+
+    };
+
+    final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
+    ResultFuture<SearchResultEntry> innerFuture = connection
+        .searchSingleEntry(request, future, p);
+    future.setInnerResultFuture(innerFuture);
+    return future;
+  }
+
+
+
+  // Constructs a search request for retrieving the named subschema
+  // sub-entry.
+  private static SearchRequest getReadSchemaSearchRequest(DN dn)
+  {
+    return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT,
+        SUBSCHEMA_FILTER, SUBSCHEMA_ATTRS);
+  }
+
+
+
+  // Constructs a search request for retrieving the subschemaSubentry
+  // attribute from the named entry.
+  private static SearchRequest getReadSchemaForEntrySearchRequest(DN dn)
+  {
+    return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT,
+        SUBSCHEMA_FILTER, SUBSCHEMA_SUBENTRY_ATTRS);
+  }
+
 
 
   /**
@@ -1520,62 +1841,19 @@
 
 
   /**
-   * Reads the schema associated with the provided entry from an LDAP
-   * Directory Server.
+   * Parses the provided entry as a subschema subentry. Any problems
+   * encountered while parsing the entry can be retrieved using the
+   * returned schema's {@link #getWarnings()} method.
    *
-   * @param connection
-   *          The connection to the Directory Server.
-   * @param dn
-   *          The name of the entry whose schema is to be retrieved.
-   * @param warnings
-   *          A list to which any warning messages encountered while
-   *          decoding the schema should be appended.
-   * @return The schema.
-   * @throws LocalizedIllegalArgumentException
-   *           If {@code dn} could not be decoded using the default
-   *           schema.
-   * @throws ErrorResultException
-   *           If the server returned an error result code.
-   * @throws InterruptedException
-   *           If the current thread was interrupted while waiting.
-   * @throws SchemaNotFoundException
-   *           If the requested schema was not found in the Directory
-   *           Server.
+   * @param entry
+   *          The subschema subentry to be parsed.
+   * @return The parsed schema.
    */
-  public static Schema getSchema(Connection connection, String dn,
-      List<LocalizableMessage> warnings) throws ErrorResultException,
-      InterruptedException, LocalizedIllegalArgumentException,
-      SchemaNotFoundException
+  public static Schema valueOf(Entry entry)
   {
-    Validator.ensureNotNull(connection, dn, warnings);
-    SearchResultEntry result = connection.readEntry(dn,
-        ATTR_SUBSCHEMA_SUBENTRY.toString());
-    Attribute subentryAttr;
-    if ((subentryAttr = result.getAttribute(ATTR_SUBSCHEMA_SUBENTRY)) == null
-        || subentryAttr.isEmpty())
-    {
-      throw new SchemaNotFoundException(ERR_NO_SUBSCHEMA_SUBENTRY_ATTR
-          .get(dn));
-    }
-
-    String subschemaDNString = subentryAttr.iterator().next()
-        .toString();
-    DN subschemaDN;
-    try
-    {
-      subschemaDN = DN.valueOf(subschemaDNString);
-    }
-    catch (LocalizedIllegalArgumentException e)
-    {
-      throw new SchemaNotFoundException(
-          ERR_INVALID_SUBSCHEMA_SUBENTRY_ATTR.get(dn,
-              subschemaDNString, e.getMessageObject()));
-    }
-    result = connection.readEntry(subschemaDN, SUBSCHEMA_ATTRS);
-
     final SchemaBuilder builder = new SchemaBuilder();
-    Attribute attr = result.getAttribute(ATTR_LDAP_SYNTAXES);
 
+    Attribute attr = entry.getAttribute(ATTR_LDAP_SYNTAXES);
     if (attr != null)
     {
       for (final ByteString def : attr)
@@ -1586,12 +1864,12 @@
         }
         catch (final LocalizedIllegalArgumentException e)
         {
-          warnings.add(e.getMessageObject());
+          builder.addWarning(e.getMessageObject());
         }
       }
     }
 
-    attr = result.getAttribute(ATTR_ATTRIBUTE_TYPES);
+    attr = entry.getAttribute(ATTR_ATTRIBUTE_TYPES);
     if (attr != null)
     {
       for (final ByteString def : attr)
@@ -1602,12 +1880,12 @@
         }
         catch (final LocalizedIllegalArgumentException e)
         {
-          warnings.add(e.getMessageObject());
+          builder.addWarning(e.getMessageObject());
         }
       }
     }
 
-    attr = result.getAttribute(ATTR_OBJECT_CLASSES);
+    attr = entry.getAttribute(ATTR_OBJECT_CLASSES);
     if (attr != null)
     {
       for (final ByteString def : attr)
@@ -1618,12 +1896,12 @@
         }
         catch (final LocalizedIllegalArgumentException e)
         {
-          warnings.add(e.getMessageObject());
+          builder.addWarning(e.getMessageObject());
         }
       }
     }
 
-    attr = result.getAttribute(ATTR_MATCHING_RULE_USE);
+    attr = entry.getAttribute(ATTR_MATCHING_RULE_USE);
     if (attr != null)
     {
       for (final ByteString def : attr)
@@ -1634,12 +1912,12 @@
         }
         catch (final LocalizedIllegalArgumentException e)
         {
-          warnings.add(e.getMessageObject());
+          builder.addWarning(e.getMessageObject());
         }
       }
     }
 
-    attr = result.getAttribute(ATTR_MATCHING_RULES);
+    attr = entry.getAttribute(ATTR_MATCHING_RULES);
     if (attr != null)
     {
       for (final ByteString def : attr)
@@ -1650,12 +1928,12 @@
         }
         catch (final LocalizedIllegalArgumentException e)
         {
-          warnings.add(e.getMessageObject());
+          builder.addWarning(e.getMessageObject());
         }
       }
     }
 
-    attr = result.getAttribute(ATTR_DIT_CONTENT_RULES);
+    attr = entry.getAttribute(ATTR_DIT_CONTENT_RULES);
     if (attr != null)
     {
       for (final ByteString def : attr)
@@ -1666,12 +1944,12 @@
         }
         catch (final LocalizedIllegalArgumentException e)
         {
-          warnings.add(e.getMessageObject());
+          builder.addWarning(e.getMessageObject());
         }
       }
     }
 
-    attr = result.getAttribute(ATTR_DIT_STRUCTURE_RULES);
+    attr = entry.getAttribute(ATTR_DIT_STRUCTURE_RULES);
     if (attr != null)
     {
       for (final ByteString def : attr)
@@ -1682,12 +1960,12 @@
         }
         catch (final LocalizedIllegalArgumentException e)
         {
-          warnings.add(e.getMessageObject());
+          builder.addWarning(e.getMessageObject());
         }
       }
     }
 
-    attr = result.getAttribute(ATTR_NAME_FORMS);
+    attr = entry.getAttribute(ATTR_NAME_FORMS);
     if (attr != null)
     {
       for (final ByteString def : attr)
@@ -1698,12 +1976,12 @@
         }
         catch (final LocalizedIllegalArgumentException e)
         {
-          warnings.add(e.getMessageObject());
+          builder.addWarning(e.getMessageObject());
         }
       }
     }
 
-    return builder.toSchema(warnings);
+    return builder.toSchema();
   }
 
 
@@ -1758,7 +2036,7 @@
       Map<String, List<DITStructureRule>> name2StructureRules,
       Map<String, List<NameForm>> objectClass2NameForms,
       Map<String, List<DITStructureRule>> nameForm2StructureRules,
-      SchemaCompatOptions options)
+      SchemaCompatOptions options, List<LocalizableMessage> warnings)
   {
     impl = new StrictImpl(numericOID2Syntaxes,
         numericOID2MatchingRules, numericOID2MatchingRuleUses,
@@ -1767,7 +2045,7 @@
         id2StructureRules, name2MatchingRules, name2MatchingRuleUses,
         name2AttributeTypes, name2ObjectClasses, name2NameForms,
         name2ContentRules, name2StructureRules, objectClass2NameForms,
-        nameForm2StructureRules, options);
+        nameForm2StructureRules, options, warnings);
   }
 
 
@@ -2205,6 +2483,20 @@
 
 
   /**
+   * Returns an unmodifiable collection containing all of the warnings
+   * that were detected when this schema was constructed.
+   *
+   * @return An unmodifiable collection containing all of the warnings
+   *         that were detected when this schema was constructed.
+   */
+  public Collection<LocalizableMessage> getWarnings()
+  {
+    return impl.getWarnings();
+  }
+
+
+
+  /**
    * Indicates whether or not this schema contains an attribute type
    * with the specified name or numeric OID.
    *
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaBuilder.java b/opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaBuilder.java
index 1496309..8516737 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaBuilder.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaBuilder.java
@@ -51,23 +51,43 @@
 {
 
   private Map<Integer, DITStructureRule> id2StructureRules;
+
   private Map<String, List<AttributeType>> name2AttributeTypes;
+
   private Map<String, List<DITContentRule>> name2ContentRules;
+
   private Map<String, List<MatchingRule>> name2MatchingRules;
+
   private Map<String, List<MatchingRuleUse>> name2MatchingRuleUses;
+
   private Map<String, List<NameForm>> name2NameForms;
+
   private Map<String, List<ObjectClass>> name2ObjectClasses;
+
   private Map<String, List<DITStructureRule>> name2StructureRules;
+
   private Map<String, List<DITStructureRule>> nameForm2StructureRules;
+
   private Map<String, AttributeType> numericOID2AttributeTypes;
+
   private Map<String, DITContentRule> numericOID2ContentRules;
+
   private Map<String, MatchingRule> numericOID2MatchingRules;
+
   private Map<String, MatchingRuleUse> numericOID2MatchingRuleUses;
+
   private Map<String, NameForm> numericOID2NameForms;
+
   private Map<String, ObjectClass> numericOID2ObjectClasses;
+
   private Map<String, Syntax> numericOID2Syntaxes;
+
   private Map<String, List<NameForm>> objectClass2NameForms;
+
   private SchemaCompatOptions options;
+
+  private List<LocalizableMessage> warnings;
+
   private Schema schema;
 
 
@@ -137,8 +157,8 @@
       {
         // This means that the definition was empty or contained only
         // whitespace. That is illegal.
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE.get();
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE
+            .get();
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -147,9 +167,8 @@
       final char c = reader.read();
       if (c != '(')
       {
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS.get(
-                definition, (reader.pos() - 1), String.valueOf(c));
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -173,8 +192,8 @@
       boolean isCollective = false;
       boolean isNoUserModification = false;
       AttributeUsage attributeUsage = AttributeUsage.USER_APPLICATIONS;
-      Map<String, List<String>> extraProperties =
-          Collections.emptyMap();
+      Map<String, List<String>> extraProperties = Collections
+          .emptyMap();
 
       // At this point, we should have a pretty specific syntax that
       // describes what may come next, but some of the components are
@@ -312,9 +331,8 @@
           }
           else
           {
-            final LocalizableMessage message =
-                WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE.get(
-                    String.valueOf(oid), usageStr);
+            final LocalizableMessage message = WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE
+                .get(String.valueOf(oid), usageStr);
             throw new LocalizedIllegalArgumentException(message);
           }
         }
@@ -334,25 +352,25 @@
         }
         else
         {
-          final LocalizableMessage message =
-              ERR_ATTR_SYNTAX_ILLEGAL_TOKEN.get(tokenName);
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
           throw new LocalizedIllegalArgumentException(message);
         }
       }
 
-      final List<String> approxRules =
-          extraProperties.get(SCHEMA_PROPERTY_APPROX_RULE);
+      final List<String> approxRules = extraProperties
+          .get(SCHEMA_PROPERTY_APPROX_RULE);
       if (approxRules != null && !approxRules.isEmpty())
       {
         approximateMatchingRule = approxRules.get(0);
       }
 
-      final AttributeType attrType =
-          new AttributeType(oid, names, description, isObsolete,
-              superiorType, equalityMatchingRule, orderingMatchingRule,
-              substringMatchingRule, approximateMatchingRule, syntax,
-              isSingleValue, isCollective, isNoUserModification,
-              attributeUsage, extraProperties, definition);
+      final AttributeType attrType = new AttributeType(oid, names,
+          description, isObsolete, superiorType, equalityMatchingRule,
+          orderingMatchingRule, substringMatchingRule,
+          approximateMatchingRule, syntax, isSingleValue, isCollective,
+          isNoUserModification, attributeUsage, extraProperties,
+          definition);
 
       addAttributeType(attrType, overwrite);
     }
@@ -433,12 +451,11 @@
       Map<String, List<String>> extraProperties, boolean overwrite)
       throws ConflictingSchemaElementException
   {
-    final AttributeType attrType =
-        new AttributeType(oid, names, description, obsolete,
-            superiorType, equalityMatchingRule, orderingMatchingRule,
-            substringMatchingRule, approximateMatchingRule, syntax,
-            singleValue, collective, noUserModification,
-            attributeUsage, extraProperties, null);
+    final AttributeType attrType = new AttributeType(oid, names,
+        description, obsolete, superiorType, equalityMatchingRule,
+        orderingMatchingRule, substringMatchingRule,
+        approximateMatchingRule, syntax, singleValue, collective,
+        noUserModification, attributeUsage, extraProperties, null);
     addAttributeType(attrType, overwrite);
     return this;
   }
@@ -481,7 +498,8 @@
       {
         // This means that the value was empty or contained only
         // whitespace. That is illegal.
-        final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_EMPTY_VALUE.get();
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_EMPTY_VALUE
+            .get();
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -490,9 +508,8 @@
       final char c = reader.read();
       if (c != '(')
       {
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS.get(
-                definition, (reader.pos() - 1), String.valueOf(c));
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -510,8 +527,8 @@
       Set<String> optionalAttributes = Collections.emptySet();
       Set<String> prohibitedAttributes = Collections.emptySet();
       Set<String> requiredAttributes = Collections.emptySet();
-      Map<String, List<String>> extraProperties =
-          Collections.emptyMap();
+      Map<String, List<String>> extraProperties = Collections
+          .emptyMap();
 
       // At this point, we should have a pretty specific syntax that
       // describes what may come next, but some of the components are
@@ -580,17 +597,16 @@
         }
         else
         {
-          final LocalizableMessage message =
-              ERR_ATTR_SYNTAX_ILLEGAL_TOKEN.get(tokenName);
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
           throw new LocalizedIllegalArgumentException(message);
         }
       }
 
-      final DITContentRule rule =
-          new DITContentRule(structuralClass, names, description,
-              isObsolete, auxiliaryClasses, optionalAttributes,
-              prohibitedAttributes, requiredAttributes,
-              extraProperties, definition);
+      final DITContentRule rule = new DITContentRule(structuralClass,
+          names, description, isObsolete, auxiliaryClasses,
+          optionalAttributes, prohibitedAttributes, requiredAttributes,
+          extraProperties, definition);
       addDITContentRule(rule, overwrite);
     }
     catch (final DecodeException e)
@@ -648,11 +664,10 @@
       Map<String, List<String>> extraProperties, boolean overwrite)
       throws ConflictingSchemaElementException
   {
-    final DITContentRule rule =
-        new DITContentRule(structuralClass, names, description,
-            obsolete, auxiliaryClasses, optionalAttributes,
-            prohibitedAttributes, requiredAttributes, extraProperties,
-            null);
+    final DITContentRule rule = new DITContentRule(structuralClass,
+        names, description, obsolete, auxiliaryClasses,
+        optionalAttributes, prohibitedAttributes, requiredAttributes,
+        extraProperties, null);
     addDITContentRule(rule, overwrite);
     return this;
   }
@@ -694,9 +709,9 @@
       Map<String, List<String>> extraProperties, boolean overwrite)
       throws ConflictingSchemaElementException
   {
-    final DITStructureRule rule =
-        new DITStructureRule(ruleID, names, description, obsolete,
-            nameForm, superiorRules, extraProperties, null);
+    final DITStructureRule rule = new DITStructureRule(ruleID, names,
+        description, obsolete, nameForm, superiorRules,
+        extraProperties, null);
     addDITStructureRule(rule, overwrite);
     return this;
   }
@@ -739,7 +754,8 @@
       {
         // This means that the value was empty or contained only
         // whitespace. That is illegal.
-        final LocalizableMessage message = ERR_ATTR_SYNTAX_DSR_EMPTY_VALUE.get();
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DSR_EMPTY_VALUE
+            .get();
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -748,9 +764,8 @@
       final char c = reader.read();
       if (c != '(')
       {
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS.get(
-                definition, (reader.pos() - 1), String.valueOf(c));
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -766,8 +781,8 @@
       boolean isObsolete = false;
       String nameForm = null;
       Set<Integer> superiorRules = Collections.emptySet();
-      Map<String, List<String>> extraProperties =
-          Collections.emptyMap();
+      Map<String, List<String>> extraProperties = Collections
+          .emptyMap();
 
       // At this point, we should have a pretty specific syntax that
       // describes what may come next, but some of the components are
@@ -828,22 +843,22 @@
         }
         else
         {
-          final LocalizableMessage message =
-              ERR_ATTR_SYNTAX_ILLEGAL_TOKEN.get(tokenName);
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
           throw new LocalizedIllegalArgumentException(message);
         }
       }
 
       if (nameForm == null)
       {
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM.get(definition);
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM
+            .get(definition);
         throw new LocalizedIllegalArgumentException(message);
       }
 
-      final DITStructureRule rule =
-          new DITStructureRule(ruleID, names, description, isObsolete,
-              nameForm, superiorRules, extraProperties, definition);
+      final DITStructureRule rule = new DITStructureRule(ruleID, names,
+          description, isObsolete, nameForm, superiorRules,
+          extraProperties, definition);
       addDITStructureRule(rule, overwrite);
     }
     catch (final DecodeException e)
@@ -881,16 +896,16 @@
   {
     Validator.ensureNotNull((Object) enumerations);
 
-    final EnumSyntaxImpl enumImpl =
-        new EnumSyntaxImpl(oid, Arrays.asList(enumerations));
-    final Syntax enumSyntax =
-        new Syntax(oid, description, Collections.singletonMap("X-ENUM",
-            Arrays.asList(enumerations)), null, enumImpl);
-    final MatchingRule enumOMR =
-        new MatchingRule(enumImpl.getOrderingMatchingRule(),
-            Collections.singletonList(OMR_GENERIC_ENUM_NAME + oid), "",
-            false, oid, CoreSchemaImpl.OPENDS_ORIGIN, null,
-            new EnumOrderingMatchingRule(enumImpl));
+    final EnumSyntaxImpl enumImpl = new EnumSyntaxImpl(oid, Arrays
+        .asList(enumerations));
+    final Syntax enumSyntax = new Syntax(oid, description, Collections
+        .singletonMap("X-ENUM", Arrays.asList(enumerations)), null,
+        enumImpl);
+    final MatchingRule enumOMR = new MatchingRule(enumImpl
+        .getOrderingMatchingRule(), Collections
+        .singletonList(OMR_GENERIC_ENUM_NAME + oid), "", false, oid,
+        CoreSchemaImpl.OPENDS_ORIGIN, null,
+        new EnumOrderingMatchingRule(enumImpl));
 
     addSyntax(enumSyntax, overwrite);
     try
@@ -941,7 +956,8 @@
       {
         // This means that the value was empty or contained only
         // whitespace. That is illegal.
-        final LocalizableMessage message = ERR_ATTR_SYNTAX_MR_EMPTY_VALUE.get();
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MR_EMPTY_VALUE
+            .get();
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -950,9 +966,8 @@
       final char c = reader.read();
       if (c != '(')
       {
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS.get(
-                definition, (reader.pos() - 1), String.valueOf(c));
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -967,8 +982,8 @@
       String description = "".intern();
       boolean isObsolete = false;
       String syntax = null;
-      Map<String, List<String>> extraProperties =
-          Collections.emptyMap();
+      Map<String, List<String>> extraProperties = Collections
+          .emptyMap();
 
       // At this point, we should have a pretty specific syntax that
       // describes what may come next, but some of the components are
@@ -1025,8 +1040,8 @@
         }
         else
         {
-          final LocalizableMessage message =
-              ERR_ATTR_SYNTAX_ILLEGAL_TOKEN.get(tokenName);
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
           throw new LocalizedIllegalArgumentException(message);
         }
       }
@@ -1034,8 +1049,8 @@
       // Make sure that a syntax was specified.
       if (syntax == null)
       {
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_MR_NO_SYNTAX.get(definition);
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MR_NO_SYNTAX
+            .get(definition);
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -1087,9 +1102,9 @@
       throws ConflictingSchemaElementException
   {
     Validator.ensureNotNull(implementation);
-    final MatchingRule matchingRule =
-        new MatchingRule(oid, names, description, obsolete,
-            assertionSyntax, extraProperties, null, implementation);
+    final MatchingRule matchingRule = new MatchingRule(oid, names,
+        description, obsolete, assertionSyntax, extraProperties, null,
+        implementation);
     addMatchingRule(matchingRule, overwrite);
     return this;
   }
@@ -1132,7 +1147,8 @@
       {
         // This means that the value was empty or contained only
         // whitespace. That is illegal.
-        final LocalizableMessage message = ERR_ATTR_SYNTAX_MRUSE_EMPTY_VALUE.get();
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MRUSE_EMPTY_VALUE
+            .get();
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -1141,9 +1157,8 @@
       final char c = reader.read();
       if (c != '(')
       {
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS.get(
-                definition, (reader.pos() - 1), String.valueOf(c));
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -1158,8 +1173,8 @@
       String description = "".intern();
       boolean isObsolete = false;
       Set<String> attributes = null;
-      Map<String, List<String>> extraProperties =
-          Collections.emptyMap();
+      Map<String, List<String>> extraProperties = Collections
+          .emptyMap();
 
       // At this point, we should have a pretty specific syntax that
       // describes what may come next, but some of the components are
@@ -1216,8 +1231,8 @@
         }
         else
         {
-          final LocalizableMessage message =
-              ERR_ATTR_SYNTAX_ILLEGAL_TOKEN.get(tokenName);
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
           throw new LocalizedIllegalArgumentException(message);
         }
       }
@@ -1225,14 +1240,14 @@
       // Make sure that the set of attributes was defined.
       if (attributes == null || attributes.size() == 0)
       {
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_MRUSE_NO_ATTR.get(definition);
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MRUSE_NO_ATTR
+            .get(definition);
         throw new LocalizedIllegalArgumentException(message);
       }
 
-      final MatchingRuleUse use =
-          new MatchingRuleUse(oid, names, description, isObsolete,
-              attributes, extraProperties, definition);
+      final MatchingRuleUse use = new MatchingRuleUse(oid, names,
+          description, isObsolete, attributes, extraProperties,
+          definition);
       addMatchingRuleUse(use, overwrite);
     }
     catch (final DecodeException e)
@@ -1278,9 +1293,8 @@
       Map<String, List<String>> extraProperties, boolean overwrite)
       throws ConflictingSchemaElementException
   {
-    final MatchingRuleUse use =
-        new MatchingRuleUse(oid, names, description, obsolete,
-            attributeOIDs, extraProperties, null);
+    final MatchingRuleUse use = new MatchingRuleUse(oid, names,
+        description, obsolete, attributeOIDs, extraProperties, null);
     addMatchingRuleUse(use, overwrite);
     return this;
   }
@@ -1321,8 +1335,8 @@
       {
         // This means that the value was empty or contained only
         // whitespace. That is illegal.
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_NAME_FORM_EMPTY_VALUE.get();
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_EMPTY_VALUE
+            .get();
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -1331,9 +1345,8 @@
       final char c = reader.read();
       if (c != '(')
       {
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS.get(
-                definition, (reader.pos() - 1), c);
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), c);
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -1350,8 +1363,8 @@
       String structuralClass = null;
       Set<String> optionalAttributes = Collections.emptySet();
       Set<String> requiredAttributes = null;
-      Map<String, List<String>> extraProperties =
-          Collections.emptyMap();
+      Map<String, List<String>> extraProperties = Collections
+          .emptyMap();
 
       // At this point, we should have a pretty specific syntax that
       // describes what may come next, but some of the components are
@@ -1416,8 +1429,8 @@
         }
         else
         {
-          final LocalizableMessage message =
-              ERR_ATTR_SYNTAX_ILLEGAL_TOKEN.get(tokenName);
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
           throw new LocalizedIllegalArgumentException(message);
         }
       }
@@ -1426,23 +1439,21 @@
       // it cannot be valid.
       if (structuralClass == null)
       {
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS
-                .get(definition);
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS
+            .get(definition);
         throw new LocalizedIllegalArgumentException(message);
       }
 
       if (requiredAttributes == null || requiredAttributes.size() == 0)
       {
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_NAME_FORM_NO_REQUIRED_ATTR.get(definition);
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_NO_REQUIRED_ATTR
+            .get(definition);
         throw new LocalizedIllegalArgumentException(message);
       }
 
-      final NameForm nameForm =
-          new NameForm(oid, names, description, isObsolete,
-              structuralClass, requiredAttributes, optionalAttributes,
-              extraProperties, definition);
+      final NameForm nameForm = new NameForm(oid, names, description,
+          isObsolete, structuralClass, requiredAttributes,
+          optionalAttributes, extraProperties, definition);
       addNameForm(nameForm, overwrite);
     }
     catch (final DecodeException e)
@@ -1492,10 +1503,9 @@
       Map<String, List<String>> extraProperties, boolean overwrite)
       throws ConflictingSchemaElementException
   {
-    final NameForm nameForm =
-        new NameForm(oid, names, description, obsolete,
-            structuralClass, requiredAttributes, optionalAttributes,
-            extraProperties, null);
+    final NameForm nameForm = new NameForm(oid, names, description,
+        obsolete, structuralClass, requiredAttributes,
+        optionalAttributes, extraProperties, null);
     addNameForm(nameForm, overwrite);
     return this;
   }
@@ -1537,8 +1547,8 @@
       {
         // This means that the value was empty or contained only
         // whitespace. That is illegal.
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_OBJECTCLASS_EMPTY_VALUE.get();
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_OBJECTCLASS_EMPTY_VALUE
+            .get();
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -1547,9 +1557,8 @@
       final char c = reader.read();
       if (c != '(')
       {
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS.get(
-                definition, (reader.pos() - 1), String.valueOf(c));
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -1567,8 +1576,8 @@
       Set<String> requiredAttributes = Collections.emptySet();
       Set<String> optionalAttributes = Collections.emptySet();
       ObjectClassType objectClassType = ObjectClassType.STRUCTURAL;
-      Map<String, List<String>> extraProperties =
-          Collections.emptyMap();
+      Map<String, List<String>> extraProperties = Collections
+          .emptyMap();
 
       // At this point, we should have a pretty specific syntax that
       // describes what may come next, but some of the components are
@@ -1653,8 +1662,8 @@
         }
         else
         {
-          final LocalizableMessage message =
-              ERR_ATTR_SYNTAX_ILLEGAL_TOKEN.get(tokenName);
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
           throw new LocalizedIllegalArgumentException(message);
         }
       }
@@ -1917,8 +1926,8 @@
       {
         // This means that the value was empty or contained only
         // whitespace. That is illegal.
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE.get();
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE
+            .get();
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -1927,9 +1936,8 @@
       final char c = reader.read();
       if (c != '(')
       {
-        final LocalizableMessage message =
-            ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS.get(
-                definition, (reader.pos() - 1), String.valueOf(c));
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
         throw new LocalizedIllegalArgumentException(message);
       }
 
@@ -1941,8 +1949,8 @@
       final String oid = SchemaUtils.readOID(reader);
 
       String description = "".intern();
-      Map<String, List<String>> extraProperties =
-          Collections.emptyMap();
+      Map<String, List<String>> extraProperties = Collections
+          .emptyMap();
 
       // At this point, we should have a pretty specific syntax that
       // describes what may come next, but some of the components are
@@ -1983,8 +1991,8 @@
         }
         else
         {
-          final LocalizableMessage message =
-              ERR_ATTR_SYNTAX_ILLEGAL_TOKEN.get(tokenName);
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
           throw new LocalizedIllegalArgumentException(message);
         }
       }
@@ -1995,17 +2003,15 @@
       {
         if (property.getKey().equalsIgnoreCase("x-enum"))
         {
-          final EnumSyntaxImpl enumImpl =
-              new EnumSyntaxImpl(oid, property.getValue());
-          final Syntax enumSyntax =
-              new Syntax(oid, description, extraProperties, definition,
-                  enumImpl);
-          final MatchingRule enumOMR =
-              new MatchingRule(enumImpl.getOrderingMatchingRule(),
-                  Collections
-                      .singletonList(OMR_GENERIC_ENUM_NAME + oid), "",
-                  false, oid, CoreSchemaImpl.OPENDS_ORIGIN, null,
-                  new EnumOrderingMatchingRule(enumImpl));
+          final EnumSyntaxImpl enumImpl = new EnumSyntaxImpl(oid,
+              property.getValue());
+          final Syntax enumSyntax = new Syntax(oid, description,
+              extraProperties, definition, enumImpl);
+          final MatchingRule enumOMR = new MatchingRule(enumImpl
+              .getOrderingMatchingRule(), Collections
+              .singletonList(OMR_GENERIC_ENUM_NAME + oid), "", false,
+              oid, CoreSchemaImpl.OPENDS_ORIGIN, null,
+              new EnumOrderingMatchingRule(enumImpl));
 
           addSyntax(enumSyntax, overwrite);
           addMatchingRule(enumOMR, overwrite);
@@ -2240,9 +2246,6 @@
    * contained in this schema builder as well as the same set of schema
    * compatibility options.
    * <p>
-   * Any errors that were detected while validating the schema will be
-   * ignored.
-   * <p>
    * When this method returns this schema builder is empty and contains
    * a default set of compatibility options.
    *
@@ -2252,38 +2255,17 @@
    */
   public Schema toSchema()
   {
-    return toSchema(null);
+    validate();
+    final Schema builtSchema = schema;
+    initBuilder();
+    return builtSchema;
   }
 
 
 
-  /**
-   * Returns a {@code Schema} containing all of the schema elements
-   * contained in this schema builder as well as the same set of schema
-   * compatibility options.
-   * <p>
-   * When this method returns this schema builder is empty and contains
-   * a default set of compatibility options.
-   *
-   * @param errorMessages
-   *          A list into which any errors that were detected while
-   *          validating the schema will be placed, may be {@code null}
-   *          in which case any errors will be ignored.
-   * @return A {@code Schema} containing all of the schema elements
-   *         contained in this schema builder as well as the same set of
-   *         schema compatibility options
-   */
-  public Schema toSchema(List<LocalizableMessage> errorMessages)
+  void addWarning(LocalizableMessage warning)
   {
-    if (errorMessages == null)
-    {
-      errorMessages = new LinkedList<LocalizableMessage>();
-    }
-
-    validate(errorMessages);
-    final Schema builtSchema = schema;
-    initBuilder();
-    return builtSchema;
+    warnings.add(warning);
   }
 
 
@@ -2294,13 +2276,12 @@
     AttributeType conflictingAttribute;
     if (numericOID2AttributeTypes.containsKey(attribute.getOID()))
     {
-      conflictingAttribute =
-          numericOID2AttributeTypes.get(attribute.getOID());
+      conflictingAttribute = numericOID2AttributeTypes.get(attribute
+          .getOID());
       if (!overwrite)
       {
-        final LocalizableMessage message =
-            ERR_SCHEMA_CONFLICTING_ATTRIBUTE_OID.get(attribute
-                .getNameOrOID(), attribute.getOID(),
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_ATTRIBUTE_OID
+            .get(attribute.getNameOrOID(), attribute.getOID(),
                 conflictingAttribute.getNameOrOID());
         throw new ConflictingSchemaElementException(message);
       }
@@ -2339,13 +2320,12 @@
     if (numericOID2ContentRules.containsKey(rule
         .getStructuralClassOID()))
     {
-      conflictingRule =
-          numericOID2ContentRules.get(rule.getStructuralClassOID());
+      conflictingRule = numericOID2ContentRules.get(rule
+          .getStructuralClassOID());
       if (!overwrite)
       {
-        final LocalizableMessage message =
-            ERR_SCHEMA_CONFLICTING_DIT_CONTENT_RULE.get(rule
-                .getNameOrOID(), rule.getStructuralClassOID(),
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_DIT_CONTENT_RULE
+            .get(rule.getNameOrOID(), rule.getStructuralClassOID(),
                 conflictingRule.getNameOrOID());
         throw new ConflictingSchemaElementException(message);
       }
@@ -2386,10 +2366,9 @@
       conflictingRule = id2StructureRules.get(rule.getRuleID());
       if (!overwrite)
       {
-        final LocalizableMessage message =
-            ERR_SCHEMA_CONFLICTING_DIT_STRUCTURE_RULE_ID.get(rule
-                .getNameOrRuleID(), rule.getRuleID(), conflictingRule
-                .getNameOrRuleID());
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_DIT_STRUCTURE_RULE_ID
+            .get(rule.getNameOrRuleID(), rule.getRuleID(),
+                conflictingRule.getNameOrRuleID());
         throw new ConflictingSchemaElementException(message);
       }
       removeDITStructureRule(conflictingRule);
@@ -2429,9 +2408,9 @@
       conflictingRule = numericOID2MatchingRules.get(rule.getOID());
       if (!overwrite)
       {
-        final LocalizableMessage message =
-            ERR_SCHEMA_CONFLICTING_MR_OID.get(rule.getNameOrOID(), rule
-                .getOID(), conflictingRule.getNameOrOID());
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_MR_OID
+            .get(rule.getNameOrOID(), rule.getOID(), conflictingRule
+                .getNameOrOID());
         throw new ConflictingSchemaElementException(message);
       }
       removeMatchingRule(conflictingRule);
@@ -2469,13 +2448,12 @@
     if (numericOID2MatchingRuleUses.containsKey(use
         .getMatchingRuleOID()))
     {
-      conflictingUse =
-          numericOID2MatchingRuleUses.get(use.getMatchingRuleOID());
+      conflictingUse = numericOID2MatchingRuleUses.get(use
+          .getMatchingRuleOID());
       if (!overwrite)
       {
-        final LocalizableMessage message =
-            ERR_SCHEMA_CONFLICTING_MATCHING_RULE_USE.get(use
-                .getNameOrOID(), use.getMatchingRuleOID(),
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_MATCHING_RULE_USE
+            .get(use.getNameOrOID(), use.getMatchingRuleOID(),
                 conflictingUse.getNameOrOID());
         throw new ConflictingSchemaElementException(message);
       }
@@ -2516,9 +2494,8 @@
       conflictingForm = numericOID2NameForms.get(form.getOID());
       if (!overwrite)
       {
-        final LocalizableMessage message =
-            ERR_SCHEMA_CONFLICTING_NAME_FORM_OID.get(form
-                .getNameOrOID(), form.getOID(), conflictingForm
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_NAME_FORM_OID
+            .get(form.getNameOrOID(), form.getOID(), conflictingForm
                 .getNameOrOID());
         throw new ConflictingSchemaElementException(message);
       }
@@ -2558,9 +2535,8 @@
       conflictingOC = numericOID2ObjectClasses.get(oc.getOID());
       if (!overwrite)
       {
-        final LocalizableMessage message =
-            ERR_SCHEMA_CONFLICTING_OBJECTCLASS_OID.get(oc
-                .getNameOrOID(), oc.getOID(), conflictingOC
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_OBJECTCLASS_OID
+            .get(oc.getNameOrOID(), oc.getOID(), conflictingOC
                 .getNameOrOID());
         throw new ConflictingSchemaElementException(message);
       }
@@ -2601,9 +2577,9 @@
       conflictingSyntax = numericOID2Syntaxes.get(syntax.getOID());
       if (!overwrite)
       {
-        final LocalizableMessage message =
-            ERR_SCHEMA_CONFLICTING_SYNTAX_OID.get(syntax.toString(),
-                syntax.getOID(), conflictingSyntax.getOID());
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_SYNTAX_OID
+            .get(syntax.toString(), syntax.getOID(), conflictingSyntax
+                .getOID());
         throw new ConflictingSchemaElementException(message);
       }
       removeSyntax(conflictingSyntax);
@@ -2617,8 +2593,7 @@
   {
     numericOID2Syntaxes = new HashMap<String, Syntax>();
     numericOID2MatchingRules = new HashMap<String, MatchingRule>();
-    numericOID2MatchingRuleUses =
-        new HashMap<String, MatchingRuleUse>();
+    numericOID2MatchingRuleUses = new HashMap<String, MatchingRuleUse>();
     numericOID2AttributeTypes = new HashMap<String, AttributeType>();
     numericOID2ObjectClasses = new HashMap<String, ObjectClass>();
     numericOID2NameForms = new HashMap<String, NameForm>();
@@ -2626,8 +2601,7 @@
     id2StructureRules = new HashMap<Integer, DITStructureRule>();
 
     name2MatchingRules = new HashMap<String, List<MatchingRule>>();
-    name2MatchingRuleUses =
-        new HashMap<String, List<MatchingRuleUse>>();
+    name2MatchingRuleUses = new HashMap<String, List<MatchingRuleUse>>();
     name2AttributeTypes = new HashMap<String, List<AttributeType>>();
     name2ObjectClasses = new HashMap<String, List<ObjectClass>>();
     name2NameForms = new HashMap<String, List<NameForm>>();
@@ -2635,18 +2609,18 @@
     name2StructureRules = new HashMap<String, List<DITStructureRule>>();
 
     objectClass2NameForms = new HashMap<String, List<NameForm>>();
-    nameForm2StructureRules =
-        new HashMap<String, List<DITStructureRule>>();
+    nameForm2StructureRules = new HashMap<String, List<DITStructureRule>>();
     options = SchemaCompatOptions.defaultOptions();
-    schema =
-        new Schema(numericOID2Syntaxes, numericOID2MatchingRules,
-            numericOID2MatchingRuleUses, numericOID2AttributeTypes,
-            numericOID2ObjectClasses, numericOID2NameForms,
-            numericOID2ContentRules, id2StructureRules,
-            name2MatchingRules, name2MatchingRuleUses,
-            name2AttributeTypes, name2ObjectClasses, name2NameForms,
-            name2ContentRules, name2StructureRules,
-            objectClass2NameForms, nameForm2StructureRules, options);
+    warnings = new LinkedList<LocalizableMessage>();
+
+    schema = new Schema(numericOID2Syntaxes, numericOID2MatchingRules,
+        numericOID2MatchingRuleUses, numericOID2AttributeTypes,
+        numericOID2ObjectClasses, numericOID2NameForms,
+        numericOID2ContentRules, id2StructureRules, name2MatchingRules,
+        name2MatchingRuleUses, name2AttributeTypes, name2ObjectClasses,
+        name2NameForms, name2ContentRules, name2StructureRules,
+        objectClass2NameForms, nameForm2StructureRules, options,
+        warnings);
   }
 
 
@@ -2658,8 +2632,8 @@
     for (final String name : attributeType.getNames())
     {
       final String lowerName = StaticUtils.toLowerCase(name);
-      final List<AttributeType> attributes =
-          name2AttributeTypes.get(lowerName);
+      final List<AttributeType> attributes = name2AttributeTypes
+          .get(lowerName);
       if (attributes != null && attributes.contains(attributeType))
       {
         if (attributes.size() <= 1)
@@ -2682,8 +2656,8 @@
     for (final String name : rule.getNames())
     {
       final String lowerName = StaticUtils.toLowerCase(name);
-      final List<DITContentRule> rules =
-          name2ContentRules.get(lowerName);
+      final List<DITContentRule> rules = name2ContentRules
+          .get(lowerName);
       if (rules != null && rules.contains(rule))
       {
         if (rules.size() <= 1)
@@ -2706,8 +2680,8 @@
     for (final String name : rule.getNames())
     {
       final String lowerName = StaticUtils.toLowerCase(name);
-      final List<DITStructureRule> rules =
-          name2StructureRules.get(lowerName);
+      final List<DITStructureRule> rules = name2StructureRules
+          .get(lowerName);
       if (rules != null && rules.contains(rule))
       {
         if (rules.size() <= 1)
@@ -2730,8 +2704,8 @@
     for (final String name : rule.getNames())
     {
       final String lowerName = StaticUtils.toLowerCase(name);
-      final List<MatchingRule> rules =
-          name2MatchingRules.get(lowerName);
+      final List<MatchingRule> rules = name2MatchingRules
+          .get(lowerName);
       if (rules != null && rules.contains(rule))
       {
         if (rules.size() <= 1)
@@ -2754,8 +2728,8 @@
     for (final String name : use.getNames())
     {
       final String lowerName = StaticUtils.toLowerCase(name);
-      final List<MatchingRuleUse> uses =
-          name2MatchingRuleUses.get(lowerName);
+      final List<MatchingRuleUse> uses = name2MatchingRuleUses
+          .get(lowerName);
       if (uses != null && uses.contains(use))
       {
         if (uses.size() <= 1)
@@ -2803,8 +2777,8 @@
     for (final String name : oc.getNames())
     {
       final String lowerName = StaticUtils.toLowerCase(name);
-      final List<ObjectClass> classes =
-          name2ObjectClasses.get(lowerName);
+      final List<ObjectClass> classes = name2ObjectClasses
+          .get(lowerName);
       if (classes != null && classes.contains(oc))
       {
         if (classes.size() <= 1)
@@ -2828,7 +2802,7 @@
 
 
 
-  private synchronized void validate(List<LocalizableMessage> warnings)
+  private synchronized void validate()
   {
     // Verify all references in all elements
     for (final Syntax syntax : numericOID2Syntaxes.values().toArray(
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaNotFoundException.java b/opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaNotFoundException.java
deleted file mode 100644
index 44137b7..0000000
--- a/opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaNotFoundException.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL HEADER, with the fields enclosed
- * by brackets "[]" replaced with your own identifying information:
- *      Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- *      Copyright 2009 Sun Microsystems, Inc.
- */
-
-package org.opends.sdk.schema;
-
-
-
-import org.opends.sdk.LocalizableException;
-import org.opends.sdk.LocalizableMessage;
-
-
-
-
-/**
- * Thrown when a schema could not be decoded or validated.
- * <p>
- * TODO: is this needed? Should it be a sub-type of
- * ErrorResultException?
- */
-@SuppressWarnings("serial")
-public class SchemaNotFoundException extends Exception implements
-    LocalizableException
-{
-  // The I18N message associated with this exception.
-  private final LocalizableMessage message;
-
-
-
-  /**
-   * Creates a new schema not found exception with the provided message.
-   * 
-   * @param message
-   *          The message that explains the problem that occurred.
-   */
-  public SchemaNotFoundException(LocalizableMessage message)
-  {
-    super(String.valueOf(message));
-    this.message = message;
-  }
-
-
-
-  /**
-   * Creates a new schema not found exception with the provided message
-   * and cause.
-   * 
-   * @param message
-   *          The message that explains the problem that occurred.
-   * @param cause
-   *          The cause which may be later retrieved by the
-   *          {@link #getCause} method. A {@code null} value is
-   *          permitted, and indicates that the cause is nonexistent or
-   *          unknown.
-   */
-  public SchemaNotFoundException(LocalizableMessage message, Throwable cause)
-  {
-    super(String.valueOf(message), cause);
-    this.message = message;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public LocalizableMessage getMessageObject()
-  {
-    return this.message;
-  }
-}
diff --git a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/util/StaticUtilsTest.java b/opendj-sdk/sdk/tests/unit-tests-testng/src/com/sun/opends/sdk/util/StaticUtilsTest.java
similarity index 98%
rename from opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/util/StaticUtilsTest.java
rename to opendj-sdk/sdk/tests/unit-tests-testng/src/com/sun/opends/sdk/util/StaticUtilsTest.java
index 4e53528..352cbac 100644
--- a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/util/StaticUtilsTest.java
+++ b/opendj-sdk/sdk/tests/unit-tests-testng/src/com/sun/opends/sdk/util/StaticUtilsTest.java
@@ -25,7 +25,7 @@
  *      Copyright 2009 Sun Microsystems, Inc.
  */
 
-package org.opends.sdk.util;
+package com.sun.opends.sdk.util;
 
 
 
diff --git a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/AttributeDescriptionTest.java b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/AttributeDescriptionTest.java
index 851bd26..5819963 100644
--- a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/AttributeDescriptionTest.java
+++ b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/AttributeDescriptionTest.java
@@ -32,11 +32,12 @@
 import java.util.Iterator;
 
 import org.opends.sdk.schema.Schema;
-import org.opends.sdk.util.LocalizedIllegalArgumentException;
 import org.testng.Assert;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
 
 
 /**
diff --git a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/LinkedAttributeTest.java b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/LinkedAttributeTest.java
index 04211a9..834fc59 100644
--- a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/LinkedAttributeTest.java
+++ b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/LinkedAttributeTest.java
@@ -30,9 +30,10 @@
 
 
 import org.opends.sdk.schema.Schema;
-import org.opends.sdk.util.ByteString;
 import org.testng.annotations.Test;
 
+import org.opends.sdk.ByteString;
+
 
 
 /**
diff --git a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/ApproximateMatchingRuleTest.java b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/ApproximateMatchingRuleTest.java
index b5946c4..62b99bc 100644
--- a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/ApproximateMatchingRuleTest.java
+++ b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/ApproximateMatchingRuleTest.java
@@ -32,10 +32,11 @@
 import static org.testng.Assert.assertEquals;
 
 import org.opends.sdk.ConditionResult;
-import org.opends.sdk.util.ByteString;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import org.opends.sdk.ByteString;
+
 
 
 /**
diff --git a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/EnumSyntaxTestCase.java b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/EnumSyntaxTestCase.java
index 0fc52d3..de96a89 100644
--- a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/EnumSyntaxTestCase.java
+++ b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/EnumSyntaxTestCase.java
@@ -32,11 +32,12 @@
 
 import org.opends.sdk.ConditionResult;
 import org.opends.sdk.DecodeException;
-import org.opends.sdk.util.ByteString;
 import org.testng.Assert;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import org.opends.sdk.ByteString;
+
 
 
 /**
diff --git a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/MatchingRuleTest.java b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/MatchingRuleTest.java
index 221293f..775a2f3 100644
--- a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/MatchingRuleTest.java
+++ b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/MatchingRuleTest.java
@@ -33,10 +33,11 @@
 import org.opends.sdk.Assertion;
 import org.opends.sdk.ConditionResult;
 import org.opends.sdk.DecodeException;
-import org.opends.sdk.util.ByteString;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import org.opends.sdk.ByteString;
+
 
 
 /**
diff --git a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/OrderingMatchingRuleTest.java b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/OrderingMatchingRuleTest.java
index d0b8880..53444ff 100644
--- a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/OrderingMatchingRuleTest.java
+++ b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/OrderingMatchingRuleTest.java
@@ -31,11 +31,12 @@
 import org.opends.sdk.Assertion;
 import org.opends.sdk.ConditionResult;
 import org.opends.sdk.DecodeException;
-import org.opends.sdk.util.ByteString;
 import org.testng.Assert;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import org.opends.sdk.ByteString;
+
 
 
 /**
diff --git a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/SubstringMatchingRuleTest.java b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/SubstringMatchingRuleTest.java
index 163e4c7..4c2ee85 100644
--- a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/SubstringMatchingRuleTest.java
+++ b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/SubstringMatchingRuleTest.java
@@ -35,11 +35,12 @@
 
 import org.opends.sdk.ConditionResult;
 import org.opends.sdk.DecodeException;
-import org.opends.sdk.util.ByteSequence;
-import org.opends.sdk.util.ByteString;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
 
 
 /**
diff --git a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/SyntaxTestCase.java b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/SyntaxTestCase.java
index 09b8757..bc69054 100644
--- a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/SyntaxTestCase.java
+++ b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/SyntaxTestCase.java
@@ -32,10 +32,11 @@
 
 import org.opends.messages.MessageBuilder;
 import org.opends.sdk.DecodeException;
-import org.opends.sdk.util.ByteString;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import org.opends.sdk.ByteString;
+
 
 
 /**

--
Gitblit v1.10.0