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

matthew_swift
15.58.2009 388f25a9dc58704ea19a333ba9a28054d48590b1
Various changes:

* fix command line tools so that they exit
* remove ConnectionFuture and ConnectionResultHandler and use ResultFuture/ResultHandler instead
* rename ResultFuture -> FutureResult to align with FutureTask name format
* provide AbstractFutureResult which can be used for handling asynchronous results
* fix FutureResultTransformer so that it does not create a new result for each invocation of get()
* fix ResultChain - remove race conditions, simplify, improve APIs, etc...
* rename ResultChain -> RecursiveFutureResult
* rename ResultTransformer -> FutureResultTransformer
* add getSchemaName() to Schema class for retrieving a user friendly name of a schema (for use in debugging).
3 files deleted
29 files modified
2 files added
2 files renamed
3206 ■■■■ changed files
sdk/src/com/sun/opends/sdk/ldap/AbstractResultFutureImpl.java 213 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/BindResultFutureImpl.java 12 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/CompareResultFutureImpl.java 12 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/ExtendedResultFutureImpl.java 11 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java 125 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/LDAPConnectionFactoryImpl.java 93 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/ResultFutureImpl.java 11 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/SearchResultFutureImpl.java 43 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/tools/ArgumentParserConnectionFactory.java 4 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/tools/LDAPCompare.java 6 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/tools/LDAPModify.java 6 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/tools/LDAPPasswordModify.java 6 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/tools/LDAPSearch.java 7 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/tools/ModRate.java 8 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/tools/PerformanceRunner.java 4 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/tools/SearchRate.java 8 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/util/AbstractFutureResult.java 418 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/util/FutureResultTransformer.java 199 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/util/RecursiveFutureResult.java 267 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/util/ResultChain.java 312 ●●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/AbstractAsynchronousConnection.java 27 ●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/AbstractConnectionFactory.java 6 ●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/AsynchronousConnection.java 38 ●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/AuthenticatedConnectionFactory.java 168 ●●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/ConnectionFactory.java 8 ●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/ConnectionFuture.java 150 ●●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/ConnectionPool.java 90 ●●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/ConnectionResultHandler.java 71 ●●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/FutureResult.java 20 ●●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/HeartBeatConnectionFactory.java 61 ●●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/RootDSE.java 10 ●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/SynchronousConnection.java 18 ●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/ldap/LDAPConnectionFactory.java 4 ●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/schema/CoreSchemaImpl.java 2 ●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/schema/Schema.java 635 ●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/schema/SchemaBuilder.java 133 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/AbstractResultFutureImpl.java
@@ -29,236 +29,97 @@
import java.util.concurrent.*;
import java.util.logging.Level;
import org.opends.sdk.ErrorResultException;
import org.opends.sdk.ResultCode;
import org.opends.sdk.ResultFuture;
import org.opends.sdk.FutureResult;
import org.opends.sdk.ResultHandler;
import org.opends.sdk.requests.Requests;
import org.opends.sdk.responses.Responses;
import org.opends.sdk.responses.Result;
import com.sun.opends.sdk.util.StaticUtils;
import com.sun.opends.sdk.util.AbstractFutureResult;
/**
 * Abstract result future implementation.
 *
 * @param <S>
 *          The type of result returned by this future.
 */
public abstract class AbstractResultFutureImpl<R extends Result>
    implements ResultFuture<R>, Runnable
abstract class AbstractResultFutureImpl<S extends Result> extends
    AbstractFutureResult<S> implements FutureResult<S>
{
  private final LDAPConnection connection;
  private final ResultHandler<? super R> handler;
  private final ExecutorService handlerExecutor;
  private final int messageID;
  // Use a semaphore instead of a lock because semaphores can be
  // released by different thread to acquirer.
  private final Semaphore invokerLock;
  private final CountDownLatch latch = new CountDownLatch(1);
  private volatile boolean isCancelled = false;
  private volatile R result = null;
  /**
   * Creates a new LDAP result future.
   *
   * @param messageID
   *          The request message ID.
   * @param handler
   *          The result handler, maybe {@code null}.
   * @param connection
   *          The client connection.
   */
  AbstractResultFutureImpl(int messageID,
      ResultHandler<? super R> handler, LDAPConnection connection,
      ExecutorService handlerExecutor)
      ResultHandler<? super S> handler, LDAPConnection connection)
  {
    super(handler);
    this.messageID = messageID;
    this.handler = handler;
    this.connection = connection;
    this.handlerExecutor = handlerExecutor;
    if (handlerExecutor == null)
    {
      invokerLock = null;
    }
    else
    {
      invokerLock = new Semaphore(1);
    }
  }
  public synchronized boolean cancel(boolean b)
  /**
   * {@inheritDoc}
   */
  protected final ErrorResultException handleCancelRequest()
  {
    if (!isDone())
    {
      isCancelled = true;
      connection.abandon(Requests.newAbandonRequest(messageID));
      latch.countDown();
      return true;
    }
    else
    {
      return false;
    }
    connection.abandon(Requests.newAbandonRequest(messageID));
    return null;
  }
  public R get() throws InterruptedException, ErrorResultException
  {
    latch.await();
    return get0();
  }
  public R get(long timeout, TimeUnit unit)
      throws InterruptedException, TimeoutException,
      ErrorResultException
  {
    if (!latch.await(timeout, unit))
    {
      throw new TimeoutException();
    }
    return get0();
  }
  public int getMessageID()
  /**
   * {@inheritDoc}
   */
  public final int getRequestID()
  {
    return messageID;
  }
  public boolean isCancelled()
  final void adaptErrorResult(Result result)
  {
    return isCancelled;
    S errorResult = newErrorResult(result.getResultCode(), result
        .getDiagnosticMessage(), result.getCause());
    setResultOrError(errorResult);
  }
  public boolean isDone()
  {
    return latch.getCount() == 0;
  }
  public void run()
  final void setResultOrError(S result)
  {
    if (result.getResultCode().isExceptional())
    {
      ErrorResultException e = ErrorResultException.wrap(result);
      handler.handleErrorResult(e);
      handleErrorResult(ErrorResultException.wrap(result));
    }
    else
    {
      handler.handleResult(result);
      handleResult(result);
    }
  }
  final void handleErrorResult(Result result)
  {
    R errorResult = newErrorResult(result.getResultCode(), result
        .getDiagnosticMessage(), result.getCause());
    handleResult(errorResult);
  }
  abstract R newErrorResult(ResultCode resultCode,
  abstract S newErrorResult(ResultCode resultCode,
      String diagnosticMessage, Throwable cause);
  final void handleResult(R result)
  {
    if (!isDone())
    {
      this.result = result;
      if (handler != null)
      {
        invokeHandler(this);
      }
      latch.countDown();
    }
  }
  final void invokeHandler(final Runnable runnable)
  {
    try
    {
      if (handlerExecutor == null)
      {
        runnable.run();
      }
      else
      {
        invokerLock.acquire();
        try
        {
          handlerExecutor.submit(new Runnable()
          {
            public void run()
            {
              try
              {
                runnable.run();
              }
              finally
              {
                invokerLock.release();
              }
            }
          });
        }
        catch (Exception e)
        {
          invokerLock.release();
        }
      }
    }
    catch (InterruptedException e)
    {
      // Thread has been interrupted so give up.
      if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING))
      {
        StaticUtils.DEBUG_LOG.warning(String.format(
            "Invoke thread interrupted: %s", StaticUtils
                .getExceptionMessage(e)));
      }
      // Reset interrupt status.
      Thread.currentThread().interrupt();
    }
  }
  private R get0() throws ErrorResultException
  {
    if (isCancelled())
    {
      throw ErrorResultException.wrap(Responses
          .newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED));
    }
    else if (result.getResultCode().isExceptional())
    {
      throw ErrorResultException.wrap(result);
    }
    else
    {
      return result;
    }
  }
}
sdk/src/com/sun/opends/sdk/ldap/BindResultFutureImpl.java
@@ -29,10 +29,8 @@
import java.util.concurrent.ExecutorService;
import org.opends.sdk.ResultCode;
import org.opends.sdk.ResultFuture;
import org.opends.sdk.FutureResult;
import org.opends.sdk.ResultHandler;
import org.opends.sdk.requests.BindRequest;
import org.opends.sdk.responses.BindResult;
@@ -44,9 +42,9 @@
/**
 * Bind result future implementation.
 */
public final class BindResultFutureImpl extends
final class BindResultFutureImpl extends
    AbstractResultFutureImpl<BindResult> implements
    ResultFuture<BindResult>
    FutureResult<BindResult>
{
  private final BindRequest request;
@@ -56,9 +54,9 @@
  BindResultFutureImpl(int messageID, BindRequest request,
      ResultHandler<? super BindResult> handler,
      LDAPConnection connection, ExecutorService handlerExecutor)
      LDAPConnection connection)
  {
    super(messageID, handler, connection, handlerExecutor);
    super(messageID, handler, connection);
    this.request = request;
  }
sdk/src/com/sun/opends/sdk/ldap/CompareResultFutureImpl.java
@@ -29,10 +29,8 @@
import java.util.concurrent.ExecutorService;
import org.opends.sdk.ResultCode;
import org.opends.sdk.ResultFuture;
import org.opends.sdk.FutureResult;
import org.opends.sdk.ResultHandler;
import org.opends.sdk.requests.CompareRequest;
import org.opends.sdk.responses.CompareResult;
@@ -43,9 +41,9 @@
/**
 * Compare result future implementation.
 */
public final class CompareResultFutureImpl extends
final class CompareResultFutureImpl extends
    AbstractResultFutureImpl<CompareResult> implements
    ResultFuture<CompareResult>
    FutureResult<CompareResult>
{
  private final CompareRequest request;
@@ -53,9 +51,9 @@
  CompareResultFutureImpl(int messageID, CompareRequest request,
      ResultHandler<? super CompareResult> handler,
      LDAPConnection connection, ExecutorService handlerExecutor)
      LDAPConnection connection)
  {
    super(messageID, handler, connection, handlerExecutor);
    super(messageID, handler, connection);
    this.request = request;
  }
sdk/src/com/sun/opends/sdk/ldap/ExtendedResultFutureImpl.java
@@ -29,8 +29,6 @@
import java.util.concurrent.ExecutorService;
import org.opends.sdk.*;
import org.opends.sdk.requests.ExtendedRequest;
import org.opends.sdk.responses.Result;
@@ -40,18 +38,17 @@
/**
 * Extended result future implementation.
 */
public final class ExtendedResultFutureImpl<R extends Result> extends
    AbstractResultFutureImpl<R> implements ResultFuture<R>
final class ExtendedResultFutureImpl<R extends Result> extends
    AbstractResultFutureImpl<R> implements FutureResult<R>
{
  private final ExtendedRequest<R> request;
  ExtendedResultFutureImpl(int messageID, ExtendedRequest<R> request,
      ResultHandler<? super R> handler,
      LDAPConnection connection, ExecutorService handlerExecutor)
      ResultHandler<? super R> handler, LDAPConnection connection)
  {
    super(messageID, handler, connection, handlerExecutor);
    super(messageID, handler, connection);
    this.request = request;
  }
sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java
@@ -92,7 +92,7 @@
          ResultFutureImpl future = (ResultFutureImpl) pendingRequest;
          if (future.getRequest() instanceof AddRequest)
          {
            future.handleResult(result);
            future.setResultOrError(result);
            return;
          }
        }
@@ -142,7 +142,7 @@
                    .setDiagnosticMessage(
                        "An error occurred during SASL authentication")
                    .setCause(e);
                future.handleErrorResult(errorResult);
                future.adaptErrorResult(errorResult);
                return;
              }
            }
@@ -177,7 +177,7 @@
                        ResultCode.CLIENT_SIDE_ENCODING_ERROR)
                        .setCause(e);
                    connectionErrorOccurred(errorResult);
                    future.handleErrorResult(errorResult);
                    future.adaptErrorResult(errorResult);
                  }
                }
              }
@@ -198,7 +198,7 @@
            }
          }
          pendingBindOrStartTLS = -1;
          future.handleResult(result);
          future.setResultOrError(result);
        }
        else
        {
@@ -222,7 +222,7 @@
        if (pendingRequest instanceof CompareResultFutureImpl)
        {
          CompareResultFutureImpl future = (CompareResultFutureImpl) pendingRequest;
          future.handleResult(result);
          future.setResultOrError(result);
        }
        else
        {
@@ -248,7 +248,7 @@
          ResultFutureImpl future = (ResultFutureImpl) pendingRequest;
          if (future.getRequest() instanceof DeleteRequest)
          {
            future.handleResult(result);
            future.setResultOrError(result);
            return;
          }
        }
@@ -339,7 +339,7 @@
              ResultCode.CLIENT_SIDE_DECODING_ERROR)
              .setDiagnosticMessage(de.getLocalizedMessage()).setCause(
                  de);
          extendedFuture.handleErrorResult(errorResult);
          extendedFuture.adaptErrorResult(errorResult);
        }
      }
      else
@@ -409,7 +409,7 @@
          ResultFutureImpl future = (ResultFutureImpl) pendingRequest;
          if (future.getRequest() instanceof ModifyDNRequest)
          {
            future.handleResult(result);
            future.setResultOrError(result);
            return;
          }
        }
@@ -434,7 +434,7 @@
          ResultFutureImpl future = (ResultFutureImpl) pendingRequest;
          if (future.getRequest() instanceof ModifyRequest)
          {
            future.handleResult(result);
            future.setResultOrError(result);
            return;
          }
        }
