From 7502e11a640c6eb92c4fc7604a4abf31c28745ed Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Mon, 20 Jun 2011 11:16:07 +0000
Subject: [PATCH] Fix OPENDJ-206: Add schema reading methods to SchemaBuilder and remove Schema/RootDSE methods from the Connection/AsynchronousConnection APIs

---
 opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java       |    4 
 opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/schema/Main.java        |    7 
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java            |  293 +++++++++++++++
 opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/AsynchronousConnectionDecorator.java |   44 --
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/RootDSE.java                         |   40 +
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java                   |  165 ++-------
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Connection.java                      |  193 ----------
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConnectionPool.java                  |   53 --
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/SynchronousConnection.java           |   25 -
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java              |   75 ----
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnection.java  |   46 --
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AsynchronousConnection.java          |   83 ----
 12 files changed, 356 insertions(+), 672 deletions(-)

diff --git a/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/schema/Main.java b/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/schema/Main.java
index 94dead2..2fc706c 100644
--- a/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/schema/Main.java
+++ b/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/schema/Main.java
@@ -31,10 +31,7 @@
 
 
 import org.forgerock.i18n.LocalizableMessage;
-import org.forgerock.opendj.ldap.Connection;
-import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.LDAPConnectionFactory;
-import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.*;
 import org.forgerock.opendj.ldap.schema.*;
 
 
@@ -81,7 +78,7 @@
       connection.bind(userName, password.toCharArray());
 
       // Read the schema.
-      Schema schema = connection.readSchemaForRootDSE();
+      Schema schema = Schema.readSchemaForEntry(connection, DN.rootDN());
 
       System.out.println("Attribute types");
       for (AttributeType at : schema.getAttributeTypes())
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/AsynchronousConnectionDecorator.java b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/AsynchronousConnectionDecorator.java
index e3fe396..3cc077f 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/AsynchronousConnectionDecorator.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/AsynchronousConnectionDecorator.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2010 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package com.forgerock.opendj.util;
@@ -34,7 +35,6 @@
 import org.forgerock.opendj.ldap.*;
 import org.forgerock.opendj.ldap.requests.*;
 import org.forgerock.opendj.ldap.responses.*;
-import org.forgerock.opendj.ldap.schema.Schema;
 
 
 
@@ -399,48 +399,6 @@
    * <p>
    * The default implementation is to delegate.
    */