@@ -457,7 +457,7 @@
        if (pendingRequest instanceof SearchResultFutureImpl)
        {
          ((SearchResultFutureImpl) pendingRequest)
              .handleResult(result);
              .setResultOrError(result);
        }
        else
        {
@@ -666,8 +666,6 @@
  private final Object writeLock = new Object();
  /**
   * Creates a new LDAP connection.
   *
@@ -749,12 +747,12 @@
  /**
   * {@inheritDoc}
   */
  public ResultFuture<Result> add(AddRequest request,
  public FutureResult<Result> add(AddRequest request,
      ResultHandler<Result> handler)
  {
    int messageID = nextMsgID.getAndIncrement();
    ResultFutureImpl future = new ResultFutureImpl(messageID, request,
        handler, this, connFactory.getHandlerInvokers());
        handler, this);
    ASN1StreamWriter asn1Writer = connFactory
        .getASN1Writer(streamWriter);
@@ -764,12 +762,12 @@
      {
        if (connectionInvalidReason != null)
        {
          future.handleErrorResult(connectionInvalidReason);
          future.adaptErrorResult(connectionInvalidReason);
          return future;
        }
        if (pendingBindOrStartTLS > 0)
        {
          future.handleResult(Responses.newResult(
          future.setResultOrError(Responses.newResult(
              ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
              "Bind or Start TLS operation in progress"));
          return future;
@@ -789,7 +787,7 @@
          Result errorResult = Responses.newResult(
              ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
          connectionErrorOccurred(errorResult);
          future.handleErrorResult(errorResult);
          future.adaptErrorResult(errorResult);
        }
      }
    }
@@ -828,12 +826,12 @@
  /**
   * {@inheritDoc}
   */
  public ResultFuture<BindResult> bind(BindRequest request,
  public FutureResult<BindResult> bind(BindRequest request,
      ResultHandler<? super BindResult> handler)
  {
    int messageID = nextMsgID.getAndIncrement();
    BindResultFutureImpl future = new BindResultFutureImpl(messageID,
        request, handler, this, connFactory.getHandlerInvokers());
        request, handler, this);
    ASN1StreamWriter asn1Writer = connFactory
        .getASN1Writer(streamWriter);
@@ -843,19 +841,19 @@
      {
        if (connectionInvalidReason != null)
        {
          future.handleErrorResult(connectionInvalidReason);
          future.adaptErrorResult(connectionInvalidReason);
          return future;
        }
        if (pendingBindOrStartTLS > 0)
        {
          future.handleResult(Responses.newBindResult(
          future.setResultOrError(Responses.newBindResult(
              ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
              "Bind or Start TLS operation in progress"));
          return future;
        }
        if (!pendingRequests.isEmpty())
        {
          future.handleResult(Responses.newBindResult(
          future.setResultOrError(Responses.newBindResult(
              ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
              "There are other operations pending on this connection"));
          return future;
@@ -886,7 +884,7 @@
                  .setDiagnosticMessage(
                      "An error occurred during SASL authentication")
                  .setCause(e);
              future.handleErrorResult(errorResult);
              future.adaptErrorResult(errorResult);
              return future;
            }
          }
@@ -898,7 +896,7 @@
          else
          {
            pendingRequests.remove(messageID);
            future.handleResult(Responses.newBindResult(
            future.setResultOrError(Responses.newBindResult(
                ResultCode.CLIENT_SIDE_AUTH_UNKNOWN)
                .setDiagnosticMessage("Auth type not supported"));
          }
@@ -913,7 +911,7 @@
          Result errorResult = Responses.newResult(
              ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
          connectionErrorOccurred(errorResult);
          future.handleErrorResult(errorResult);
          future.adaptErrorResult(errorResult);
        }
      }
    }
@@ -947,13 +945,12 @@
  /**
   * {@inheritDoc}
   */
  public ResultFuture<CompareResult> compare(CompareRequest request,
  public FutureResult<CompareResult> compare(CompareRequest request,
      ResultHandler<? super CompareResult> handler)
  {
    int messageID = nextMsgID.getAndIncrement();
    CompareResultFutureImpl future = new CompareResultFutureImpl(
        messageID, request, handler, this, connFactory
            .getHandlerInvokers());
        messageID, request, handler, this);
    ASN1StreamWriter asn1Writer = connFactory
        .getASN1Writer(streamWriter);
@@ -963,12 +960,12 @@
      {
        if (connectionInvalidReason != null)
        {
          future.handleErrorResult(connectionInvalidReason);
          future.adaptErrorResult(connectionInvalidReason);
          return future;
        }
        if (pendingBindOrStartTLS > 0)
        {
          future.handleResult(Responses.newCompareResult(
          future.setResultOrError(Responses.newCompareResult(
              ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
              "Bind or Start TLS operation in progress"));
          return future;
@@ -989,7 +986,7 @@
          Result errorResult = Responses.newResult(
              ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
          connectionErrorOccurred(errorResult);
          future.handleErrorResult(errorResult);
          future.adaptErrorResult(errorResult);
        }
      }
    }
@@ -1006,12 +1003,12 @@
  /**
   * {@inheritDoc}
   */
  public ResultFuture<Result> delete(DeleteRequest request,
  public FutureResult<Result> delete(DeleteRequest request,
      ResultHandler<Result> handler)
  {
    int messageID = nextMsgID.getAndIncrement();
    ResultFutureImpl future = new ResultFutureImpl(messageID, request,
        handler, this, connFactory.getHandlerInvokers());
        handler, this);
    ASN1StreamWriter asn1Writer = connFactory
        .getASN1Writer(streamWriter);
@@ -1021,12 +1018,12 @@
      {
        if (connectionInvalidReason != null)
        {
          future.handleErrorResult(connectionInvalidReason);
          future.adaptErrorResult(connectionInvalidReason);
          return future;
        }
        if (pendingBindOrStartTLS > 0)
        {
          future.handleResult(Responses.newResult(
          future.setResultOrError(Responses.newResult(
              ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
              "Bind or Start TLS operation in progress"));
          return future;
@@ -1047,7 +1044,7 @@
          Result errorResult = Responses.newResult(
              ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
          connectionErrorOccurred(errorResult);
          future.handleErrorResult(errorResult);
          future.adaptErrorResult(errorResult);
        }
      }
    }
@@ -1064,13 +1061,12 @@
  /**
   * {@inheritDoc}
   */
  public <R extends Result> ResultFuture<R> extendedRequest(
  public <R extends Result> FutureResult<R> extendedRequest(
      ExtendedRequest<R> request, ResultHandler<? super R> handler)
  {
    int messageID = nextMsgID.getAndIncrement();
    ExtendedResultFutureImpl<R> future = new ExtendedResultFutureImpl<R>(
        messageID, request, handler, this, connFactory
            .getHandlerInvokers());
        messageID, request, handler, this);
    ASN1StreamWriter asn1Writer = connFactory
        .getASN1Writer(streamWriter);
@@ -1080,12 +1076,12 @@
      {
        if (connectionInvalidReason != null)
        {
          future.handleErrorResult(connectionInvalidReason);
          future.adaptErrorResult(connectionInvalidReason);
          return future;
        }
        if (pendingBindOrStartTLS > 0)
        {
          future.handleResult(request.getExtendedOperation()
          future.setResultOrError(request.getExtendedOperation()
              .decodeResponse(ResultCode.OPERATIONS_ERROR, "",
                  "Bind or Start TLS operation in progress"));
          return future;
@@ -1095,14 +1091,14 @@
        {
          if (!pendingRequests.isEmpty())
          {
            future.handleResult(request.getExtendedOperation()
            future.setResultOrError(request.getExtendedOperation()
                .decodeResponse(ResultCode.OPERATIONS_ERROR, "",
                    "There are pending operations on this connection"));
            return future;
          }
          if (isTLSEnabled())
          {
            future.handleResult(request.getExtendedOperation()
            future.setResultOrError(request.getExtendedOperation()
                .decodeResponse(ResultCode.OPERATIONS_ERROR, "",
                    "This connection is already TLS enabled"));
          }
@@ -1125,7 +1121,7 @@
          Result errorResult = Responses.newResult(
              ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
          connectionErrorOccurred(errorResult);
          future.handleErrorResult(errorResult);
          future.adaptErrorResult(errorResult);
        }
      }
    }
@@ -1142,12 +1138,12 @@
  /**
   * {@inheritDoc}
   */
  public ResultFuture<Result> modify(ModifyRequest request,
  public FutureResult<Result> modify(ModifyRequest request,
      ResultHandler<Result> handler)
  {
    int messageID = nextMsgID.getAndIncrement();
    ResultFutureImpl future = new ResultFutureImpl(messageID, request,
        handler, this, connFactory.getHandlerInvokers());
        handler, this);
    ASN1StreamWriter asn1Writer = connFactory
        .getASN1Writer(streamWriter);
@@ -1157,12 +1153,12 @@
      {
        if (connectionInvalidReason != null)
        {
          future.handleErrorResult(connectionInvalidReason);
          future.adaptErrorResult(connectionInvalidReason);
          return future;
        }
        if (pendingBindOrStartTLS > 0)
        {
          future.handleResult(Responses.newResult(
          future.setResultOrError(Responses.newResult(
              ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
              "Bind or Start TLS operation in progress"));
          return future;
@@ -1183,7 +1179,7 @@
          Result errorResult = Responses.newResult(
              ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
          connectionErrorOccurred(errorResult);
          future.handleErrorResult(errorResult);
          future.adaptErrorResult(errorResult);
        }
      }
    }
@@ -1200,12 +1196,12 @@
  /**
   * {@inheritDoc}
   */
  public ResultFuture<Result> modifyDN(ModifyDNRequest request,
  public FutureResult<Result> modifyDN(ModifyDNRequest request,
      ResultHandler<Result> handler)
  {
    int messageID = nextMsgID.getAndIncrement();
    ResultFutureImpl future = new ResultFutureImpl(messageID, request,
        handler, this, connFactory.getHandlerInvokers());
        handler, this);
    ASN1StreamWriter asn1Writer = connFactory
        .getASN1Writer(streamWriter);
@@ -1215,12 +1211,12 @@
      {
        if (connectionInvalidReason != null)
        {
          future.handleErrorResult(connectionInvalidReason);
          future.adaptErrorResult(connectionInvalidReason);
          return future;
        }
        if (pendingBindOrStartTLS > 0)
        {
          future.handleResult(Responses.newResult(
          future.setResultOrError(Responses.newResult(
              ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
              "Bind or Start TLS operation in progress"));
          return future;
@@ -1241,7 +1237,7 @@
          Result errorResult = Responses.newResult(
              ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
          connectionErrorOccurred(errorResult);
          future.handleErrorResult(errorResult);
          future.adaptErrorResult(errorResult);
        }
      }
    }
@@ -1274,14 +1270,13 @@
  /**
   * {@inheritDoc}
   */
  public ResultFuture<Result> search(SearchRequest request,
  public FutureResult<Result> search(SearchRequest request,
      ResultHandler<Result> resultHandler,
      SearchResultHandler searchResulthandler)
  {
    int messageID = nextMsgID.getAndIncrement();
    SearchResultFutureImpl future = new SearchResultFutureImpl(
        messageID, request, resultHandler, searchResulthandler, this,
        connFactory.getHandlerInvokers());
        messageID, request, resultHandler, searchResulthandler, this);
    ASN1StreamWriter asn1Writer = connFactory
        .getASN1Writer(streamWriter);
@@ -1291,12 +1286,12 @@
      {
        if (connectionInvalidReason != null)
        {
          future.handleErrorResult(connectionInvalidReason);
          future.adaptErrorResult(connectionInvalidReason);
          return future;
        }
        if (pendingBindOrStartTLS > 0)
        {
          future.handleResult(Responses.newResult(
          future.setResultOrError(Responses.newResult(
              ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
              "Bind or Start TLS operation in progress"));
          return future;
@@ -1317,7 +1312,7 @@
          Result errorResult = Responses.newResult(
              ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
          connectionErrorOccurred(errorResult);
          future.handleErrorResult(errorResult);
          future.adaptErrorResult(errorResult);
        }
      }
    }
@@ -1407,7 +1402,7 @@
              .getASN1Writer(streamWriter);
          int messageID = nextMsgID.getAndIncrement();
          AbandonRequest abandon = Requests.newAbandonRequest(future
              .getMessageID());
              .getRequestID());
          try
          {
            LDAPEncoder.encodeAbandonRequest(asn1Writer, messageID,
@@ -1424,7 +1419,7 @@
          }
        }
        future.handleErrorResult(reason);
        future.adaptErrorResult(reason);
      }
      pendingRequests.clear();
@@ -1584,14 +1579,14 @@
        }
        catch (ErrorResultException e)
        {
          future.handleErrorResult(e.getResult());
          future.adaptErrorResult(e.getResult());
          return;
        }
      }
      pendingBindOrStartTLS = -1;
    }
    future.handleResult(decodedResponse);
    future.setResultOrError(decodedResponse);
  }
@@ -1604,7 +1599,7 @@
        ResultCode.CLIENT_SIDE_DECODING_ERROR).setDiagnosticMessage(
        "LDAP response message did not match request");
    pendingRequest.handleErrorResult(errorResult);
    pendingRequest.adaptErrorResult(errorResult);
    connectionErrorOccurred(errorResult);
  }
sdk/src/com/sun/opends/sdk/ldap/LDAPConnectionFactoryImpl.java
@@ -88,7 +88,7 @@
  private static class FailedImpl implements
      ConnectionFuture<AsynchronousConnection>
      FutureResult<AsynchronousConnection>
  {
    private volatile ErrorResultException exception;
@@ -136,12 +136,19 @@
    {
      return false;
    }
    public int getRequestID()
    {
      return -1;
    }
  }
  private class ConnectionFutureImpl implements
      ConnectionFuture<AsynchronousConnection>,
  private class ResultFutureImpl implements
      FutureResult<AsynchronousConnection>,
      com.sun.grizzly.CompletionHandler<com.sun.grizzly.Connection>,
      ResultHandler<Result>
  {
@@ -151,18 +158,18 @@
    private volatile Future<com.sun.grizzly.Connection> connectFuture;
    private volatile ResultFuture<?> sslFuture;
    private volatile FutureResult<?> sslFuture;
    private final CountDownLatch latch = new CountDownLatch(1);
    private final ConnectionResultHandler<? super AsynchronousConnection> handler;
    private final ResultHandler<? super AsynchronousConnection> handler;
    private boolean cancelled;
    private ConnectionFutureImpl(
        ConnectionResultHandler<? super AsynchronousConnection> handler)
    private ResultFutureImpl(
        ResultHandler<? super AsynchronousConnection> handler)
    {
      this.handler = handler;
    }
@@ -232,6 +239,13 @@
    public int getRequestID()
    {
      return -1;
    }
    /**
     * {@inheritDoc}
     */
@@ -267,7 +281,7 @@
          latch.countDown();
          if (handler != null)
          {
            handler.handleConnection(this.connection);
            handler.handleResult(this.connection);
          }
        }
        catch (CancellationException ce)
@@ -281,7 +295,7 @@
          latch.countDown();
          if (handler != null)
          {
            handler.handleConnectionError(exception);
            handler.handleErrorResult(exception);
          }
        }
      }
@@ -290,7 +304,7 @@
        latch.countDown();
        if (handler != null)
        {
          handler.handleConnection(this.connection);
          handler.handleResult(this.connection);
        }
      }
    }
@@ -307,7 +321,7 @@
      latch.countDown();
      if (handler != null)
      {
        handler.handleConnectionError(exception);
        handler.handleErrorResult(exception);
      }
    }
@@ -330,7 +344,7 @@
      latch.countDown();
      if (handler != null)
      {
        handler.handleConnection(connection);
        handler.handleResult(connection);
      }
    }
@@ -343,7 +357,7 @@
      latch.countDown();
      if (handler != null)
      {
        handler.handleConnectionError(exception);
        handler.handleErrorResult(exception);
      }
    }
  }
@@ -363,7 +377,6 @@
    if (TCP_NIO_TRANSPORT == null)
    {
      // Create a default transport using the Grizzly framework.
      //
      TCP_NIO_TRANSPORT = TransportFactory.getInstance()
          .createTCPTransport();
      try
@@ -382,23 +395,7 @@
        @Override
        public void run()
        {
          try
          {
            TCP_NIO_TRANSPORT.stop();
          }
          catch (Exception e)
          {
            // Ignore.
          }
          try
          {
            TCP_NIO_TRANSPORT.getWorkerThreadPool().shutdown();
          }
          catch (Exception e)
          {
            // Ignore.
          }
          ShutdownTCPNIOTransport();
        }
      });
@@ -408,6 +405,34 @@
  private synchronized static void ShutdownTCPNIOTransport()
  {
    if (TCP_NIO_TRANSPORT != null)
    {
      try
      {
        TCP_NIO_TRANSPORT.stop();
      }
      catch (Exception e)
      {
        // Ignore.
      }
      // try
      // {
      // TCP_NIO_TRANSPORT.getWorkerThreadPool().shutdown();
      // }
      // catch (Exception e)
      // {
      // // Ignore.
      // }
      TCP_NIO_TRANSPORT = null;
    }
  }
  private final Attribute<LDAPConnection> ldapConnectionAttr;
  private final InetSocketAddress socketAddress;
@@ -482,10 +507,10 @@
  /**
   * {@inheritDoc}
   */
  public ConnectionFuture<AsynchronousConnection> getAsynchronousConnection(
      ConnectionResultHandler<? super AsynchronousConnection> handler)
  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
      ResultHandler<? super AsynchronousConnection> handler)
  {
    ConnectionFutureImpl future = new ConnectionFutureImpl(handler);
    ResultFutureImpl future = new ResultFutureImpl(handler);
    try
    {
sdk/src/com/sun/opends/sdk/ldap/ResultFutureImpl.java
@@ -29,10 +29,8 @@
import java.util.concurrent.ExecutorService;
import org.opends.sdk.ResultCode;
import org.opends.sdk.ResultFuture;
import org.opends.sdk.FutureResult;
import org.opends.sdk.ResultHandler;
import org.opends.sdk.requests.Request;
import org.opends.sdk.responses.Responses;
@@ -44,17 +42,16 @@
 * Result future implementation.
 */
public final class ResultFutureImpl extends
    AbstractResultFutureImpl<Result> implements ResultFuture<Result>
    AbstractResultFutureImpl<Result> implements FutureResult<Result>
{
  private final Request request;
  ResultFutureImpl(int messageID, Request request,
      ResultHandler<Result> handler, LDAPConnection connection,
      ExecutorService handlerExecutor)
      ResultHandler<Result> handler, LDAPConnection connection)
  {
    super(messageID, handler, connection, handlerExecutor);
    super(messageID, handler, connection);
    this.request = request;
  }
sdk/src/com/sun/opends/sdk/ldap/SearchResultFutureImpl.java
@@ -29,10 +29,8 @@
import java.util.concurrent.ExecutorService;
import org.opends.sdk.ResultCode;
import org.opends.sdk.ResultFuture;
import org.opends.sdk.FutureResult;
import org.opends.sdk.ResultHandler;
import org.opends.sdk.SearchResultHandler;
import org.opends.sdk.requests.SearchRequest;
@@ -46,8 +44,8 @@
/**
 * Search result future implementation.
 */
public final class SearchResultFutureImpl extends
    AbstractResultFutureImpl<Result> implements ResultFuture<Result>
final class SearchResultFutureImpl extends
    AbstractResultFutureImpl<Result> implements FutureResult<Result>
{
  private final SearchResultHandler searchResultHandler;
@@ -58,50 +56,43 @@
  SearchResultFutureImpl(int messageID, SearchRequest request,
      ResultHandler<Result> resultHandler,
      SearchResultHandler searchResultHandler,
      LDAPConnection connection, ExecutorService handlerExecutor)
      SearchResultHandler searchResultHandler, LDAPConnection connection)
  {
    super(messageID, resultHandler, connection, handlerExecutor);
    super(messageID, resultHandler, connection);
    this.request = request;
    this.searchResultHandler = searchResultHandler;
  }
  void handleSearchResultEntry(
      final SearchResultEntry entry)
  void handleSearchResultEntry(SearchResultEntry entry)
  {
    // FIXME: there's a potential race condition here - the future could
    // get cancelled between the isDone() call and the handler
    // invocation. We'd need to add support for intermediate handlers in
    // the synchronizer.
    if (!isDone())
    {
      if (searchResultHandler != null)
      {
        invokeHandler(new Runnable()
        {
          public void run()
          {
            searchResultHandler.handleEntry(entry);
          }
        });
        searchResultHandler.handleEntry(entry);
      }
    }
  }
  void handleSearchResultReference(
      final SearchResultReference reference)
  void handleSearchResultReference(SearchResultReference reference)
  {
    // FIXME: there's a potential race condition here - the future could
    // get cancelled between the isDone() call and the handler
    // invocation. We'd need to add support for intermediate handlers in
    // the synchronizer.
    if (!isDone())
    {
      if (searchResultHandler != null)
      {
        invokeHandler(new Runnable()
        {
          public void run()
          {
            searchResultHandler.handleReference(reference);
          }
        });
        searchResultHandler.handleReference(reference);
      }
    }
  }
sdk/src/com/sun/opends/sdk/tools/ArgumentParserConnectionFactory.java
@@ -349,8 +349,8 @@
  /**
   * {@inheritDoc}
   */
  public ConnectionFuture<? extends AsynchronousConnection> getAsynchronousConnection(
      ConnectionResultHandler<? super AsynchronousConnection> handler)
  public FutureResult<? extends AsynchronousConnection> getAsynchronousConnection(
      ResultHandler<? super AsynchronousConnection> handler)
  {
    return connFactory.getAsynchronousConnection(handler);
  }
sdk/src/com/sun/opends/sdk/tools/LDAPCompare.java
@@ -69,11 +69,7 @@
  public static void main(String[] args)
  {
    int retCode = mainCompare(args, System.in, System.out, System.err);
    if (retCode != 0)
    {
      System.exit(filterExitCode(retCode));
    }
    System.exit(filterExitCode(retCode));
  }
sdk/src/com/sun/opends/sdk/tools/LDAPModify.java
@@ -80,11 +80,7 @@
  public static void main(String[] args)
  {
    int retCode = mainModify(args, System.in, System.out, System.err);
    if (retCode != 0)
    {
      System.exit(filterExitCode(retCode));
    }
    System.exit(filterExitCode(retCode));
  }
sdk/src/com/sun/opends/sdk/tools/LDAPPasswordModify.java
@@ -41,11 +41,7 @@
  public static void main(String[] args)
  {
    int retCode = mainPasswordModify(args, System.in, System.out, System.err);
    if (retCode != 0)
    {
      System.exit(filterExitCode(retCode));
    }
    System.exit(filterExitCode(retCode));
  }
sdk/src/com/sun/opends/sdk/tools/LDAPSearch.java
@@ -31,6 +31,7 @@
import static com.sun.opends.sdk.messages.Messages.*;
import static com.sun.opends.sdk.tools.ToolConstants.*;
import static com.sun.opends.sdk.tools.Utils.*;
import java.io.*;
import java.util.ArrayList;
@@ -186,11 +187,7 @@
  {
    int retCode = mainSearch(args, false, System.in, System.out,
        System.err);
    if (retCode != 0)
    {
      System.exit(Utils.filterExitCode(retCode));
    }
    System.exit(filterExitCode(retCode));
  }
sdk/src/com/sun/opends/sdk/tools/ModRate.java
@@ -64,11 +64,7 @@
  public static void main(String[] args)
  {
    int retCode = mainModRate(args, System.in, System.out, System.err);
    if (retCode != 0)
    {
      System.exit(filterExitCode(retCode));
    }
    System.exit(filterExitCode(retCode));
  }
@@ -295,7 +291,7 @@
      public ResultFuture<?> performOperation(
      public FutureResult<?> performOperation(
          AsynchronousConnection connection,
          ResultHandler<Result> handler, DataSource[] dataSources)
      {
sdk/src/com/sun/opends/sdk/tools/PerformanceRunner.java
@@ -370,7 +370,7 @@
    public abstract ResultFuture<?> performOperation(
    public abstract FutureResult<?> performOperation(
        AsynchronousConnection connection, R handler,
        DataSource[] dataSources);
@@ -394,7 +394,7 @@
        }
      }
      ResultFuture<?> future;
      FutureResult<?> future;
      AsynchronousConnection connection;
      R handler;
sdk/src/com/sun/opends/sdk/tools/SearchRate.java
@@ -71,11 +71,7 @@
  {
    int retCode = mainSearchRate(args, System.in, System.out,
        System.err);
    if (retCode != 0)
    {
      System.exit(filterExitCode(retCode));
    }
    System.exit(filterExitCode(retCode));
  }
@@ -375,7 +371,7 @@
      public ResultFuture<?> performOperation(
      public FutureResult<?> performOperation(
          AsynchronousConnection connection,
          SearchStatsHandler handler, DataSource[] dataSources)
      {
sdk/src/com/sun/opends/sdk/util/AbstractFutureResult.java
New file
@@ -0,0 +1,418 @@
/*
 * 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.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import org.opends.sdk.*;
import org.opends.sdk.responses.Responses;
import org.opends.sdk.responses.Result;
/**
 * This class provides a skeletal implementation of the {@code
 * FutureResult} interface, to minimize the effort required to implement
 * this interface.
 * <p>
 * This {@code FutureResult} implementation provides the following
 * features:
 * <ul>
 * <li>The {@link #get} methods throw {@link ErrorResultException}s
 * instead of the more generic {@code ExecutionException}s.
 * <li>The {@link #get} methods never throw {@code
 * CancellationException} since requests in this SDK can usually be
 * cancelled via other external means (e.g. the {@code Cancel} extended
 * operation) for which there are well defined error results. Therefore
 * cancellation is always signalled by throwing a
 * {@link CancelledResultException} in order to be consistent with other
 * error results.
 * <li>A {@link ResultHandler} can be provided to the constructor. The
 * result handler will be invoked immediately after the result or error
 * is received but before threads blocked on {@link #get} are released.
 * More specifically, result handler invocation <i>happens-before</i> a
 * call to {@link #get}. <b>NOTE:</b> a result handler which attempts to
 * call {@link #get} will deadlock.
 * <li>Sub-classes may choose to implement specific cancellation cleanup
 * by implementing the {@link #handleCancelRequest} method.
 * </ul>
 *
 * @param <M>
 *          The type of result returned by this completion future.
 */
public abstract class AbstractFutureResult<M> implements
    FutureResult<M>, ResultHandler<M>
{
  @SuppressWarnings("serial")
  private final class Sync extends AbstractQueuedSynchronizer
  {
    // State value representing the initial state before a result has
    // been received.
    private static final int WAITING = 0;
    // State value representing that a result has been received and is
    // being processed.
    private static final int PENDING = 1;
    // State value representing that the request was cancelled.
    private static final int CANCELLED = 2;
    // State value representing that the request has failed.
    private static final int FAIL = 3;
    // State value representing that the request has succeeded.
    private static final int SUCCESS = 4;
    // These do not need to be volatile since their values are published
    // by updating the state after they are set and reading the state
    // immediately before they are read.
    private ErrorResultException errorResult = null;
    private M result = null;
    private M get0() throws ErrorResultException
    {
      if (errorResult != null)
      {
        // State must be FAILED or CANCELLED.
        throw errorResult;
      }
      else
      {
        // State must be SUCCESS.
        return result;
      }
    }
    private boolean setStatePending()
    {
      for (;;)
      {
        final int s = getState();
        if (s != WAITING)
        {
          return false;
        }
        if (compareAndSetState(s, PENDING))
        {
          return true;
        }
      }
    }
    /**
     * Allow all threads to acquire if future has completed.
     */
    protected int tryAcquireShared(int ignore)
    {
      return innerIsDone() ? 1 : -1;
    }
    /**
     * Signal that the future has completed and threads waiting on get()
     * can be released.
     */
    protected boolean tryReleaseShared(int finalState)
    {
      // Ensures that errorResult/result is published.
      setState(finalState);
      return true;
    }
    boolean innerCancel(boolean mayInterruptIfRunning)
    {
      if (!setStatePending())
      {
        return false;
      }
      // Perform implementation defined cancellation.
      ErrorResultException errorResult = handleCancelRequest(mayInterruptIfRunning);
      if (errorResult == null)
      {
        final Result result = Responses
            .newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED);
        errorResult = ErrorResultException.wrap(result);
      }
      this.errorResult = errorResult;
      try
      {
        // Invoke error result completion handler.
        if (handler != null)
        {
          handler.handleErrorResult(errorResult);
        }
      }
      finally
      {
        releaseShared(CANCELLED); // Publishes errorResult.
      }
      return true;
    }
    M innerGet() throws ErrorResultException, InterruptedException
    {
      acquireSharedInterruptibly(0);
      return get0();
    }
    M innerGet(long nanosTimeout) throws ErrorResultException,
        TimeoutException, InterruptedException
    {
      if (!tryAcquireSharedNanos(0, nanosTimeout))
      {
        throw new TimeoutException();
      }
      else
      {
        return get0();
      }
    }
    boolean innerIsCancelled()
    {
      return getState() == CANCELLED;
    }
    boolean innerIsDone()
    {
      return getState() > 1;
    }
    void innerSetErrorResult(ErrorResultException errorResult)
    {
      if (setStatePending())
      {
        this.errorResult = errorResult;
        try
        {
          // Invoke error result completion handler.
          if (handler != null)
          {
            handler.handleErrorResult(errorResult);
          }
        }
        finally
        {
          releaseShared(FAIL); // Publishes errorResult.
        }
      }
    }
    void innerSetResult(M result)
    {
      if (setStatePending())
      {
        this.result = result;
        try
        {
          // Invoke result completion handler.
          if (handler != null)
          {
            handler.handleResult(result);
          }
        }
        finally
        {
          releaseShared(SUCCESS); // Publishes result.
        }
      }
    }
  }
  private final Sync sync = new Sync();
  private final ResultHandler<? super M> handler;
  /**
   * Creates a new abstract future result with the provided result
   * handler.
   *
   * @param handler
   *          A result handler which will be forwarded the result or
   *          error when it arrives.
   */
  protected AbstractFutureResult(ResultHandler<? super M> handler)
  {
    this.handler = handler;
  }
  /**
   * {@inheritDoc}
   */
  public final boolean cancel(boolean mayInterruptIfRunning)
  {
    return sync.innerCancel(mayInterruptIfRunning);
  }
  /**
   * {@inheritDoc}
   */
  public final M get() throws ErrorResultException,
      InterruptedException
  {
    return sync.innerGet();
  }
  /**
   * {@inheritDoc}
   */
  public final M get(long timeout, TimeUnit unit)
      throws ErrorResultException, TimeoutException,
      InterruptedException
  {
    return sync.innerGet(unit.toNanos(timeout));
  }
  /**
   * Sets the error result associated with this future. If ({@code
   * isDone() == true}) then the error result will be ignored, otherwise
   * the result handler will be invoked if one was provided and, on
   * return, any threads waiting on {@link #get} will be released and
   * the provided error result will be thrown.
   *
   * @param errorResult
   *          The error result.
   */
  public final void handleErrorResult(ErrorResultException errorResult)
  {
    sync.innerSetErrorResult(errorResult);
  }
  /**
   * Sets the result associated with this future. If ({@code isDone() ==
   * true}) then the result will be ignored, otherwise the result
   * handler will be invoked if one was provided and, on return, any
   * threads waiting on {@link #get} will be released and the provided
   * result will be returned.
   *
   * @param result
   *          The result.
   */
  public final void handleResult(M result)
  {
    sync.innerSetResult(result);
  }
  /**
   * {@inheritDoc}
   */
  public final boolean isCancelled()
  {
    return sync.innerIsCancelled();
  }
  /**
   * {@inheritDoc}
   */
  public final boolean isDone()
  {
    return sync.innerIsDone();
  }
  /**
   * Invoked when {@link #cancel} is called and {@code isDone() ==
   * false} and immediately before any threads waiting on {@link #get}
   * are released. Implementations may choose to return a custom error
   * result if needed or return {@code null} if the following default
   * error result is acceptable:
   *
   * <pre>
   * Result result = Responses
   *     .newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED);
   * </pre>
   *
   * In addition, implementations may perform other cleanup, for
   * example, by issuing an LDAP abandon request. The default
   * implementation is to do nothing.
   *
   * @param mayInterruptIfRunning
   *          {@code true} if the thread executing executing the
   *          response handler should be interrupted; otherwise,
   *          in-progress response handlers are allowed to complete.
   * @return The custom error result, or {@code null} if the default is
   *         acceptable.
   */
  protected ErrorResultException handleCancelRequest(
      boolean mayInterruptIfRunning)
  {
    // Do nothing by default.
    return null;
  }
}
sdk/src/com/sun/opends/sdk/util/FutureResultTransformer.java
File was renamed from sdk/src/com/sun/opends/sdk/util/ResultTransformer.java
@@ -29,62 +29,39 @@
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.FutureResult;
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.
 * An implementation of the {@code FutureResult} interface which
 * transforms the result of an asynchronous operation from one type to
 * another. The implementation ensures that the transformed is computed
 * only once.
 *
 * @param <M>
 *          The type of the inner result.
 * @param <N>
 *          The type of the outer result.
 */
public abstract class ResultTransformer<M, N> implements
    ResultFuture<N>, ResultHandler<M>
public abstract class FutureResultTransformer<M, N> implements
    FutureResult<N>, ResultHandler<M>
{
  private final ResultHandler<? super N> handler;
  private volatile ResultFuture<M> future = null;
  private volatile FutureResult<M> future = null;
  // These do not need to be volatile since the future acts as a memory
  // barrier.
  private N transformedResult = 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;
  private ErrorResultException transformedErrorResult = null;
@@ -95,7 +72,7 @@
   * @param handler
   *          The outer result handler.
   */
  protected ResultTransformer(ResultHandler<? super N> handler)
  protected FutureResultTransformer(ResultHandler<? super N> handler)
  {
    this.handler = handler;
  }
@@ -105,39 +82,6 @@
  /**
   * {@inheritDoc}
   */
  public final void handleErrorResult(ErrorResultException error)
  {
    if (handler != null)
    {
      handler.handleErrorResult(error);
    }
  }
  /**
   * {@inheritDoc}
   */
  public final void handleResult(M result)
  {
    if (handler != null)
    {
      try
      {
        handler.handleResult(transformResult(result));
      }
      catch (ErrorResultException e)
      {
        handler.handleErrorResult(e);
      }
    }
  }
  /**
   * {@inheritDoc}
   */
  public final boolean cancel(boolean mayInterruptIfRunning)
  {
    return future.cancel(mayInterruptIfRunning);
@@ -149,9 +93,12 @@
   * {@inheritDoc}
   */
  public final N get() throws ErrorResultException,
      CancellationException, InterruptedException
      InterruptedException
  {
    return transformResult(future.get());
    future.get();
    // The handlers are guaranteed to have been invoked at this point.
    return get0();
  }
@@ -161,9 +108,12 @@
   */
  public final N get(long timeout, TimeUnit unit)
      throws ErrorResultException, TimeoutException,
      CancellationException, InterruptedException
      InterruptedException
  {
    return transformResult(future.get(timeout, unit));
    future.get(timeout, unit);
    // The handlers are guaranteed to have been invoked at this point.
    return get0();
  }
@@ -171,9 +121,48 @@
  /**
   * {@inheritDoc}
   */
  public final int getMessageID()
  public final int getRequestID()
  {
    return future.getMessageID();
    return future.getRequestID();
  }
  /**
   * {@inheritDoc}
   */
  public final void handleErrorResult(ErrorResultException error)
  {
    transformedErrorResult = transformErrorResult(error);
    if (handler != null)
    {
      handler.handleErrorResult(transformedErrorResult);
    }
  }
  /**
   * {@inheritDoc}
   */
  public final void handleResult(M result)
  {
    try
    {
      transformedResult = transformResult(result);
      if (handler != null)
      {
        handler.handleResult(transformedResult);
      }
    }
    catch (final ErrorResultException e)
    {
      transformedErrorResult = e;
      if (handler != null)
      {
        handler.handleErrorResult(transformedErrorResult);
      }
    }
  }
@@ -196,4 +185,64 @@
    return future.isDone();
  }
  /**
   * 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 setFutureResult(FutureResult<M> future)
  {
    this.future = future;
  }
  private N get0() throws ErrorResultException
  {
    if (transformedErrorResult != null)
    {
      throw transformedErrorResult;
    }
    else
    {
      return transformedResult;
    }
  }
  /**
   * Transforms the inner error result to an outer error result. The
   * default implementation is to return the inner error result.
   *
   * @param errorResult
   *          The inner error result.
   * @return The outer error result.
   */
  protected ErrorResultException transformErrorResult(
      ErrorResultException errorResult)
  {
    return errorResult;
  }
  /**
   * 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;
}
sdk/src/com/sun/opends/sdk/util/RecursiveFutureResult.java
New file
@@ -0,0 +1,267 @@
/*
 * 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.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.opends.sdk.ErrorResultException;
import org.opends.sdk.FutureResult;
import org.opends.sdk.ResultHandler;
/**
 * An implementation of the {@code FutureResult} interface which can be
 * used to combine a sequence of two asynchronous operations into a
 * single future result. Implementations should override the methods
 * {@link #chainResult} and {@link #chainErrorResult} in order to define
 * the second asynchronous operation.
 *
 * @param <M>
 *          The type of the inner result.
 * @param <N>
 *          The type of the outer result.
 */
public abstract class RecursiveFutureResult<M, N> implements
    FutureResult<N>, ResultHandler<M>
{
  private final class FutureResultImpl extends AbstractFutureResult<N>
  {
    private FutureResultImpl(ResultHandler<? super N> handler)
    {
      super(handler);
    }
    public int getRequestID()
    {
      return innerFuture.getRequestID();
    }
    /**
     * {@inheritDoc}
     */
    protected ErrorResultException handleCancelRequest(
        boolean mayInterruptIfRunning)
    {
      innerFuture.cancel(mayInterruptIfRunning);
      if (outerFuture != null)
      {
        outerFuture.cancel(mayInterruptIfRunning);
      }
      return null;
    }
  }
  private final FutureResultImpl impl;
  private volatile FutureResult<M> innerFuture = null;
  // This does not need to be volatile since the inner future acts as a
  // memory barrier.
  private FutureResult<N> outerFuture = 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 RecursiveFutureResult(ResultHandler<? super N> handler)
  {
    this.impl = new FutureResultImpl(handler);
  }
  /**
   * {@inheritDoc}
   */
  public final boolean cancel(boolean mayInterruptIfRunning)
  {
    return impl.cancel(mayInterruptIfRunning);
  }
  /**
   * {@inheritDoc}
   */
  public final N get() throws ErrorResultException,
      InterruptedException
  {
    return impl.get();
  }
  /**
   * {@inheritDoc}
   */
  public final N get(long timeout, TimeUnit unit)
      throws ErrorResultException, TimeoutException,
      InterruptedException
  {
    return impl.get(timeout, unit);
  }
  /**
   * {@inheritDoc}
   */
  public final int getRequestID()
  {
    return impl.getRequestID();
  }
  /**
   * {@inheritDoc}
   */
  public final void handleErrorResult(ErrorResultException error)
  {
    try
    {
      outerFuture = chainErrorResult(error, impl);
    }
    catch (final ErrorResultException e)
    {
      impl.handleErrorResult(e);
    }
  }
  /**
   * {@inheritDoc}
   */
  public final void handleResult(M result)
  {
    try
    {
      outerFuture = chainResult(result, impl);
    }
    catch (final ErrorResultException e)
    {
      impl.handleErrorResult(e);
    }
  }
  /**
   * {@inheritDoc}
   */
  public final boolean isCancelled()
  {
    return impl.isCancelled();
  }
  /**
   * {@inheritDoc}
   */
  public final boolean isDone()
  {
    return impl.isDone();
  }
  /**
   * 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 setFutureResult(FutureResult<M> future)
  {
    this.innerFuture = future;
  }
  /**
   * 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 FutureResult<N> chainErrorResult(
      ErrorResultException innerError, ResultHandler<? super N> 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 FutureResult<N> chainResult(M innerResult,
      ResultHandler<? super N> handler) throws ErrorResultException;
}
sdk/src/com/sun/opends/sdk/util/ResultChain.java
File was deleted
sdk/src/org/opends/sdk/AbstractAsynchronousConnection.java
@@ -32,7 +32,6 @@
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;
@@ -56,7 +55,7 @@
{
  private static final class SingleEntryFuture implements
      ResultFuture<SearchResultEntry>, ResultHandler<Result>,
      FutureResult<SearchResultEntry>, ResultHandler<Result>,
      SearchResultHandler
  {
    private final ResultHandler<? super SearchResultEntry> handler;
@@ -67,7 +66,7 @@
    private volatile int entryCount = 0;
    private volatile ResultFuture<Result> future = null;
    private volatile FutureResult<Result> future = null;
@@ -87,7 +86,7 @@
    public SearchResultEntry get() throws ErrorResultException,
        CancellationException, InterruptedException
        InterruptedException
    {
      future.get();
      return get0();
@@ -97,7 +96,7 @@
    public SearchResultEntry get(long timeout, TimeUnit unit)
        throws ErrorResultException, TimeoutException,
        CancellationException, InterruptedException
        InterruptedException
    {
      future.get(timeout, unit);
      return get0();
@@ -145,9 +144,9 @@
    public int getMessageID()
    public int getRequestID()
    {
      return future.getMessageID();
      return future.getRequestID();
    }
@@ -214,7 +213,7 @@
    private void setResultFuture(ResultFuture<Result> future)
    private void setResultFuture(FutureResult<Result> future)
    {
      this.future = future;
    }
@@ -245,7 +244,7 @@
  /**
   * {@inheritDoc}
   */
  public ResultFuture<SearchResultEntry> readEntry(DN name,
  public FutureResult<SearchResultEntry> readEntry(DN name,
      Collection<String> attributeDescriptions,
      ResultHandler<? super SearchResultEntry> handler)
      throws UnsupportedOperationException, IllegalStateException,
@@ -262,7 +261,7 @@
  /**
   * {@inheritDoc}
   */
  public ResultFuture<RootDSE> readRootDSE(
  public FutureResult<RootDSE> readRootDSE(
      ResultHandler<RootDSE> handler)
      throws UnsupportedOperationException, IllegalStateException
  {
@@ -274,7 +273,7 @@
  /**
   * {@inheritDoc}
   */
  public ResultFuture<Schema> readSchema(DN name,
  public FutureResult<Schema> readSchema(DN name,
      ResultHandler<Schema> handler)
      throws UnsupportedOperationException, IllegalStateException
  {
@@ -286,7 +285,7 @@
  /**
   * {@inheritDoc}
   */
  public ResultFuture<Schema> readSchemaForEntry(DN name,
  public FutureResult<Schema> readSchemaForEntry(DN name,
      ResultHandler<Schema> handler)
      throws UnsupportedOperationException, IllegalStateException
  {
@@ -298,14 +297,14 @@
  /**
   * {@inheritDoc}
   */
  public ResultFuture<SearchResultEntry> searchSingleEntry(
  public FutureResult<SearchResultEntry> searchSingleEntry(
      SearchRequest request,
      ResultHandler<? super SearchResultEntry> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    final SingleEntryFuture innerFuture = new SingleEntryFuture(handler);
    final ResultFuture<Result> future = search(request, innerFuture,
    final FutureResult<Result> future = search(request, innerFuture,
        innerFuture);
    innerFuture.setResultFuture(future);
    return innerFuture;
sdk/src/org/opends/sdk/AbstractConnectionFactory.java
@@ -59,8 +59,8 @@
  /**
   * {@inheritDoc}
   */
  public abstract ConnectionFuture<? extends C> getAsynchronousConnection(
      ConnectionResultHandler<? super C> handler);
  public abstract FutureResult<? extends C> getAsynchronousConnection(
      ResultHandler<? super C> handler);
@@ -104,7 +104,7 @@
  protected final C blockingGetAsynchronousConnection()
      throws ErrorResultException
  {
    ConnectionFuture<? extends C> future = getAsynchronousConnection(null);
    FutureResult<? extends C> future = getAsynchronousConnection(null);
    try
    {
      return future.get();
sdk/src/org/opends/sdk/AsynchronousConnection.java
@@ -50,10 +50,10 @@
 * <h3>Operation processing</h3>
 * <p>
 * All operations are performed asynchronously and return a
 * {@link ResultFuture} or sub-type thereof which can be used for
 * retrieving the result using the {@link ResultFuture#get} method.
 * {@link FutureResult} or sub-type thereof which can be used for
 * retrieving the result using the {@link FutureResult#get} method.
 * Operation failures, for whatever reason, are signalled by the
 * {@link ResultFuture#get()} method throwing an
 * {@link FutureResult#get()} method throwing an
 * {@link ErrorResultException}.
 * <p>
 * Synchronous operations are easily simulated by immediately getting
@@ -75,9 +75,9 @@
 * Connection connection2 = ...;
 * AddRequest request = ...;
 * // Add the entry to the first server (don't block).
 * ResultFuture future1 = connection1.add(request);
 * FutureResult future1 = connection1.add(request);
 * // Add the entry to the second server (in parallel).
 * ResultFuture future2 = connection2.add(request);
 * FutureResult future2 = connection2.add(request);
 * // Total time = is O(1) instead of O(n).
 * future1.get();
 * future2.get();
@@ -142,7 +142,7 @@
   * abandon request.
   * <p>
   * <b>Note:</b> a more convenient approach to abandoning unfinished
   * operations is provided via the {@link ResultFuture#cancel(boolean)}
   * operations is provided via the {@link FutureResult#cancel(boolean)}
   * method.
   *
   * @param request
@@ -180,7 +180,7 @@
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  ResultFuture<Result> add(AddRequest request,
  FutureResult<Result> add(AddRequest request,
      ResultHandler<Result> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -225,7 +225,7 @@
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  ResultFuture<BindResult> bind(BindRequest request,
  FutureResult<BindResult> bind(BindRequest request,
      ResultHandler<? super BindResult> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -302,7 +302,7 @@
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  ResultFuture<CompareResult> compare(CompareRequest request,
  FutureResult<CompareResult> compare(CompareRequest request,
      ResultHandler<? super CompareResult> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -328,7 +328,7 @@
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  ResultFuture<Result> delete(DeleteRequest request,
  FutureResult<Result> delete(DeleteRequest request,
      ResultHandler<Result> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -356,7 +356,7 @@
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  <R extends Result> ResultFuture<R> extendedRequest(
  <R extends Result> FutureResult<R> extendedRequest(
      ExtendedRequest<R> request, ResultHandler<? super R> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -395,7 +395,7 @@
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  ResultFuture<Result> modify(ModifyRequest request,
  FutureResult<Result> modify(ModifyRequest request,
      ResultHandler<Result> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -421,7 +421,7 @@
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  ResultFuture<Result> modifyDN(ModifyDNRequest request,
  FutureResult<Result> modifyDN(ModifyDNRequest request,
      ResultHandler<Result> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -462,7 +462,7 @@
   * @throws NullPointerException
   *           If the {@code name} was {@code null}.
   */
  ResultFuture<SearchResultEntry> readEntry(DN name,
  FutureResult<SearchResultEntry> readEntry(DN name,
      Collection<String> attributeDescriptions,
      ResultHandler<? super SearchResultEntry> handler)
      throws UnsupportedOperationException, IllegalStateException,
@@ -488,7 +488,7 @@
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   */
  ResultFuture<RootDSE> readRootDSE(ResultHandler<RootDSE> handler)
  FutureResult<RootDSE> readRootDSE(ResultHandler<RootDSE> handler)
      throws UnsupportedOperationException, IllegalStateException;
@@ -518,7 +518,7 @@
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   */
  ResultFuture<Schema> readSchema(DN name, ResultHandler<Schema> handler)
  FutureResult<Schema> readSchema(DN name, ResultHandler<Schema> handler)
      throws UnsupportedOperationException, IllegalStateException;
@@ -551,7 +551,7 @@
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   */
  ResultFuture<Schema> readSchemaForEntry(DN name,
  FutureResult<Schema> readSchemaForEntry(DN name,
      ResultHandler<Schema> handler)
      throws UnsupportedOperationException, IllegalStateException;
@@ -596,7 +596,7 @@
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  ResultFuture<Result> search(SearchRequest request,
  FutureResult<Result> search(SearchRequest request,
      ResultHandler<Result> resultHandler,
      SearchResultHandler searchResulthandler)
      throws UnsupportedOperationException, IllegalStateException,
@@ -630,7 +630,7 @@
   * @throws NullPointerException
   *           If the {@code request} was {@code null}.
   */
  ResultFuture<SearchResultEntry> searchSingleEntry(
  FutureResult<SearchResultEntry> searchSingleEntry(
      SearchRequest request,
      ResultHandler<? super SearchResultEntry> handler)
      throws UnsupportedOperationException, IllegalStateException,
sdk/src/org/opends/sdk/AuthenticatedConnectionFactory.java
@@ -105,15 +105,15 @@
    /**
     * {@inheritDoc}
     */
    public ConnectionFuture<AuthenticatedAsynchronousConnection> getAsynchronousConnection(
        ConnectionResultHandler<? super AuthenticatedAsynchronousConnection> handler)
    public FutureResult<AuthenticatedAsynchronousConnection> getAsynchronousConnection(
        ResultHandler<? super AuthenticatedAsynchronousConnection> handler)
    {
      // TODO: bug here? if allowRebind= false then bind will never
      // happen
      ConnectionFutureImpl future = new ConnectionFutureImpl(
      ResultFutureImpl future = new ResultFutureImpl(
          allowRebinds ? request : null, handler);
      future.connectFuture = parentFactory
          .getAsynchronousConnection(future);
          .getAsynchronousConnection(future.connectionHandler);
      return future;
    }
@@ -279,7 +279,7 @@
    public ResultFuture<Result> add(AddRequest request,
    public FutureResult<Result> add(AddRequest request,
        ResultHandler<Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -303,7 +303,7 @@
     * connections. This method will always throw {@code
     * UnsupportedOperationException}.
     */
    public ResultFuture<BindResult> bind(BindRequest request,
    public FutureResult<BindResult> bind(BindRequest request,
        ResultHandler<? super BindResult> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -328,7 +328,7 @@
    public ResultFuture<CompareResult> compare(CompareRequest request,
    public FutureResult<CompareResult> compare(CompareRequest request,
        ResultHandler<? super CompareResult> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -338,7 +338,7 @@
    public ResultFuture<Result> delete(DeleteRequest request,
    public FutureResult<Result> delete(DeleteRequest request,
        ResultHandler<Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -348,7 +348,7 @@
    public <R extends Result> ResultFuture<R> extendedRequest(
    public <R extends Result> FutureResult<R> extendedRequest(
        ExtendedRequest<R> request, ResultHandler<? super R> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -358,7 +358,7 @@
    public ResultFuture<Result> modify(ModifyRequest request,
    public FutureResult<Result> modify(ModifyRequest request,
        ResultHandler<Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -368,7 +368,7 @@
    public ResultFuture<Result> modifyDN(ModifyDNRequest request,
    public FutureResult<Result> modifyDN(ModifyDNRequest request,
        ResultHandler<Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -394,7 +394,7 @@
     *           If this connection has already been closed, i.e. if
     *           {@code isClosed() == true}.
     */
    public ResultFuture<BindResult> rebind(
    public FutureResult<BindResult> rebind(
        ResultHandler<? super BindResult> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
@@ -450,7 +450,7 @@
    public ResultFuture<Result> search(SearchRequest request,
    public FutureResult<Result> search(SearchRequest request,
        ResultHandler<Result> resultHandler,
        SearchResultHandler searchResulthandler)
        throws UnsupportedOperationException, IllegalStateException,
@@ -475,7 +475,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<RootDSE> readRootDSE(
    public FutureResult<RootDSE> readRootDSE(
        ResultHandler<RootDSE> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
@@ -487,7 +487,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<SearchResultEntry> readEntry(DN name,
    public FutureResult<SearchResultEntry> readEntry(DN name,
        Collection<String> attributeDescriptions,
        ResultHandler<? super SearchResultEntry> resultHandler)
        throws UnsupportedOperationException, IllegalStateException,
@@ -502,7 +502,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<SearchResultEntry> searchSingleEntry(
    public FutureResult<SearchResultEntry> searchSingleEntry(
        SearchRequest request,
        ResultHandler<? super SearchResultEntry> resultHandler)
        throws UnsupportedOperationException, IllegalStateException,
@@ -516,7 +516,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<Schema> readSchemaForEntry(DN name,
    public FutureResult<Schema> readSchemaForEntry(DN name,
        ResultHandler<Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
@@ -528,7 +528,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<Schema> readSchema(DN name,
    public FutureResult<Schema> readSchema(DN name,
        ResultHandler<Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
@@ -560,24 +560,86 @@
  private static final class ConnectionFutureImpl implements
      ConnectionFuture<AuthenticatedAsynchronousConnection>,
      ConnectionResultHandler<AsynchronousConnection>,
      ResultHandler<BindResult>
  private static final class ResultFutureImpl implements
      FutureResult<AuthenticatedAsynchronousConnection>
  {
    private final class ConnectionResultHandler implements
        ResultHandler<AsynchronousConnection>
    {
      public void handleResult(AsynchronousConnection conn)
      {
        connection = conn;
        bindFuture = connection.bind(request, bindHandler);
      }
      public void handleErrorResult(ErrorResultException error)
      {
        exception = error;
        latch.countDown();
      }
    }
    private final class BindRequestResultHandler implements
        ResultHandler<BindResult>
    {
      public void handleResult(BindResult result)
      {
        // FIXME: should make the result unmodifiable.
        authenticatedConnection = new AuthenticatedAsynchronousConnection(
            connection, request, result);
        latch.countDown();
        if (handler != null)
        {
          handler.handleResult(authenticatedConnection);
        }
      }
      public void handleErrorResult(ErrorResultException error)
      {
        // Ensure that the connection is closed.
        try
        {
          connection.close();
        }
        catch (Exception e)
        {
          // Ignore.
        }
        exception = error;
        latch.countDown();
        if (handler != null)
        {
          handler.handleErrorResult(exception);
        }
      }
    }
    private final ResultHandler<BindResult> bindHandler = new BindRequestResultHandler();
    private final ResultHandler<AsynchronousConnection> connectionHandler = new ConnectionResultHandler();
    private volatile AuthenticatedAsynchronousConnection authenticatedConnection;
    private volatile AsynchronousConnection connection;
    private volatile ErrorResultException exception;
    private volatile ConnectionFuture<?> connectFuture;
    private volatile FutureResult<?> connectFuture;
    private volatile ResultFuture<BindResult> bindFuture;
    private volatile FutureResult<BindResult> bindFuture;
    private final CountDownLatch latch = new CountDownLatch(1);
    private final ConnectionResultHandler<? super AuthenticatedAsynchronousConnection> handler;
    private final ResultHandler<? super AuthenticatedAsynchronousConnection> handler;
    private boolean cancelled;
@@ -585,9 +647,9 @@
    private ConnectionFutureImpl(
    private ResultFutureImpl(
        BindRequest request,
        ConnectionResultHandler<? super AuthenticatedAsynchronousConnection> handler)
        ResultHandler<? super AuthenticatedAsynchronousConnection> handler)
    {
      this.request = request;
      this.handler = handler;
@@ -658,55 +720,11 @@
    public void handleConnection(AsynchronousConnection connection)
    public int getRequestID()
    {
      this.connection = connection;
      this.bindFuture = this.connection.bind(request, this);
      return -1;
    }
    public void handleConnectionError(ErrorResultException error)
    {
      exception = error;
      latch.countDown();
    }
    public void handleResult(BindResult result)
    {
      // FIXME: should make the result unmodifiable.
      authenticatedConnection = new AuthenticatedAsynchronousConnection(
          connection, request, result);
      latch.countDown();
      if (handler != null)
      {
        handler.handleConnection(authenticatedConnection);
      }
    }
    public void handleErrorResult(ErrorResultException error)
    {
      // Ensure that the connection is closed.
      try
      {
        connection.close();
      }
      catch (Exception e)
      {
        // Ignore.
      }
      exception = error;
      latch.countDown();
      if (handler != null)
      {
        handler.handleConnectionError(exception);
      }
    }
  }
@@ -751,8 +769,8 @@
  public ConnectionFuture<AuthenticatedAsynchronousConnection> getAsynchronousConnection(
      ConnectionResultHandler<? super AuthenticatedAsynchronousConnection> handler)
  public FutureResult<AuthenticatedAsynchronousConnection> getAsynchronousConnection(
      ResultHandler<? super AuthenticatedAsynchronousConnection> handler)
  {
    return impl.getAsynchronousConnection(handler);
  }
sdk/src/org/opends/sdk/ConnectionFactory.java
@@ -72,9 +72,9 @@
  /**
   * Initiates an asynchronous connection request to the Directory
   * Server associated with this connection factory. The returned
   * {@code ConnectionFuture} can be used to retrieve the completed
   * {@code FutureResult} can be used to retrieve the completed
   * asynchronous connection. Alternatively, if a {@code
   * ConnectionResultHandler} is provided, the handler will be notified
   * ResultHandler} is provided, the handler will be notified
   * when the connection is available and ready for use.
   *
   * @param handler
@@ -83,6 +83,6 @@
   * @return A future which can be used to retrieve the asynchronous
   *         connection.
   */
  ConnectionFuture<? extends C> getAsynchronousConnection(
      ConnectionResultHandler<? super C> handler);
  FutureResult<? extends C> getAsynchronousConnection(
      ResultHandler<? super C> handler);
}
sdk/src/org/opends/sdk/ConnectionFuture.java
File was deleted
sdk/src/org/opends/sdk/ConnectionPool.java
@@ -60,7 +60,7 @@
  // FIXME: should use a better collection than this - CLQ?
  private final Stack<AsynchronousConnection> pool;
  private final ConcurrentLinkedQueue<PendingConnectionFuture> pendingFutures;
  private final ConcurrentLinkedQueue<PendingResultFuture> pendingFutures;
  private final Object lock = new Object();
@@ -94,7 +94,7 @@
    public ResultFuture<Result> add(AddRequest request,
    public FutureResult<Result> add(AddRequest request,
        ResultHandler<Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -108,7 +108,7 @@
    public ResultFuture<BindResult> bind(BindRequest request,
    public FutureResult<BindResult> bind(BindRequest request,
        ResultHandler<? super BindResult> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -145,7 +145,7 @@
          }
          // See if there waiters pending
          PendingConnectionFuture future = pendingFutures.poll();
          PendingResultFuture future = pendingFutures.poll();
          if (future != null)
          {
            PooledConnectionWapper pooledConnection = new PooledConnectionWapper(
@@ -195,7 +195,7 @@
    public ResultFuture<CompareResult> compare(CompareRequest request,
    public FutureResult<CompareResult> compare(CompareRequest request,
        ResultHandler<? super CompareResult> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -209,7 +209,7 @@
    public ResultFuture<Result> delete(DeleteRequest request,
    public FutureResult<Result> delete(DeleteRequest request,
        ResultHandler<Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -223,7 +223,7 @@
    public <R extends Result> ResultFuture<R> extendedRequest(
    public <R extends Result> FutureResult<R> extendedRequest(
        ExtendedRequest<R> request, ResultHandler<? super R> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -237,7 +237,7 @@
    public ResultFuture<Result> modify(ModifyRequest request,
    public FutureResult<Result> modify(ModifyRequest request,
        ResultHandler<Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -251,7 +251,7 @@
    public ResultFuture<Result> modifyDN(ModifyDNRequest request,
    public FutureResult<Result> modifyDN(ModifyDNRequest request,
        ResultHandler<Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -265,7 +265,7 @@
    public ResultFuture<Result> search(SearchRequest request,
    public FutureResult<Result> search(SearchRequest request,
        ResultHandler<Result> resultHandler,
        SearchResultHandler searchResulthandler)
        throws UnsupportedOperationException, IllegalStateException,
@@ -284,7 +284,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<SearchResultEntry> readEntry(DN name,
    public FutureResult<SearchResultEntry> readEntry(DN name,
        Collection<String> attributeDescriptions,
        ResultHandler<? super SearchResultEntry> resultHandler)
        throws UnsupportedOperationException, IllegalStateException,
@@ -303,7 +303,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<SearchResultEntry> searchSingleEntry(
    public FutureResult<SearchResultEntry> searchSingleEntry(
        SearchRequest request,
        ResultHandler<? super SearchResultEntry> resultHandler)
        throws UnsupportedOperationException, IllegalStateException,
@@ -321,7 +321,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<RootDSE> readRootDSE(
    public FutureResult<RootDSE> readRootDSE(
        ResultHandler<RootDSE> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
@@ -337,7 +337,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<Schema> readSchemaForEntry(DN name,
    public FutureResult<Schema> readSchemaForEntry(DN name,
        ResultHandler<Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
@@ -353,7 +353,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<Schema> readSchema(DN name,
    public FutureResult<Schema> readSchema(DN name,
        ResultHandler<Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
@@ -438,14 +438,14 @@
  private static final class CompletedConnectionFuture implements
      ConnectionFuture<AsynchronousConnection>
  private static final class CompletedResultFuture implements
      FutureResult<AsynchronousConnection>
  {
    private final PooledConnectionWapper connection;
    private CompletedConnectionFuture(PooledConnectionWapper connection)
    private CompletedResultFuture(PooledConnectionWapper connection)
    {
      this.connection = connection;
    }
@@ -487,12 +487,19 @@
    {
      return true;
    }
    public int getRequestID()
    {
      return -1;
    }
  }
  private final class PendingConnectionFuture implements
      ConnectionFuture<AsynchronousConnection>
  private final class PendingResultFuture implements
      FutureResult<AsynchronousConnection>
  {
    private volatile boolean isCancelled;
@@ -500,14 +507,14 @@
    private volatile ErrorResultException err;
    private final ConnectionResultHandler<? super AsynchronousConnection> handler;
    private final ResultHandler<? super AsynchronousConnection> handler;
    private final CountDownLatch latch = new CountDownLatch(1);
    private PendingConnectionFuture(
        ConnectionResultHandler<? super AsynchronousConnection> handler)
    private PendingResultFuture(
        ResultHandler<? super AsynchronousConnection> handler)
    {
      this.handler = handler;
    }
@@ -562,12 +569,19 @@
    public int getRequestID()
    {
      return -1;
    }
    private void connection(PooledConnectionWapper connection)
    {
      this.connection = connection;
      if (handler != null)
      {
        handler.handleConnection(connection);
        handler.handleResult(connection);
      }
      latch.countDown();
    }
@@ -579,7 +593,7 @@
      this.err = e;
      if (handler != null)
      {
        handler.handleConnectionError(e);
        handler.handleErrorResult(e);
      }
      latch.countDown();
    }
@@ -603,26 +617,26 @@
    this.connectionFactory = connectionFactory;
    this.poolSize = poolSize;
    this.pool = new Stack<AsynchronousConnection>();
    this.pendingFutures = new ConcurrentLinkedQueue<PendingConnectionFuture>();
    this.pendingFutures = new ConcurrentLinkedQueue<PendingResultFuture>();
  }
  private final class WrapConnectionResultHandler implements
      ConnectionResultHandler<AsynchronousConnection>
  private final class WrapResultHandler implements
      ResultHandler<AsynchronousConnection>
  {
    private final PendingConnectionFuture future;
    private final PendingResultFuture future;
    private WrapConnectionResultHandler(PendingConnectionFuture future)
    private WrapResultHandler(PendingResultFuture future)
    {
      this.future = future;
    }
    public void handleConnection(AsynchronousConnection connection)
    public void handleResult(AsynchronousConnection connection)
    {
      PooledConnectionWapper pooledConnection = new PooledConnectionWapper(
          connection);
@@ -631,7 +645,7 @@
    public void handleConnectionError(ErrorResultException error)
    public void handleErrorResult(ErrorResultException error)
    {
      future.error(error);
    }
@@ -639,8 +653,8 @@
  public ConnectionFuture<AsynchronousConnection> getAsynchronousConnection(
      ConnectionResultHandler<? super AsynchronousConnection> handler)
  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
      ResultHandler<? super AsynchronousConnection> handler)
  {
    synchronized (lock)
    {
@@ -663,19 +677,19 @@
            conn);
        if (handler != null)
        {
          handler.handleConnection(pooledConnection);
          handler.handleResult(pooledConnection);
        }
        return new CompletedConnectionFuture(pooledConnection);
        return new CompletedResultFuture(pooledConnection);
      }
      PendingConnectionFuture pendingFuture = new PendingConnectionFuture(
      PendingResultFuture pendingFuture = new PendingResultFuture(
          handler);
      // Pool was empty. Maybe a new connection if pool size is not
      // reached
      if (numConnections < poolSize)
      {
        numConnections++;
        WrapConnectionResultHandler wrapHandler = new WrapConnectionResultHandler(
        WrapResultHandler wrapHandler = new WrapResultHandler(
            pendingFuture);
        connectionFactory.getAsynchronousConnection(wrapHandler);
        if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
sdk/src/org/opends/sdk/ConnectionResultHandler.java
File was deleted
sdk/src/org/opends/sdk/FutureResult.java
File was renamed from sdk/src/org/opends/sdk/ResultFuture.java
@@ -29,7 +29,6 @@
import java.util.concurrent.CancellationException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -43,7 +42,7 @@
 * @param <S>
 *          The type of result returned by this future.
 */
public interface ResultFuture<S> extends Future<S>
public interface FutureResult<S> extends Future<S>
{
  /**
   * Attempts to cancel the request. This attempt will fail if the
@@ -79,14 +78,10 @@
   * @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 ErrorResultException, CancellationException,
      InterruptedException;
  S get() throws ErrorResultException, InterruptedException;
@@ -107,23 +102,20 @@
   *           some reason.
   * @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 ErrorResultException,
      TimeoutException, CancellationException, InterruptedException;
      TimeoutException, InterruptedException;
  /**
   * Returns the message ID of the request.
   * Returns the request ID of the request if appropriate.
   *
   * @return The message ID.
   * @return The request ID, or {@code -1} if there is no request ID.
   */
  int getMessageID();
  int getRequestID();
sdk/src/org/opends/sdk/HeartBeatConnectionFactory.java
@@ -158,7 +158,7 @@
    public ResultFuture<Result> add(AddRequest request,
    public FutureResult<Result> add(AddRequest request,
        ResultHandler<Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -168,7 +168,7 @@
    public ResultFuture<BindResult> bind(BindRequest request,
    public FutureResult<BindResult> bind(BindRequest request,
        ResultHandler<? super BindResult> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -203,7 +203,7 @@
    public ResultFuture<CompareResult> compare(CompareRequest request,
    public FutureResult<CompareResult> compare(CompareRequest request,
        ResultHandler<? super CompareResult> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -213,7 +213,7 @@
    public ResultFuture<Result> delete(DeleteRequest request,
    public FutureResult<Result> delete(DeleteRequest request,
        ResultHandler<Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -223,7 +223,7 @@
    public <R extends Result> ResultFuture<R> extendedRequest(
    public <R extends Result> FutureResult<R> extendedRequest(
        ExtendedRequest<R> request, ResultHandler<? super R> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -233,7 +233,7 @@
    public ResultFuture<Result> modify(ModifyRequest request,
    public FutureResult<Result> modify(ModifyRequest request,
        ResultHandler<Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -243,7 +243,7 @@
    public ResultFuture<Result> modifyDN(ModifyDNRequest request,
    public FutureResult<Result> modifyDN(ModifyDNRequest request,
        ResultHandler<Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -253,7 +253,7 @@
    public ResultFuture<Result> search(SearchRequest request,
    public FutureResult<Result> search(SearchRequest request,
        ResultHandler<Result> resultHandler,
        SearchResultHandler searchResultHandler)
        throws UnsupportedOperationException, IllegalStateException,
@@ -268,7 +268,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<SearchResultEntry> readEntry(DN name,
    public FutureResult<SearchResultEntry> readEntry(DN name,
        Collection<String> attributeDescriptions,
        ResultHandler<? super SearchResultEntry> resultHandler)
        throws UnsupportedOperationException, IllegalStateException,
@@ -283,7 +283,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<SearchResultEntry> searchSingleEntry(
    public FutureResult<SearchResultEntry> searchSingleEntry(
        SearchRequest request,
        ResultHandler<? super SearchResultEntry> resultHandler)
        throws UnsupportedOperationException, IllegalStateException,
@@ -297,7 +297,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<RootDSE> readRootDSE(
    public FutureResult<RootDSE> readRootDSE(
        ResultHandler<RootDSE> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
@@ -309,7 +309,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<Schema> readSchemaForEntry(DN name,
    public FutureResult<Schema> readSchemaForEntry(DN name,
        ResultHandler<Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
@@ -321,7 +321,7 @@
    /**
     * {@inheritDoc}
     */
    public ResultFuture<Schema> readSchema(DN name,
    public FutureResult<Schema> readSchema(DN name,
        ResultHandler<Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
@@ -437,26 +437,26 @@
  private final class ConnectionFutureImpl implements
      ConnectionFuture<AsynchronousConnection>,
      ConnectionResultHandler<AsynchronousConnection>
  private final class ResultFutureImpl implements
      FutureResult<AsynchronousConnection>,
      ResultHandler<AsynchronousConnection>
  {
    private volatile AsynchronousConnectionImpl heartBeatConnection;
    private volatile ErrorResultException exception;
    private volatile ConnectionFuture<?> connectFuture;
    private volatile FutureResult<?> connectFuture;
    private final CountDownLatch latch = new CountDownLatch(1);
    private final ConnectionResultHandler<? super AsynchronousConnectionImpl> handler;
    private final ResultHandler<? super AsynchronousConnectionImpl> handler;
    private boolean cancelled;
    private ConnectionFutureImpl(
        ConnectionResultHandler<? super AsynchronousConnectionImpl> handler)
    private ResultFutureImpl(
        ResultHandler<? super AsynchronousConnectionImpl> handler)
    {
      this.handler = handler;
    }
@@ -524,7 +524,14 @@
    public void handleConnection(AsynchronousConnection connection)
    public int getRequestID()
    {
      return -1;
    }
    public void handleResult(AsynchronousConnection connection)
    {
      heartBeatConnection = new AsynchronousConnectionImpl(connection);
      synchronized (activeConnections)
@@ -534,19 +541,19 @@
      }
      if (handler != null)
      {
        handler.handleConnection(heartBeatConnection);
        handler.handleResult(heartBeatConnection);
      }
      latch.countDown();
    }
    public void handleConnectionError(ErrorResultException error)
    public void handleErrorResult(ErrorResultException error)
    {
      exception = error;
      if (handler != null)
      {
        handler.handleConnectionError(error);
        handler.handleErrorResult(error);
      }
      latch.countDown();
    }
@@ -554,10 +561,10 @@
  public ConnectionFuture<AsynchronousConnection> getAsynchronousConnection(
      ConnectionResultHandler<? super AsynchronousConnection> handler)
  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
      ResultHandler<? super AsynchronousConnection> handler)
  {
    ConnectionFutureImpl future = new ConnectionFutureImpl(handler);
    ResultFutureImpl future = new ResultFutureImpl(handler);
    future.connectFuture = parentFactory
        .getAsynchronousConnection(future);
    return future;
sdk/src/org/opends/sdk/RootDSE.java
@@ -156,14 +156,14 @@
   * @throws NullPointerException
   *           If the {@code connection} was {@code null}.
   */
  public static ResultFuture<RootDSE> readRootDSE(
  public static FutureResult<RootDSE> readRootDSE(
      AsynchronousConnection connection,
      ResultHandler<RootDSE> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    final ResultTransformer<SearchResultEntry, RootDSE> future =
      new ResultTransformer<SearchResultEntry, RootDSE>(handler)
    final FutureResultTransformer<SearchResultEntry, RootDSE> future =
      new FutureResultTransformer<SearchResultEntry, RootDSE>(handler)
    {
      protected RootDSE transformResult(SearchResultEntry result)
@@ -174,9 +174,9 @@
    };
    ResultFuture<SearchResultEntry> innerFuture = connection
    FutureResult<SearchResultEntry> innerFuture = connection
        .searchSingleEntry(SEARCH_REQUEST, future);
    future.setResultFuture(innerFuture);
    future.setFutureResult(innerFuture);
    return future;
  }
sdk/src/org/opends/sdk/SynchronousConnection.java
@@ -74,7 +74,7 @@
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException
  {
    ResultFuture<Result> future = connection.add(request, null);
    FutureResult<Result> future = connection.add(request, null);
    try
    {
      return future.get();
@@ -102,7 +102,7 @@
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    ResultFuture<BindResult> future = connection.bind(request, null);
    FutureResult<BindResult> future = connection.bind(request, null);
    try
    {
      return future.get();
@@ -136,7 +136,7 @@
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    ResultFuture<CompareResult> future = connection.compare(request,
    FutureResult<CompareResult> future = connection.compare(request,
        null);
    try
    {
@@ -156,7 +156,7 @@
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    ResultFuture<Result> future = connection.delete(request, null);
    FutureResult<Result> future = connection.delete(request, null);
    try
    {
      return future.get();
@@ -175,7 +175,7 @@
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    ResultFuture<R> future = connection.extendedRequest(request, null);
    FutureResult<R> future = connection.extendedRequest(request, null);
    try
    {
      return future.get();
@@ -194,7 +194,7 @@
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    ResultFuture<Result> future = connection.modify(request, null);
    FutureResult<Result> future = connection.modify(request, null);
    try
    {
      return future.get();
@@ -213,7 +213,7 @@
      UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    ResultFuture<Result> future = connection.modifyDN(request, null);
    FutureResult<Result> future = connection.modifyDN(request, null);
    try
    {
      return future.get();
@@ -243,7 +243,7 @@
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException
  {
    ResultFuture<Result> future = connection.search(request, null,
    FutureResult<Result> future = connection.search(request, null,
        handler);
    try
    {
@@ -275,7 +275,7 @@
      throws ErrorResultException, InterruptedException,
      UnsupportedOperationException, IllegalStateException
  {
    ResultFuture<Schema> future = connection.readSchemaForEntry(name,
    FutureResult<Schema> future = connection.readSchemaForEntry(name,
        null);
    try
    {
sdk/src/org/opends/sdk/ldap/LDAPConnectionFactory.java
@@ -114,8 +114,8 @@
  public ConnectionFuture<AsynchronousConnection> getAsynchronousConnection(
      ConnectionResultHandler<? super AsynchronousConnection> handler)
  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
      ResultHandler<? super AsynchronousConnection> handler)
  {
    return impl.getAsynchronousConnection(handler);
  }
sdk/src/org/opends/sdk/schema/CoreSchemaImpl.java
@@ -81,7 +81,7 @@
  static
  {
    final SchemaBuilder builder = new SchemaBuilder();
    final SchemaBuilder builder = new SchemaBuilder("Core Schema");
    defaultSyntaxes(builder);
    defaultMatchingRules(builder);
    defaultAttributeTypes(builder);
sdk/src/org/opends/sdk/schema/Schema.java
@@ -42,8 +42,8 @@
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.FutureResultTransformer;
import com.sun.opends.sdk.util.RecursiveFutureResult;
import com.sun.opends.sdk.util.StaticUtils;
@@ -281,6 +281,16 @@
    /**
     * {@inheritDoc}
     */
    public String getSchemaName()
    {
      return "Empty Schema";
    }
    public Syntax getSyntax(String numericOID)
    {
      // Fake up a syntax substituted by the default syntax.
@@ -483,6 +493,10 @@
    String getSchemaName();
    Syntax getSyntax(String numericOID)
        throws UnknownSchemaElementException;
@@ -750,6 +764,13 @@
    public String getSchemaName()
    {
      return strictImpl.getSchemaName();
    }
    public Syntax getSyntax(String numericOID)
    {
      if (!strictImpl.hasSyntax(numericOID))
@@ -883,9 +904,12 @@
    private final List<LocalizableMessage> warnings;
    private final String schemaName;
    private StrictImpl(Map<String, Syntax> numericOID2Syntaxes,
    private StrictImpl(String schemaName,
        Map<String, Syntax> numericOID2Syntaxes,
        Map<String, MatchingRule> numericOID2MatchingRules,
        Map<String, MatchingRuleUse> numericOID2MatchingRuleUses,
        Map<String, AttributeType> numericOID2AttributeTypes,
@@ -904,6 +928,7 @@
        Map<String, List<DITStructureRule>> nameForm2StructureRules,
        SchemaCompatOptions options, List<LocalizableMessage> warnings)
    {
      this.schemaName = schemaName;
      this.numericOID2Syntaxes = Collections
          .unmodifiableMap(numericOID2Syntaxes);
      this.numericOID2MatchingRules = Collections
@@ -1320,6 +1345,13 @@
    public String getSchemaName()
    {
      return schemaName;
    }
    public Syntax getSyntax(String numericOID)
        throws UnknownSchemaElementException
    {
@@ -1502,276 +1534,6 @@
  /**
   * 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 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}.
   * @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 ResultFuture<Schema> readSchema(
      AsynchronousConnection connection, DN name,
      ResultHandler<? super Schema> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    final SearchRequest request = getReadSchemaSearchRequest(name);
    final ResultTransformer<SearchResultEntry, Schema> future = new ResultTransformer<SearchResultEntry, Schema>(
        handler)
    {
      protected Schema transformResult(SearchResultEntry result)
          throws ErrorResultException
      {
        return valueOf(result);
      }
    };
    ResultFuture<SearchResultEntry> innerFuture = connection
        .searchSingleEntry(request, future);
    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 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}.
   * @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 ResultFuture<Schema> readSchemaForEntry(
      final AsynchronousConnection connection, final DN name,
      ResultHandler<Schema> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    final ResultChain<SearchResultEntry, Schema> future = new ResultChain<SearchResultEntry, Schema>(
        handler)
    {
      protected ResultFuture<Schema> chainResult(
          SearchResultEntry innerResult,
          ResultHandler<? super Schema> handler)
          throws ErrorResultException
      {
        final DN subschemaDN = getSubschemaSubentryDN(name, innerResult);
        return readSchema(connection, subschemaDN, handler);
      }
    };
    final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
    ResultFuture<SearchResultEntry> innerFuture = connection
        .searchSingleEntry(request, future);
    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);
  }
  /**
   * Returns the core schema. The core schema is non-strict and contains
   * the following standard LDAP schema elements:
   * <ul>
@@ -1831,6 +1593,234 @@
  /**
   * 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 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}.
   * @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 FutureResult<Schema> readSchema(
      AsynchronousConnection connection, DN name,
      ResultHandler<? super Schema> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    final SearchRequest request = getReadSchemaSearchRequest(name);
    final FutureResultTransformer<SearchResultEntry, Schema> future = new FutureResultTransformer<SearchResultEntry, Schema>(
        handler)
    {
      protected Schema transformResult(SearchResultEntry result)
          throws ErrorResultException
      {
        return valueOf(result);
      }
    };
    final FutureResult<SearchResultEntry> innerFuture = connection
        .searchSingleEntry(request, future);
    future.setFutureResult(innerFuture);
    return future;
  }
  /**
   * 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.
   * <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 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}.
   * @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 FutureResult<Schema> readSchemaForEntry(
      final AsynchronousConnection connection, final DN name,
      ResultHandler<Schema> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    final RecursiveFutureResult<SearchResultEntry, Schema> future = new RecursiveFutureResult<SearchResultEntry, Schema>(
        handler)
    {
      protected FutureResult<Schema> chainResult(
          SearchResultEntry innerResult,
          ResultHandler<? super Schema> handler)
          throws ErrorResultException
      {
        final DN subschemaDN = getSubschemaSubentryDN(name, innerResult);
        return readSchema(connection, subschemaDN, handler);
      }
    };
    final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
    final FutureResult<SearchResultEntry> innerFuture = connection
        .searchSingleEntry(request, future);
    future.setFutureResult(innerFuture);
    return future;
  }
  /**
   * 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);
  }
  /**
   * Sets the default schema which should be used by this application.
   * The default schema is initially set to the core schema.
   *
   * @param schema
   *          The default schema which should be used by this
   *          application.
   */
  public static void setDefaultSchema(Schema schema)
  {
    DEFAULT_SCHEMA = schema;
  }
  /**
   * 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.
@@ -1841,7 +1831,8 @@
   */
  public static Schema valueOf(Entry entry)
  {
    final SchemaBuilder builder = new SchemaBuilder();
    final SchemaBuilder builder = new SchemaBuilder(entry.getName()
        .toString());
    Attribute attr = entry.getAttribute(ATTR_LDAP_SYNTAXES);
    if (attr != null)
@@ -1976,17 +1967,59 @@
  /**
   * Sets the default schema which should be used by this application.
   * The default schema is initially set to the core schema.
   *
   * @param schema
   *          The default schema which should be used by this
   *          application.
   */
  public static void setDefaultSchema(Schema schema)
  // Constructs a search request for retrieving the subschemaSubentry
  // attribute from the named entry.
  private static SearchRequest getReadSchemaForEntrySearchRequest(DN dn)
  {
    DEFAULT_SCHEMA = schema;
    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(DN dn)
  {
    return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT,
        SUBSCHEMA_FILTER, SUBSCHEMA_ATTRS);
  }
  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.
      final Result result = Responses.newResult(
          ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED)
          .setDiagnosticMessage(
              ERR_NO_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString())
                  .toString());
      throw ErrorResultException.wrap(result);
    }
    final String dnString = subentryAttr.iterator().next().toString();
    DN subschemaDN;
    try
    {
      subschemaDN = DN.valueOf(dnString);
    }
    catch (final LocalizedIllegalArgumentException e)
    {
      final 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;
  }
@@ -2009,7 +2042,14 @@
  Schema(Map<String, Syntax> numericOID2Syntaxes,
  private Schema(Impl impl)
  {
    this.impl = impl;
  }
  Schema(String schemaName, Map<String, Syntax> numericOID2Syntaxes,
      Map<String, MatchingRule> numericOID2MatchingRules,
      Map<String, MatchingRuleUse> numericOID2MatchingRuleUses,
      Map<String, AttributeType> numericOID2AttributeTypes,
@@ -2028,7 +2068,7 @@
      Map<String, List<DITStructureRule>> nameForm2StructureRules,
      SchemaCompatOptions options, List<LocalizableMessage> warnings)
  {
    impl = new StrictImpl(numericOID2Syntaxes,
    impl = new StrictImpl(schemaName, numericOID2Syntaxes,
        numericOID2MatchingRules, numericOID2MatchingRuleUses,
        numericOID2AttributeTypes, numericOID2ObjectClasses,
        numericOID2NameForms, numericOID2ContentRules,
@@ -2040,13 +2080,6 @@
  private Schema(Impl impl)
  {
    this.impl = impl;
  }
  /**
   * Returns the attribute type with the specified name or numeric OID.
   *
@@ -2441,6 +2474,22 @@
  /**
   * Returns the user-friendly name of this schema which may be used for
   * debugging purposes. The format of the schema name is not defined
   * but should contain the distinguished name of the subschema
   * sub-entry for those schemas retrieved from a Directory Server.
   *
   * @return The user-friendly name of this schema which may be used for
   *         debugging purposes.
   */
  public String getSchemaName()
  {
    return impl.getSchemaName();
  }
  /**
   * Returns the syntax with the specified numeric OID.
   *
   * @param numericOID
sdk/src/org/opends/sdk/schema/SchemaBuilder.java
@@ -33,13 +33,16 @@
import static org.opends.sdk.schema.SchemaConstants.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import org.opends.sdk.DecodeException;
import org.opends.sdk.LocalizedIllegalArgumentException;
import org.opends.sdk.LocalizableMessage;
import org.opends.sdk.LocalizedIllegalArgumentException;
import com.sun.opends.sdk.util.*;
import com.sun.opends.sdk.util.StaticUtils;
import com.sun.opends.sdk.util.SubstringReader;
import com.sun.opends.sdk.util.Validator;
@@ -90,6 +93,10 @@
  private Schema schema;
  // A unique ID which can be used to uniquely identify schemas
  // constructed without a name.
  private final AtomicInteger nextSchemaID = new AtomicInteger();
  /**
@@ -98,7 +105,7 @@
   */
  public SchemaBuilder()
  {
    initBuilder();
    initBuilder(null);
  }
@@ -106,7 +113,7 @@
  /**
   * Creates a new schema builder containing all of the schema elements
   * from the provided schema and its compatibility options.
   *
   *
   * @param schema
   *          The initial contents of the schema builder.
   * @throws NullPointerException
@@ -114,8 +121,7 @@
   */
  public SchemaBuilder(Schema schema) throws NullPointerException
  {
    Validator.ensureNotNull(schema);
    initBuilder();
    initBuilder(schema.getSchemaName());
    setSchemaCompatOptions(schema.getSchemaCompatOptions());
    addSchema(schema, true);
  }
@@ -123,8 +129,23 @@
  /**
   * Creates a new schema builder with no schema elements and default
   * compatibility options.
   *
   * @param schemaName
   *          The user-friendly name of this schema which may be used
   *          for debugging purposes.
   */
  public SchemaBuilder(String schemaName)
  {
    initBuilder(schemaName);
  }
  /**
   * Adds the provided attribute type definition to this schema builder.
   *
   *
   * @param definition
   *          The attribute type definition.
   * @param overwrite
@@ -386,7 +407,7 @@
  /**
   * Adds the provided attribute type definition to this schema builder.
   *
   *
   * @param oid
   *          The OID of the attribute type definition.
   * @param names
@@ -465,7 +486,7 @@
  /**
   * Adds the provided DIT content rule definition to this schema
   * builder.
   *
   *
   * @param definition
   *          The DIT content rule definition.
   * @param overwrite
@@ -622,7 +643,7 @@
  /**
   * Adds the provided DIT content rule definition to this schema
   * builder.
   *
   *
   * @param structuralClass
   *          The name of the structural object class to which the DIT
   *          content rule applies.
@@ -677,7 +698,7 @@
  /**
   * Adds the provided DIT structure rule definition to this schema
   * builder.
   *
   *
   * @param ruleID
   *          The rule identifier of the DIT structure rule.
   * @param names
@@ -721,7 +742,7 @@
  /**
   * Adds the provided DIT structure rule definition to this schema
   * builder.
   *
   *
   * @param definition
   *          The DIT structure rule definition.
   * @param overwrite
@@ -874,7 +895,7 @@
  /**
   * Adds the provided enumeration syntax definition to this schema
   * builder.
   *
   *
   * @param oid
   *          The OID of the enumeration syntax definition.
   * @param description
@@ -923,7 +944,7 @@
  /**
   * Adds the provided matching rule definition to this schema builder.
   *
   *
   * @param definition
   *          The matching rule definition.
   * @param overwrite
@@ -1070,7 +1091,7 @@
  /**
   * Adds the provided matching rule definition to this schema builder.
   *
   *
   * @param oid
   *          The OID of the matching rule definition.
   * @param names
@@ -1114,7 +1135,7 @@
  /**
   * Adds the provided matching rule use definition to this schema
   * builder.
   *
   *
   * @param definition
   *          The matching rule use definition.
   * @param overwrite
@@ -1263,7 +1284,7 @@
  /**
   * Adds the provided matching rule use definition to this schema
   * builder.
   *
   *
   * @param oid
   *          The OID of the matching rule use definition.
   * @param names
@@ -1303,7 +1324,7 @@
  /**
   * Adds the provided name form definition to this schema builder.
   *
   *
   * @param definition
   *          The name form definition.
   * @param overwrite
@@ -1468,7 +1489,7 @@
  /**
   * Adds the provided name form definition to this schema builder.
   *
   *
   * @param oid
   *          The OID of the name form definition.
   * @param names
@@ -1514,7 +1535,7 @@
  /**
   * Adds the provided object class definition to this schema builder.
   *
   *
   * @param definition
   *          The object class definition.
   * @param overwrite
@@ -1699,7 +1720,7 @@
  /**
   * Adds the provided object class definition to this schema builder.
   *
   *
   * @param oid
   *          The OID of the object class definition.
   * @param names
@@ -1762,7 +1783,7 @@
  /**
   * Adds the provided pattern syntax definition to this schema builder.
   *
   *
   * @param oid
   *          The OID of the pattern syntax definition.
   * @param description
@@ -1795,7 +1816,7 @@
  /**
   * Adds all of the schema elements in the provided schema to this
   * schema builder.
   *
   *
   * @param schema
   *          The schema to be copied into this schema builder.
   * @param overwrite
@@ -1862,7 +1883,7 @@
  /**
   * Adds the provided substitution syntax definition to this schema
   * builder.
   *
   *
   * @param oid
   *          The OID of the substitution syntax definition.
   * @param description
@@ -1894,7 +1915,7 @@
  /**
   * Adds the provided syntax definition to this schema builder.
   *
   *
   * @param definition
   *          The syntax definition.
   * @param overwrite
@@ -2034,7 +2055,7 @@
  /**
   * Adds the provided syntax definition to this schema builder.
   *
   *
   * @param oid
   *          The OID of the syntax definition.
   * @param description
@@ -2068,7 +2089,7 @@
  /**
   * Removes the named attribute type from this schema builder.
   *
   *
   * @param name
   *          The name or OID of the attribute type to be removed.
   * @return {@code true} if the attribute type was found.
@@ -2087,7 +2108,7 @@
  /**
   * Removes the named DIT content rule from this schema builder.
   *
   *
   * @param name
   *          The name or OID of the DIT content rule to be removed.
   * @return {@code true} if the DIT content rule was found.
@@ -2106,7 +2127,7 @@
  /**
   * Removes the specified DIT structure rule from this schema builder.
   *
   *
   * @param ruleID
   *          The ID of the DIT structure rule to be removed.
   * @return {@code true} if the DIT structure rule was found.
@@ -2125,7 +2146,7 @@
  /**
   * Removes the named matching rule from this schema builder.
   *
   *
   * @param name
   *          The name or OID of the matching rule to be removed.
   * @return {@code true} if the matching rule was found.
@@ -2144,7 +2165,7 @@
  /**
   * Removes the named matching rule use from this schema builder.
   *
   *
   * @param name
   *          The name or OID of the matching rule use to be removed.
   * @return {@code true} if the matching rule use was found.
@@ -2163,7 +2184,7 @@
  /**
   * Removes the named name form from this schema builder.
   *
   *
   * @param name
   *          The name or OID of the name form to be removed.
   * @return {@code true} if the name form was found.
@@ -2182,7 +2203,7 @@
  /**
   * Removes the named object class from this schema builder.
   *
   *
   * @param name
   *          The name or OID of the object class to be removed.
   * @return {@code true} if the object class was found.
@@ -2201,7 +2222,7 @@
  /**
   * Removes the named syntax from this schema builder.
   *
   *
   * @param numericOID
   *          The name of the syntax to be removed.
   * @return {@code true} if the syntax was found.
@@ -2223,7 +2244,7 @@
   * schema builder maintains its own set of compatibility options, so
   * subsequent changes to the provided set of options will not impact
   * this schema builder.
   *
   *
   * @param options
   *          The set of schema compatibility options that this schema
   *          builder should use.
@@ -2248,7 +2269,7 @@
   * <p>
   * When this method returns this schema builder is empty and contains
   * a default set of compatibility options.
   *
   *
   * @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
@@ -2257,19 +2278,12 @@
  {
    validate();
    final Schema builtSchema = schema;
    initBuilder();
    initBuilder(null);
    return builtSchema;
  }
  void addWarning(LocalizableMessage warning)
  {
    warnings.add(warning);
  }
  private synchronized void addAttributeType(AttributeType attribute,
      boolean overwrite) throws ConflictingSchemaElementException
  {
@@ -2589,7 +2603,7 @@
  private void initBuilder()
  private void initBuilder(String schemaName)
  {
    numericOID2Syntaxes = new HashMap<String, Syntax>();
    numericOID2MatchingRules = new HashMap<String, MatchingRule>();
@@ -2613,14 +2627,20 @@
    options = SchemaCompatOptions.defaultOptions();
    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);
    if (schemaName == null)
    {
      schemaName = String.format("Schema#%d", nextSchemaID
          .getAndIncrement());
    }
    schema = new Schema(schemaName, numericOID2Syntaxes,
        numericOID2MatchingRules, numericOID2MatchingRuleUses,
        numericOID2AttributeTypes, numericOID2ObjectClasses,
        numericOID2NameForms, numericOID2ContentRules,
        id2StructureRules, name2MatchingRules, name2MatchingRuleUses,
        name2AttributeTypes, name2ObjectClasses, name2NameForms,
        name2ContentRules, name2StructureRules, objectClass2NameForms,
        nameForm2StructureRules, options, warnings);
  }
@@ -2973,4 +2993,11 @@
    }
  }
  void addWarning(LocalizableMessage warning)
  {
    warnings.add(warning);
  }
}