-  public FutureResult<RootDSE> readRootDSE(
-      ResultHandler<? super RootDSE> handler)
-      throws UnsupportedOperationException, IllegalStateException
-  {
-    return connection.readRootDSE(handler);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   * <p>
-   * The default implementation is to delegate.
-   */
-  public FutureResult<Schema> readSchema(DN name,
-      ResultHandler<? super Schema> handler)
-      throws UnsupportedOperationException, IllegalStateException
-  {
-    return connection.readSchema(name, handler);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   * <p>
-   * The default implementation is to delegate.
-   */
-  public FutureResult<Schema> readSchemaForEntry(DN name,
-      ResultHandler<? super Schema> handler)
-      throws UnsupportedOperationException, IllegalStateException
-  {
-    return connection.readSchemaForEntry(name, handler);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   * <p>
-   * The default implementation is to delegate.
-   */
   public void removeConnectionEventListener(ConnectionEventListener listener)
       throws NullPointerException
   {
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnection.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnection.java
index c21f791..e565a14 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnection.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnection.java
@@ -30,9 +30,7 @@
 
 
 
-import static org.forgerock.opendj.ldap.CoreMessages.ERR_NO_SEARCH_RESULT_ENTRIES;
-import static org.forgerock.opendj.ldap.CoreMessages.ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES;
-import static org.forgerock.opendj.ldap.CoreMessages.ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES;
+import static org.forgerock.opendj.ldap.CoreMessages.*;
 import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
 
 import java.util.Collection;
@@ -41,7 +39,6 @@
 
 import org.forgerock.opendj.ldap.requests.*;
 import org.forgerock.opendj.ldap.responses.*;
-import org.forgerock.opendj.ldap.schema.Schema;
 
 
 
@@ -347,7 +344,10 @@
   {
     final SearchRequest request = Requests.newSearchRequest(name,
         SearchScope.BASE_OBJECT, Filter.getObjectClassPresentFilter());
-    request.getAttributes().addAll(attributeDescriptions);
+    if (attributeDescriptions != null)
+    {
+      request.getAttributes().addAll(attributeDescriptions);
+    }
     return searchSingleEntry(request, handler);
   }
 
@@ -356,42 +356,6 @@
   /**
    * {@inheritDoc}
    */
-  public FutureResult<RootDSE> readRootDSE(
-      final ResultHandler<? super RootDSE> handler)
-      throws UnsupportedOperationException, IllegalStateException
-  {
-    return RootDSE.readRootDSE(this, handler);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public FutureResult<Schema> readSchema(final DN name,
-      final ResultHandler<? super Schema> handler)
-      throws UnsupportedOperationException, IllegalStateException
-  {
-    return Schema.readSchema(this, name, handler);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public FutureResult<Schema> readSchemaForEntry(final DN name,
-      final ResultHandler<? super Schema> handler)
-      throws UnsupportedOperationException, IllegalStateException
-  {
-    return Schema.readSchemaForEntry(this, name, handler);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
   public FutureResult<Result> search(final SearchRequest request,
       final SearchResultHandler handler) throws UnsupportedOperationException,
       IllegalStateException, NullPointerException
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java
index 46288cb..b1b34f4 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap;
@@ -42,7 +43,6 @@
 import org.forgerock.opendj.ldap.requests.Requests;
 import org.forgerock.opendj.ldap.requests.SearchRequest;
 import org.forgerock.opendj.ldap.responses.*;
-import org.forgerock.opendj.ldap.schema.Schema;
 import org.forgerock.opendj.ldif.ConnectionEntryReader;
 
 import com.forgerock.opendj.util.Validator;
@@ -260,79 +260,6 @@
   /**
    * {@inheritDoc}
    */
-  public RootDSE readRootDSE() throws ErrorResultException,
-      InterruptedException, UnsupportedOperationException,
-      IllegalStateException
-  {
-    return RootDSE.readRootDSE(this);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public Schema readSchema(final DN name) throws ErrorResultException,
-      InterruptedException, UnsupportedOperationException,
-      IllegalStateException
-  {
-    return Schema.readSchema(this, name);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public Schema readSchema(final String name) throws ErrorResultException,
-      InterruptedException, LocalizedIllegalArgumentException,
-      UnsupportedOperationException, IllegalStateException
-  {
-    return readSchema(DN.valueOf(name));
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public Schema readSchemaForEntry(final DN name) throws ErrorResultException,
-      InterruptedException, UnsupportedOperationException,
-      IllegalStateException
-  {
-    return Schema.readSchemaForEntry(this, name);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public Schema readSchemaForEntry(final 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());
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
   public Result search(final SearchRequest request,
       final Collection<? super SearchResultEntry> entries)
       throws ErrorResultException, InterruptedException,
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AsynchronousConnection.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AsynchronousConnection.java
index 62c170b..f67dc84 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AsynchronousConnection.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AsynchronousConnection.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap;
@@ -34,7 +35,6 @@
 
 import org.forgerock.opendj.ldap.requests.*;
 import org.forgerock.opendj.ldap.responses.*;
-import org.forgerock.opendj.ldap.schema.Schema;
 
 
 
@@ -667,87 +667,6 @@
 
 
   /**
-   * 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 handler
-   *          A result handler which can be used to asynchronously process the
-   *          operation result when it is received, may be {@code null}.
-   * @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}.
-   */
-  FutureResult<RootDSE> readRootDSE(ResultHandler<? super RootDSE> handler)
-      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 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}.
-   * @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}.
-   */
-  FutureResult<Schema> readSchema(DN name, ResultHandler<? super Schema> handler)
-      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 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}.
-   *          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}.
-   */
-  FutureResult<Schema> readSchemaForEntry(DN name,
-      ResultHandler<? super Schema> handler)
-      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
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Connection.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Connection.java
index 3911007..f19e9ff 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Connection.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Connection.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap;
@@ -36,7 +37,6 @@
 import org.forgerock.i18n.LocalizedIllegalArgumentException;
 import org.forgerock.opendj.ldap.requests.*;
 import org.forgerock.opendj.ldap.responses.*;
-import org.forgerock.opendj.ldap.schema.Schema;
 import org.forgerock.opendj.ldif.ConnectionEntryReader;
 
 
@@ -778,197 +778,6 @@
 
 
   /**
-   * 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;
-
-
-
-  /**
-   * 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
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConnectionPool.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConnectionPool.java
index 5f16cbe..d6e03df 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConnectionPool.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConnectionPool.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap;
@@ -39,7 +40,6 @@
 
 import org.forgerock.opendj.ldap.requests.*;
 import org.forgerock.opendj.ldap.responses.*;
-import org.forgerock.opendj.ldap.schema.Schema;
 
 import com.forgerock.opendj.util.AsynchronousFutureResult;
 import com.forgerock.opendj.util.CompletedFutureResult;
@@ -555,57 +555,6 @@
      * {@inheritDoc}
      */
     @Override
-    public FutureResult<RootDSE> readRootDSE(
-        final ResultHandler<? super RootDSE> handler)
-        throws UnsupportedOperationException, IllegalStateException
-    {
-      if (isClosed())
-      {
-        throw new IllegalStateException();
-      }
-      return connection.readRootDSE(handler);
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FutureResult<Schema> readSchema(final DN name,
-        final ResultHandler<? super Schema> handler)
-        throws UnsupportedOperationException, IllegalStateException
-    {
-      if (isClosed())
-      {
-        throw new IllegalStateException();
-      }
-      return connection.readSchema(name, handler);
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FutureResult<Schema> readSchemaForEntry(final DN name,
-        final ResultHandler<? super Schema> handler)
-        throws UnsupportedOperationException, IllegalStateException
-    {
-      if (isClosed())
-      {
-        throw new IllegalStateException();
-      }
-      return connection.readSchemaForEntry(name, handler);
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
     public void removeConnectionEventListener(
         final ConnectionEventListener listener) throws NullPointerException
     {
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/RootDSE.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/RootDSE.java
index 7fb0b98..c153fbe 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/RootDSE.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/RootDSE.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap;
@@ -168,7 +169,7 @@
       protected RootDSE transformResult(final SearchResultEntry result)
           throws ErrorResultException
       {
-        return new RootDSE(result);
+        return valueOf(result);
       }
 
     };
@@ -210,6 +211,27 @@
       NullPointerException
   {
     final Entry entry = connection.searchSingleEntry(SEARCH_REQUEST);
+    return valueOf(entry);
+  }
+
+
+
+  /**
+   * 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.
+   * @return A Root DSE instance backed by the provided entry.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null} .
+   */
+  public static RootDSE valueOf(Entry entry) throws NullPointerException
+  {
+    Validator.ensureNotNull(entry);
     return new RootDSE(entry);
   }
 
@@ -219,21 +241,9 @@
 
 
 
-  /**
-   * 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(final Entry entry) throws NullPointerException
+  // Prevent direct instantiation.
+  private RootDSE(final Entry entry) throws NullPointerException
   {
-    Validator.ensureNotNull(entry);
     this.entry = entry;
   }
 
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/SynchronousConnection.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/SynchronousConnection.java
index 77ea963..dcbef80 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/SynchronousConnection.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/SynchronousConnection.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap;
@@ -33,7 +34,6 @@
 
 import org.forgerock.opendj.ldap.requests.*;
 import org.forgerock.opendj.ldap.responses.*;
-import org.forgerock.opendj.ldap.schema.Schema;
 import org.forgerock.opendj.ldif.ConnectionEntryReader;
 
 import com.forgerock.opendj.util.Validator;
@@ -311,29 +311,6 @@
   /**
    * {@inheritDoc}
    */
-  @Override
-  public Schema readSchemaForEntry(final DN name) throws ErrorResultException,
-      InterruptedException, UnsupportedOperationException,
-      IllegalStateException
-  {
-    final FutureResult<Schema> future = connection.readSchemaForEntry(name,
-        null);
-    try
-    {
-      return future.get();
-    }
-    finally
-    {
-      // Cancel the request if it hasn't completed.
-      future.cancel(false);
-    }
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
   public void removeConnectionEventListener(
       final ConnectionEventListener listener) throws NullPointerException
   {
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
index a344c19..1759a1e 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
@@ -30,7 +30,6 @@
 
 
 import static org.forgerock.opendj.ldap.CoreMessages.*;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -38,14 +37,9 @@
 import java.util.Map;
 
 import org.forgerock.i18n.LocalizableMessage;
-import org.forgerock.i18n.LocalizedIllegalArgumentException;
 import org.forgerock.opendj.ldap.*;
-import org.forgerock.opendj.ldap.requests.Requests;
-import org.forgerock.opendj.ldap.requests.SearchRequest;
-import org.forgerock.opendj.ldap.responses.SearchResultEntry;
 
 import com.forgerock.opendj.util.FutureResultTransformer;
-import com.forgerock.opendj.util.RecursiveFutureResult;
 import com.forgerock.opendj.util.StaticUtils;
 import com.forgerock.opendj.util.Validator;
 
@@ -1480,20 +1474,6 @@
 
   static final String ATTR_OBJECT_CLASSES = "objectClasses";
 
-  private static final String ATTR_SUBSCHEMA_SUBENTRY = "subschemaSubentry";
-
-  private static final String[] SUBSCHEMA_ATTRS = new String[] {
-      ATTR_LDAP_SYNTAXES, ATTR_ATTRIBUTE_TYPES,
-      ATTR_DIT_CONTENT_RULES, ATTR_DIT_STRUCTURE_RULES,
-      ATTR_MATCHING_RULE_USE, ATTR_MATCHING_RULES,
-      ATTR_NAME_FORMS, ATTR_OBJECT_CLASSES };
-
-  private static final Filter SUBSCHEMA_FILTER = Filter
-      .valueOf("(objectClass=subschema)");
-
-  private static final String[] SUBSCHEMA_SUBENTRY_ATTRS =
-    new String[] { ATTR_SUBSCHEMA_SUBENTRY };
-
 
 
   /**
@@ -1550,16 +1530,11 @@
 
 
   /**
-   * Reads the schema from the Directory Server contained in the named subschema
-   * sub-entry.
+   * Reads the schema 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>
-   * This method uses a Search operation to read the schema and does not perform
-   * caching. More specifically, it does not use the
-   * {@link AsynchronousConnection#readSchema} method.
    *
    * @param connection
    *          A connection to the Directory Server whose schema is to be read.
@@ -1568,12 +1543,12 @@
    * @param handler
    *          A result handler which can be used to asynchronously process the
    *          operation result when it is received, may be {@code null}.
-   * @return A future representing the result of the operation.
+   * @return A future representing the retrieved schema.
    * @throws UnsupportedOperationException
-   *           If this connection does not support search operations.
+   *           If the connection does not support search operations.
    * @throws IllegalStateException
-   *           If this connection has already been closed, i.e. if {@code
-   *           isClosed() == true}.
+   *           If the connection has already been closed, i.e. if
+   *           {@code connection.isClosed() == true}.
    * @throws NullPointerException
    *           If the {@code connection} or {@code name} was {@code null}.
    */
@@ -1583,23 +1558,22 @@
       throws UnsupportedOperationException, IllegalStateException,
       NullPointerException
   {
-    final SearchRequest request = getReadSchemaSearchRequest(name);
-
-    final FutureResultTransformer<SearchResultEntry, Schema> future =
-      new FutureResultTransformer<SearchResultEntry, Schema>(handler)
+    final FutureResultTransformer<SchemaBuilder, Schema> future =
+      new FutureResultTransformer<SchemaBuilder, Schema>(handler)
     {
 
       @Override
-      protected Schema transformResult(final SearchResultEntry result)
+      protected Schema transformResult(final SchemaBuilder builder)
           throws ErrorResultException
       {
-        return valueOf(result);
+        return builder.toSchema();
       }
 
     };
 
-    final FutureResult<SearchResultEntry> innerFuture = connection
-        .searchSingleEntry(request, future);
+    final SchemaBuilder builder = new SchemaBuilder();
+    final FutureResult<SchemaBuilder> innerFuture = builder.addSchema(
+        connection, name, future, true);
     future.setFutureResult(innerFuture);
     return future;
   }
@@ -1607,16 +1581,11 @@
 
 
   /**
-   * Reads the schema from the Directory Server contained in the named subschema
-   * sub-entry using the provided connection.
+   * Reads the schema 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>
-   * This method uses a Search operation to read the schema and does not perform
-   * caching. More specifically, it does not use the
-   * {@link Connection#readSchema} method.
    *
    * @param connection
    *          A connection to the Directory Server whose schema is to be read.
@@ -1632,7 +1601,7 @@
    *           If the connection does not support search operations.
    * @throws IllegalStateException
    *           If the connection has already been closed, i.e. if {@code
-   *           isClosed() == true}.
+   *           connection.isClosed() == true}.
    * @throws NullPointerException
    *           If the {@code connection} or {@code name} was {@code null}.
    */
@@ -1641,16 +1610,14 @@
       UnsupportedOperationException, IllegalStateException,
       NullPointerException
   {
-    final SearchRequest request = getReadSchemaSearchRequest(name);
-    final Entry entry = connection.searchSingleEntry(request);
-    return valueOf(entry);
+    return new SchemaBuilder().addSchema(connection, name, true).toSchema();
   }
 
 
 
   /**
-   * Reads the schema from the Directory Server which applies to the named
-   * entry.
+   * Reads the schema contained in the subschema sub-entry 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
@@ -1659,8 +1626,8 @@
    * <p>
    * This implementation first reads the {@code subschemaSubentry} attribute of
    * the entry in order to identify the schema and then invokes
-   * {@link #readSchema} to read the schema. More specifically, it does not use
-   * the {@link AsynchronousConnection#readSchemaForEntry} method.
+   * {@link #readSchema(AsynchronousConnection, DN, ResultHandler)} to read the
+   * schema.
    *
    * @param connection
    *          A connection to the Directory Server whose schema is to be read.
@@ -1669,12 +1636,12 @@
    * @param handler
    *          A result handler which can be used to asynchronously process the
    *          operation result when it is received, may be {@code null}.
-   * @return A future representing the result of the operation.
+   * @return A future representing the retrieved schema.
    * @throws UnsupportedOperationException
-   *           If this connection does not support search operations.
+   *           If the connection does not support search operations.
    * @throws IllegalStateException
-   *           If this connection has already been closed, i.e. if {@code
-   *           isClosed() == true}.
+   *           If the connection has already been closed, i.e. if
+   *           {@code connection.isClosed() == true}.
    * @throws NullPointerException
    *           If the {@code connection} or {@code name} was {@code null}.
    */
@@ -1684,34 +1651,32 @@
       throws UnsupportedOperationException, IllegalStateException,
       NullPointerException
   {
-    final RecursiveFutureResult<SearchResultEntry, Schema> future =
-      new RecursiveFutureResult<SearchResultEntry, Schema>(handler)
+    final FutureResultTransformer<SchemaBuilder, Schema> future =
+      new FutureResultTransformer<SchemaBuilder, Schema>(handler)
     {
 
       @Override
-      protected FutureResult<Schema> chainResult(
-          final SearchResultEntry innerResult,
-          final ResultHandler<? super Schema> handler)
+      protected Schema transformResult(final SchemaBuilder builder)
           throws ErrorResultException
       {
-        final DN subschemaDN = getSubschemaSubentryDN(name, innerResult);
-        return readSchema(connection, subschemaDN, handler);
+        return builder.toSchema();
       }
 
     };
 
-    final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
-    final FutureResult<SearchResultEntry> innerFuture = connection
-        .searchSingleEntry(request, future);
+    final SchemaBuilder builder = new SchemaBuilder();
+    final FutureResult<SchemaBuilder> innerFuture = builder.addSchemaForEntry(
+        connection, name, future, true);
     future.setFutureResult(innerFuture);
     return future;
+
   }
 
 
 
   /**
-   * Reads the schema from the Directory Server which applies to the named entry
-   * using the provided connection.
+   * Reads the schema contained in the subschema sub-entry 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
@@ -1720,8 +1685,7 @@
    * <p>
    * This implementation first reads the {@code subschemaSubentry} attribute of
    * the entry in order to identify the schema and then invokes
-   * {@link #readSchema} to read the schema. More specifically, it does not use
-   * the {@link Connection#readSchemaForEntry} method.
+   * {@link #readSchema(Connection, DN)} to read the schema.
    *
    * @param connection
    *          A connection to the Directory Server whose schema is to be read.
@@ -1738,7 +1702,7 @@
    *           If the connection does not support search operations.
    * @throws IllegalStateException
    *           If the connection has already been closed, i.e. if {@code
-   *           isClosed() == true}.
+   *           connection.isClosed() == true}.
    * @throws NullPointerException
    *           If the {@code connection} or {@code name} was {@code null}.
    */
@@ -1747,11 +1711,8 @@
       UnsupportedOperationException, IllegalStateException,
       NullPointerException
   {
-    final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
-    final Entry entry = connection.searchSingleEntry(request);
-    final DN subschemaDN = getSubschemaSubentryDN(name, entry);
-
-    return readSchema(connection, subschemaDN);
+    return new SchemaBuilder().addSchemaForEntry(connection, name, true)
+        .toSchema();
   }
 
 
@@ -1801,58 +1762,6 @@
 
 
 
-  // Constructs a search request for retrieving the subschemaSubentry
-  // attribute from the named entry.
-  private static SearchRequest getReadSchemaForEntrySearchRequest(final DN dn)
-  {
-    return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT, Filter
-        .getObjectClassPresentFilter(), SUBSCHEMA_SUBENTRY_ATTRS);
-  }
-
-
-
-  // Constructs a search request for retrieving the named subschema
-  // sub-entry.
-  private static SearchRequest getReadSchemaSearchRequest(final DN dn)
-  {
-    return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT,
-        SUBSCHEMA_FILTER, SUBSCHEMA_ATTRS);
-  }
-
-
-
-  private static DN getSubschemaSubentryDN(final 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.
-      throw newErrorResult(
-          ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED,
-          ERR_NO_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString())
-              .toString());
-    }
-
-    final String dnString = subentryAttr.iterator().next().toString();
-    DN subschemaDN;
-    try
-    {
-      subschemaDN = DN.valueOf(dnString);
-    }
-    catch (final LocalizedIllegalArgumentException e)
-    {
-      throw newErrorResult(
-          ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED,
-          ERR_INVALID_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString(),
-              dnString, e.getMessageObject()).toString());
-    }
-    return subschemaDN;
-  }
-
-
-
   private final Impl impl;
 
 
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
index c57c5da..11cbb23 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -31,13 +31,10 @@
 
 
 import static org.forgerock.opendj.ldap.CoreMessages.*;
-import static org.forgerock.opendj.ldap.schema.SchemaConstants.EXTENSIBLE_OBJECT_OBJECTCLASS_OID;
-import static org.forgerock.opendj.ldap.schema.SchemaConstants.OMR_GENERIC_ENUM_NAME;
-import static org.forgerock.opendj.ldap.schema.SchemaConstants.SCHEMA_PROPERTY_APPROX_RULE;
-import static org.forgerock.opendj.ldap.schema.SchemaConstants.TOP_OBJECTCLASS_NAME;
-import static org.forgerock.opendj.ldap.schema.SchemaUtils.unmodifiableCopyOfExtraProperties;
-import static org.forgerock.opendj.ldap.schema.SchemaUtils.unmodifiableCopyOfList;
-import static org.forgerock.opendj.ldap.schema.SchemaUtils.unmodifiableCopyOfSet;
+import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
+import static org.forgerock.opendj.ldap.schema.Schema.*;
+import static org.forgerock.opendj.ldap.schema.SchemaConstants.*;
+import static org.forgerock.opendj.ldap.schema.SchemaUtils.*;
 
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -45,14 +42,12 @@
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.LocalizedIllegalArgumentException;
-import org.forgerock.opendj.ldap.Attribute;
-import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DecodeException;
-import org.forgerock.opendj.ldap.Entry;
+import org.forgerock.opendj.ldap.*;
+import org.forgerock.opendj.ldap.requests.Requests;
+import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.opendj.ldap.responses.SearchResultEntry;
 
-import com.forgerock.opendj.util.StaticUtils;
-import com.forgerock.opendj.util.SubstringReader;
-import com.forgerock.opendj.util.Validator;
+import com.forgerock.opendj.util.*;
 
 
 
@@ -62,6 +57,71 @@
 public final class SchemaBuilder
 {
 
+  private static final String ATTR_SUBSCHEMA_SUBENTRY = "subschemaSubentry";
+
+  private static final String[] SUBSCHEMA_ATTRS = new String[] {
+      ATTR_LDAP_SYNTAXES, ATTR_ATTRIBUTE_TYPES, ATTR_DIT_CONTENT_RULES,
+      ATTR_DIT_STRUCTURE_RULES, ATTR_MATCHING_RULE_USE, ATTR_MATCHING_RULES,
+      ATTR_NAME_FORMS, ATTR_OBJECT_CLASSES };
+
+  private static final Filter SUBSCHEMA_FILTER = Filter
+      .valueOf("(objectClass=subschema)");
+
+  private static final String[] SUBSCHEMA_SUBENTRY_ATTRS =
+    new String[] { ATTR_SUBSCHEMA_SUBENTRY };
+
+
+
+  // Constructs a search request for retrieving the named subschema
+  // sub-entry.
+  private static SearchRequest getReadSchemaSearchRequest(final 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(final DN dn)
+  {
+    return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT,
+        Filter.getObjectClassPresentFilter(), SUBSCHEMA_SUBENTRY_ATTRS);
+  }
+
+
+
+  private static DN getSubschemaSubentryDN(final 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.
+      throw newErrorResult(ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED,
+          ERR_NO_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString()).toString());
+    }
+
+    final String dnString = subentryAttr.iterator().next().toString();
+    DN subschemaDN;
+    try
+    {
+      subschemaDN = DN.valueOf(dnString);
+    }
+    catch (final LocalizedIllegalArgumentException e)
+    {
+      throw newErrorResult(
+          ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED,
+          ERR_INVALID_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString(), dnString,
+              e.getMessageObject()).toString());
+    }
+    return subschemaDN;
+  }
+
+
+
   private Map<Integer, DITStructureRule> id2StructureRules;
 
   private Map<String, List<AttributeType>> name2AttributeTypes;
@@ -2116,6 +2176,211 @@
 
 
   /**
+   * Reads the schema elements contained in the named subschema sub-entry and
+   * adds them to this schema builder.
+   * <p>
+   * If the requested schema is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}.
+   *
+   * @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 overwrite
+   *          {@code true} if existing schema elements with the same conflicting
+   *          OIDs should be overwritten.
+   * @return A future representing the updated schema builder.
+   * @throws UnsupportedOperationException
+   *           If the connection does not support search operations.
+   * @throws IllegalStateException
+   *           If the connection has already been closed, i.e. if
+   *           {@code connection.isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} or {@code name} was {@code null}.
+   */
+  public FutureResult<SchemaBuilder> addSchema(
+      final AsynchronousConnection connection, final DN name,
+      final ResultHandler<? super SchemaBuilder> handler,
+      final boolean overwrite) throws UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    final SearchRequest request = getReadSchemaSearchRequest(name);
+
+    final FutureResultTransformer<SearchResultEntry, SchemaBuilder> future =
+      new FutureResultTransformer<SearchResultEntry, SchemaBuilder>(handler)
+    {
+
+      @Override
+      protected SchemaBuilder transformResult(final SearchResultEntry result)
+          throws ErrorResultException
+      {
+        addSchema(result, overwrite);
+        return SchemaBuilder.this;
+      }
+
+    };
+
+    final FutureResult<SearchResultEntry> innerFuture = connection
+        .searchSingleEntry(request, future);
+    future.setFutureResult(innerFuture);
+    return future;
+  }
+
+
+
+  /**
+   * Reads the schema elements contained in the named subschema sub-entry and
+   * adds them to this schema builder.
+   * <p>
+   * If the requested schema is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}.
+   *
+   * @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 overwrite
+   *          {@code true} if existing schema elements with the same conflicting
+   *          OIDs should be overwritten.
+   * @return A reference to this schema builder.
+   * @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 SchemaBuilder addSchema(final Connection connection, final DN name,
+      final boolean overwrite) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    final SearchRequest request = getReadSchemaSearchRequest(name);
+    final Entry entry = connection.searchSingleEntry(request);
+    return addSchema(entry, overwrite);
+  }
+
+
+
+  /**
+   * Reads the schema elements contained in the subschema sub-entry which
+   * applies to the named entry and adds them to this schema builder.
+   * <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}.
+   * <p>
+   * This implementation first reads the {@code subschemaSubentry} attribute of
+   * the entry in order to identify the schema and then invokes
+   * {@link #addSchema(AsynchronousConnection, DN, ResultHandler, boolean)} to
+   * read the schema.
+   *
+   * @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 overwrite
+   *          {@code true} if existing schema elements with the same conflicting
+   *          OIDs should be overwritten.
+   * @return A future representing the updated schema builder.
+   * @throws UnsupportedOperationException
+   *           If the connection does not support search operations.
+   * @throws IllegalStateException
+   *           If the connection has already been closed, i.e. if
+   *           {@code connection.isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} or {@code name} was {@code null}.
+   */
+  public FutureResult<SchemaBuilder> addSchemaForEntry(
+      final AsynchronousConnection connection, final DN name,
+      final ResultHandler<? super SchemaBuilder> handler,
+      final boolean overwrite) throws UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    final RecursiveFutureResult<SearchResultEntry, SchemaBuilder> future =
+      new RecursiveFutureResult<SearchResultEntry, SchemaBuilder>(handler)
+    {
+
+      @Override
+      protected FutureResult<SchemaBuilder> chainResult(
+          final SearchResultEntry innerResult,
+          final ResultHandler<? super SchemaBuilder> handler)
+          throws ErrorResultException
+      {
+        final DN subschemaDN = getSubschemaSubentryDN(name, innerResult);
+        return addSchema(connection, subschemaDN, handler, overwrite);
+      }
+
+    };
+
+    final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
+    final FutureResult<SearchResultEntry> innerFuture = connection
+        .searchSingleEntry(request, future);
+    future.setFutureResult(innerFuture);
+    return future;
+  }
+
+
+
+  /**
+   * Reads the schema elements contained in the subschema sub-entry which
+   * applies to the named entry and adds them to this schema builder.
+   * <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}.
+   * <p>
+   * This implementation first reads the {@code subschemaSubentry} attribute of
+   * the entry in order to identify the schema and then invokes
+   * {@link #addSchemaForEntry(Connection, DN, boolean)} to read the schema.
+   *
+   * @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 overwrite
+   *          {@code true} if existing schema elements with the same conflicting
+   *          OIDs should be overwritten.
+   * @return A reference to this schema builder.
+   * @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 connection.isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} or {@code name} was {@code null}.
+   */
+  public SchemaBuilder addSchemaForEntry(final Connection connection,
+      final DN name, final boolean overwrite) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
+    final Entry entry = connection.searchSingleEntry(request);
+    final DN subschemaDN = getSubschemaSubentryDN(name, entry);
+    return addSchema(connection, subschemaDN, overwrite);
+  }
+
+
+
+  /**
    * Adds the provided substitution syntax definition to this schema builder.
    *
    * @param oid
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
index 63677e9..fa053f4 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
@@ -263,7 +263,7 @@
     final AsynchronousConnection con = future.get();
     // quickly check if it is a valid connection.
     // Don't use a result handler.
-    assertNotNull(con.readRootDSE(null).get());
+    assertNotNull(con.readEntry(DN.rootDN(), null, null).get());
     con.close();
   }
 
@@ -306,7 +306,7 @@
     final Connection con = factory.getConnection();
     assertNotNull(con);
     // quickly check if it is a valid connection.
-    assertTrue(con.readRootDSE().getEntry().getName().isRootDN());
+    assertTrue(con.readEntry("").getName().isRootDN());
     con.close();
   }
 

--
Gitblit v1.10.0