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

matthew_swift
01.04.2010 8f4c882e39b040cca1210fcc169424f721be16c8
Various improvements:

* Fix for CR 6945479: Creating the Grizzly transport should be done synchronously to ensure only one instance is started.
* Fix for CR 6945473: checking for expired operation no longer causes race condition with other pendingRequest removals.
* Fix for CR 6979503: NullPointerException while running searchrate in asynchronous mode
* Fixed a bug where exceptions encountered when decoding a response might not be exposed.
* Fixed NPE when using performance tools.
* Added properties to configure socket options for the default transport. Set SO_LINGER to 0 for ModRate and SearchRate tools.
* Make SearchResultHandler extend ResultHandler<Result> in order to a) make async search APIs simpler, and b) allow event driven notification of search result/error for synchronous searches.
* improve generic type bounds for ResultHandlers from ResultHandler<X> to ResultHandler<? super X>
* add support for close notification to LDAPClientContext
* fix several FindBugs bugs
* rename ConnectionEventListener and ServerConnection methods to handleXXX to make the consistent with other handler interfaces.
* Added ConnectionEntryReader implementation.
* Add SchemaBuilder(Entry) constructor as an alternative to Schema.valueOf(Entry). Add Schema.toEntry(Entry) method as well for converting Schema objects to entries.
* Fixed bug in SASL BIND requests.
* Added SASL BIND test cases
* Exposed cipher and protocol configuration for establishing LDAPS connections.
* Added StartTLS test case
* Fixed a bug where bind and startTLS operation may be canceled.
* Updated to latest Grizzly
4 files deleted
2 files added
56 files modified
4489 ■■■■■ changed files
opendj-sdk/sdk/examples/org/opends/sdk/examples/DummyServer.java 80 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/lib/grizzly.jar patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/GlobalTransportFactory.java 32 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/InternalConnection.java 36 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPBindFutureResultImpl.java 12 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPClientFilter.java 407 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java 140 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnectionFactoryImpl.java 10 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPExtendedFutureResultImpl.java 13 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPFutureResultImpl.java 4 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPSearchFutureResultImpl.java 7 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPServerFilter.java 532 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/messages/messages.properties 12 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ArgumentParser.java 5 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ArgumentParserConnectionFactory.java 4 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/AuthenticatedConnectionFactory.java 38 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/DataSource.java 28 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPSearch.java 22 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ModRate.java 6 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/PerformanceRunner.java 19 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/PromptingTrustManager.java 11 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/SearchRate.java 8 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/com/sun/opends/sdk/util/AbstractFutureResult.java 18 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AVA.java 2 ●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AbstractAsynchronousConnection.java 28 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AbstractConnection.java 59 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AbstractConnectionFactory.java 4 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AsynchronousConnection.java 155 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/AuthenticatedConnectionFactory.java 36 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/Connection.java 62 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ConnectionEventListener.java 30 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ConnectionFactory.java 4 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ConnectionPool.java 42 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/FailoverLoadBalancingAlgorithm.java 2 ●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/HeartBeatConnectionFactory.java 66 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/InternalConnectionFactory.java 2 ●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/LDAPClientContext.java 91 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/LDAPConnectionFactory.java 4 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/LDAPOptions.java 76 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/LDAPUrl.java 2 ●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/LoadBalancingConnectionFactory.java 2 ●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java 4 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/SearchResultHandler.java 5 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/SearchResultReferenceIOException.java 81 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ServerConnection.java 78 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/SynchronousConnection.java 23 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/controls/EntryChangeNotificationResponseControl.java 21 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/ldif/ConnectionEntryReader.java 311 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/CRAMMD5SASLBindRequestImpl.java 35 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/DigestMD5SASLBindRequestImpl.java 34 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/ExternalSASLBindRequestImpl.java 34 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequest.java 56 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequestImpl.java 52 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/Schema.java 251 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaBuilder.java 150 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/AuthenticatedConnectionFactoryTestCase.java 62 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/ConnectionFactoryTestCase.java 105 ●●●● patch | view | raw | blame | history
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/HeartBeatConnectionFactoryTestCase.java 71 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/InternalConnectionFactoryTestCase.java 57 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/LDAPConnectionFactoryTestCase.java 56 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/LDAPServer.java 883 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/SynchronousConnectionTestCase.java 9 ●●●●● patch | view | raw | blame | history
opendj-sdk/sdk/examples/org/opends/sdk/examples/DummyServer.java
@@ -63,15 +63,17 @@
    public void abandon(final Integer context, final AbandonRequest request)
        throws UnsupportedOperationException
    @Override
    public void handleAbandon(final Integer context,
        final AbandonRequest request) throws UnsupportedOperationException
    {
    }
    public void add(final Integer context, final AddRequest request,
        final ResultHandler<Result> handler,
    @Override
    public void handleAdd(final Integer context, final AddRequest request,
        final ResultHandler<? super Result> handler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
    {
@@ -79,7 +81,8 @@
    public void bind(final Integer context, final int version,
    @Override
    public void handleBind(final Integer context, final int version,
        final BindRequest request,
        final ResultHandler<? super BindResult> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
@@ -90,21 +93,9 @@
    public void closed(final Integer context, final UnbindRequest request)
    {
      System.out.println(request);
    }
    public void closed(final Throwable error)
    {
      System.out.println(error);
    }
    public void compare(final Integer context, final CompareRequest request,
    @Override
    public void handleCompare(final Integer context,
        final CompareRequest request,
        final ResultHandler<? super CompareResult> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
@@ -113,8 +104,27 @@
    public void delete(final Integer context, final DeleteRequest request,
        final ResultHandler<Result> handler,
    @Override
    public void handleConnectionClosed(final Integer context,
        final UnbindRequest request)
    {
      System.out.println(request);
    }
    @Override
    public void handleConnectionException(final Throwable error)
    {
      System.out.println(error);
    }
    @Override
    public void handleDelete(final Integer context,
        final DeleteRequest request,
        final ResultHandler<? super Result> handler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
    {
@@ -122,9 +132,10 @@
    public <R extends ExtendedResult> void extendedRequest(
    @Override
    public <R extends ExtendedResult> void handleExtendedRequest(
        final Integer context, final ExtendedRequest<R> request,
        final ResultHandler<R> resultHandler,
        final ResultHandler<? super R> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
    {
@@ -133,14 +144,16 @@
        final R result = request.getResultDecoder().adaptExtendedErrorResult(
            ResultCode.SUCCESS, "", "");
        resultHandler.handleResult(result);
        clientContext.startTLS(sslContext);
        clientContext.startTLS(sslContext, null, null, false, false);
      }
    }
    public void modify(final Integer context, final ModifyRequest request,
        final ResultHandler<Result> resultHandler,
    @Override
    public void handleModify(final Integer context,
        final ModifyRequest request,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
    {
@@ -148,8 +161,10 @@
    public void modifyDN(final Integer context, final ModifyDNRequest request,
        final ResultHandler<Result> resultHandler,
    @Override
    public void handleModifyDN(final Integer context,
        final ModifyDNRequest request,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
    {
@@ -157,8 +172,10 @@
    public void search(final Integer context, final SearchRequest request,
        final ResultHandler<Result> resultHandler,
    @Override
    public void handleSearch(final Integer context,
        final SearchRequest request,
        final ResultHandler<? super Result> resultHandler,
        final SearchResultHandler searchResulthandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
@@ -252,6 +269,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public ServerConnection<Integer> accept(final LDAPClientContext context)
  {
    System.out.println("Connection from: " + context.getPeerAddress());
opendj-sdk/sdk/lib/grizzly.jar
Binary files differ
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/GlobalTransportFactory.java
@@ -76,6 +76,12 @@
  private int selectors;
  private int linger = -1;
  private boolean tcpNoDelay = true;
  private boolean reuseAddress = true;
  private TCPNIOTransport globalTCPNIOTransport = null;
@@ -117,12 +123,15 @@
   * @return instance of TCP {@link com.sun.grizzly.Transport}.
   */
  @Override
  public TCPNIOTransport createTCPTransport()
  public synchronized TCPNIOTransport createTCPTransport()
  {
    if (globalTCPNIOTransport == null)
    {
      globalTCPNIOTransport = setupTransport(new TCPNIOTransport());
      globalTCPNIOTransport.setSelectorRunnersCount(selectors);
      globalTCPNIOTransport.setLinger(linger);
      globalTCPNIOTransport.setTcpNoDelay(tcpNoDelay);
      globalTCPNIOTransport.setReuseAddress(reuseAddress);
      try
      {
@@ -178,6 +187,27 @@
    ThreadPoolConfig.DEFAULT.setMaxPoolSize(threads);
    ThreadPoolConfig.DEFAULT.setPoolName("OpenDS SDK Worker(Grizzly)");
    final String lingerStr = System
        .getProperty("org.opends.sdk.ldap.transport.linger");
    if (lingerStr != null)
    {
      linger = Integer.parseInt(lingerStr);
    }
    final String tcpNoDelayStr = System
        .getProperty("org.opends.sdk.ldap.transport.tcpNoDelay");
    if (tcpNoDelayStr != null)
    {
      tcpNoDelay = Integer.parseInt(tcpNoDelayStr) != 0;
    }
    final String reuseAddressStr = System
        .getProperty("org.opends.sdk.ldap.transport.reuseAddress");
    if (reuseAddressStr != null)
    {
      reuseAddress = Integer.parseInt(reuseAddressStr) != 0;
    }
    super.initialize();
  }
}
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/InternalConnection.java
@@ -49,7 +49,7 @@
 */
public final class InternalConnection extends AbstractAsynchronousConnection
{
  private final class InternalBindFutureResultImpl extends
  private static final class InternalBindFutureResultImpl extends
      AbstractLDAPFutureResultImpl<BindResult> implements
      FutureResult<BindResult>
  {
@@ -125,7 +125,7 @@
      NullPointerException
  {
    final int i = messageID.getAndIncrement();
    serverConnection.abandon(i, request);
    serverConnection.handleAbandon(i, request);
    return new CompletedFutureResult<Void>((Void) null, i);
  }
@@ -135,7 +135,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> add(final AddRequest request,
      final ResultHandler<Result> resultHandler,
      final ResultHandler<? super Result> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
@@ -143,7 +143,7 @@
    final int i = messageID.getAndIncrement();
    final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request,
        resultHandler, intermediateResponseHandler, this);
    serverConnection.add(i, request, future, future);
    serverConnection.handleAdd(i, request, future, future);
    return future;
  }
@@ -173,7 +173,7 @@
    final int i = messageID.getAndIncrement();
    final InternalBindFutureResultImpl future = new InternalBindFutureResultImpl(
        i, request, resultHandler, intermediateResponseHandler, this);
    serverConnection.bind(i, 3, request, future, future);
    serverConnection.handleBind(i, 3, request, future, future);
    return future;
  }
@@ -185,7 +185,7 @@
  public void close(final UnbindRequest request, final String reason)
  {
    final int i = messageID.getAndIncrement();
    serverConnection.closed(i, request);
    serverConnection.handleConnectionClosed(i, request);
  }
@@ -202,7 +202,7 @@
    final int i = messageID.getAndIncrement();
    final LDAPCompareFutureResultImpl future = new LDAPCompareFutureResultImpl(
        i, request, resultHandler, intermediateResponseHandler, this);
    serverConnection.compare(i, request, future, future);
    serverConnection.handleCompare(i, request, future, future);
    return future;
  }
@@ -212,7 +212,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> delete(final DeleteRequest request,
      final ResultHandler<Result> resultHandler,
      final ResultHandler<? super Result> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
@@ -220,7 +220,7 @@
    final int i = messageID.getAndIncrement();
    final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request,
        resultHandler, intermediateResponseHandler, this);
    serverConnection.delete(i, request, future, future);
    serverConnection.handleDelete(i, request, future, future);
    return future;
  }
@@ -239,7 +239,7 @@
    final int i = messageID.getAndIncrement();
    final LDAPExtendedFutureResultImpl<R> future = new LDAPExtendedFutureResultImpl<R>(
        i, request, resultHandler, intermediateResponseHandler, this);
    serverConnection.extendedRequest(i, request, future, future);
    serverConnection.handleExtendedRequest(i, request, future, future);
    return future;
  }
@@ -271,7 +271,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> modify(final ModifyRequest request,
      final ResultHandler<Result> resultHandler,
      final ResultHandler<? super Result> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
@@ -279,7 +279,7 @@
    final int i = messageID.getAndIncrement();
    final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request,
        resultHandler, intermediateResponseHandler, this);
    serverConnection.modify(i, request, future, future);
    serverConnection.handleModify(i, request, future, future);
    return future;
  }
@@ -289,7 +289,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> modifyDN(final ModifyDNRequest request,
      final ResultHandler<Result> resultHandler,
      final ResultHandler<? super Result> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
@@ -297,7 +297,7 @@
    final int i = messageID.getAndIncrement();
    final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request,
        resultHandler, intermediateResponseHandler, this);
    serverConnection.modifyDN(i, request, future, future);
    serverConnection.handleModifyDN(i, request, future, future);
    return future;
  }
@@ -319,17 +319,15 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> search(final SearchRequest request,
      final ResultHandler<Result> resultHandler,
      final SearchResultHandler searchResulthandler,
      final SearchResultHandler resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    final int i = messageID.getAndIncrement();
    final LDAPSearchFutureResultImpl future = new LDAPSearchFutureResultImpl(i,
        request, resultHandler, searchResulthandler,
        intermediateResponseHandler, this);
    serverConnection.search(i, request, future, future, future);
        request, resultHandler, intermediateResponseHandler, this);
    serverConnection.handleSearch(i, request, future, future, future);
    return future;
  }
}
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPBindFutureResultImpl.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.ldap;
@@ -58,6 +58,16 @@
  /**
   * {@inheritDoc}
   */
  @Override
  protected boolean isCancelable() {
    return false;
  }
  @Override
  public String toString()
  {
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPClientFilter.java
@@ -77,21 +77,25 @@
    {
      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
          .removePendingRequest(messageID);
      if (pendingRequest != null)
      if(ldapConnection != null)
      {
        if (pendingRequest instanceof LDAPFutureResultImpl)
        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
            .removePendingRequest(messageID);
        if (pendingRequest != null)
        {
          final LDAPFutureResultImpl future = (LDAPFutureResultImpl) pendingRequest;
          if (future.getRequest() instanceof AddRequest)
          if (pendingRequest instanceof LDAPFutureResultImpl)
          {
            future.setResultOrError(result);
            return;
            final LDAPFutureResultImpl future =
                (LDAPFutureResultImpl) pendingRequest;
            if (future.getRequest() instanceof AddRequest)
            {
              future.setResultOrError(result);
              return;
            }
          }
          throw new UnexpectedResponseException(messageID, result);
        }
        throw new UnexpectedResponseException(messageID, result);
      }
    }
@@ -104,73 +108,79 @@
    {
      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
          .removePendingRequest(messageID);
      if (pendingRequest != null)
      if(ldapConnection != null)
      {
        if (pendingRequest instanceof LDAPBindFutureResultImpl)
        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
            .removePendingRequest(messageID);
        if (pendingRequest != null)
        {
          final LDAPBindFutureResultImpl future = ((LDAPBindFutureResultImpl) pendingRequest);
          final BindClient bindClient = future.getBindClient();
          try
          if (pendingRequest instanceof LDAPBindFutureResultImpl)
          {
            if (!bindClient.evaluateResult(result))
            {
              // The server is expecting a multi stage bind response.
              final int msgID = ldapConnection
                  .addPendingRequest(pendingRequest);
            final LDAPBindFutureResultImpl future =
                ((LDAPBindFutureResultImpl) pendingRequest);
            final BindClient bindClient = future.getBindClient();
              final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
              try
            try
            {
              if (!bindClient.evaluateResult(result))
              {
                final GenericBindRequest nextRequest = bindClient
                    .nextBindRequest();
                new LDAPWriter().bindRequest(asn1Writer, msgID, 3, nextRequest);
                ctx.write(asn1Writer.getBuffer(), null);
                // The server is expecting a multi stage bind response.
                final int msgID = ldapConnection
                    .addPendingRequest(pendingRequest);
                final ASN1BufferWriter asn1Writer =
                    ASN1BufferWriter.getWriter();
                try
                {
                  final GenericBindRequest nextRequest = bindClient
                      .nextBindRequest();
                  new LDAPWriter().bindRequest(asn1Writer, msgID, 3,
                      nextRequest);
                  ctx.write(asn1Writer.getBuffer(), null);
                }
                finally
                {
                  asn1Writer.close();
                }
                return;
              }
              finally
              {
                asn1Writer.close();
              }
            }
            catch (final ErrorResultException e)
            {
              future.adaptErrorResult(e.getResult());
              return;
            }
          }
          catch (final ErrorResultException e)
          {
            future.adaptErrorResult(e.getResult());
            return;
          }
          catch (final IOException e)
          {
            // FIXME: I18N need to have a better error message.
            // FIXME: Is this the best result code?
            final Result errorResult = Responses.newResult(
                ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
                "An error occurred during multi-stage authentication")
                .setCause(e);
            future.adaptErrorResult(errorResult);
            return;
          }
          if (result.getResultCode() == ResultCode.SUCCESS)
          {
            final ConnectionSecurityLayer l = bindClient
                .getConnectionSecurityLayer();
            if (l != null)
            catch (final IOException e)
            {
              // The connection needs to be secured by the SASL
              // mechanism.
              ldapConnection.installFilter(new SASLFilter(l));
              // FIXME: I18N need to have a better error message.
              // FIXME: Is this the best result code?
              final Result errorResult = Responses.newResult(
                  ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
                  "An error occurred during multi-stage authentication")
                  .setCause(e);
              future.adaptErrorResult(errorResult);
              return;
            }
          }
          ldapConnection.setBindOrStartTLSInProgress(false);
          future.setResultOrError(result);
          return;
            if (result.getResultCode() == ResultCode.SUCCESS)
            {
              final ConnectionSecurityLayer l = bindClient
                  .getConnectionSecurityLayer();
              if (l != null)
              {
                // The connection needs to be secured by the SASL
                // mechanism.
                ldapConnection.installFilter(new SASLFilter(l));
              }
            }
            ldapConnection.setBindOrStartTLSInProgress(false);
            future.setResultOrError(result);
            return;
          }
          throw new UnexpectedResponseException(messageID, result);
        }
        throw new UnexpectedResponseException(messageID, result);
      }
    }
@@ -183,18 +193,22 @@
    {
      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
          .removePendingRequest(messageID);
      if (pendingRequest != null)
      if(ldapConnection != null)
      {
        if (pendingRequest instanceof LDAPCompareFutureResultImpl)
        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
            .removePendingRequest(messageID);
        if (pendingRequest != null)
        {
          final LDAPCompareFutureResultImpl future = (LDAPCompareFutureResultImpl) pendingRequest;
          future.setResultOrError(result);
          return;
          if (pendingRequest instanceof LDAPCompareFutureResultImpl)
          {
            final LDAPCompareFutureResultImpl future =
                (LDAPCompareFutureResultImpl) pendingRequest;
            future.setResultOrError(result);
            return;
          }
          throw new UnexpectedResponseException(messageID, result);
        }
        throw new UnexpectedResponseException(messageID, result);
      }
    }
@@ -206,21 +220,25 @@
    {
      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
          .removePendingRequest(messageID);
      if (pendingRequest != null)
      if(ldapConnection != null)
      {
        if (pendingRequest instanceof LDAPFutureResultImpl)
        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
            .removePendingRequest(messageID);
        if (pendingRequest != null)
        {
          final LDAPFutureResultImpl future = (LDAPFutureResultImpl) pendingRequest;
          if (future.getRequest() instanceof DeleteRequest)
          if (pendingRequest instanceof LDAPFutureResultImpl)
          {
            future.setResultOrError(result);
            return;
            final LDAPFutureResultImpl future =
                (LDAPFutureResultImpl) pendingRequest;
            if (future.getRequest() instanceof DeleteRequest)
            {
              future.setResultOrError(result);
              return;
            }
          }
          throw new UnexpectedResponseException(messageID, result);
        }
        throw new UnexpectedResponseException(messageID, result);
      }
    }
@@ -233,48 +251,54 @@
    {
      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      if (messageID == 0)
      if(ldapConnection != null)
      {
        if ((result.getOID() != null)
            && result.getOID().equals(OID_NOTICE_OF_DISCONNECTION))
        if (messageID == 0)
        {
          if ((result.getOID() != null)
              && result.getOID().equals(OID_NOTICE_OF_DISCONNECTION))
          {
          final Result errorResult = Responses
              .newResult(result.getResultCode()).setDiagnosticMessage(
                  result.getDiagnosticMessage());
          ldapConnection.close(null, true, errorResult);
          return;
            final Result errorResult = Responses
                .newResult(result.getResultCode()).setDiagnosticMessage(
                    result.getDiagnosticMessage());
            ldapConnection.close(null, true, errorResult);
            return;
          }
          else
          {
            // Unsolicited notification received.
            ldapConnection.handleUnsolicitedNotification(result);
          }
        }
        else
        {
          // Unsolicited notification received.
          ldapConnection.handleUnsolicitedNotification(result);
        }
      }
      final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
          .removePendingRequest(messageID);
        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
            .removePendingRequest(messageID);
      if (pendingRequest instanceof LDAPExtendedFutureResultImpl<?>)
      {
        final LDAPExtendedFutureResultImpl<?> extendedFuture =
          ((LDAPExtendedFutureResultImpl<?>) pendingRequest);
        try
        if(pendingRequest != null)
        {
          handleExtendedResult0(ldapConnection, extendedFuture, result);
          if (pendingRequest instanceof LDAPExtendedFutureResultImpl<?>)
          {
            final LDAPExtendedFutureResultImpl<?> extendedFuture =
              ((LDAPExtendedFutureResultImpl<?>) pendingRequest);
            try
            {
              handleExtendedResult0(ldapConnection, extendedFuture, result);
            }
            catch (final DecodeException de)
            {
              // FIXME: should the connection be closed as well?
              final Result errorResult = Responses.newResult(
                  ResultCode.CLIENT_SIDE_DECODING_ERROR).setDiagnosticMessage(
                  de.getLocalizedMessage()).setCause(de);
              extendedFuture.adaptErrorResult(errorResult);
            }
          }
          else
          {
            throw new UnexpectedResponseException(messageID, result);
          }
        }
        catch (final DecodeException de)
        {
          // FIXME: should the connection be closed as well?
          final Result errorResult = Responses.newResult(
              ResultCode.CLIENT_SIDE_DECODING_ERROR).setDiagnosticMessage(
              de.getLocalizedMessage()).setCause(de);
          extendedFuture.adaptErrorResult(errorResult);
        }
      }
      else
      {
        throw new UnexpectedResponseException(messageID, result);
      }
    }
@@ -287,12 +311,15 @@
    {
      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
          .getPendingRequest(messageID);
      if (pendingRequest != null)
      if(ldapConnection != null)
      {
        pendingRequest.handleIntermediateResponse(response);
        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
            .getPendingRequest(messageID);
        if (pendingRequest != null)
        {
          pendingRequest.handleIntermediateResponse(response);
        }
      }
    }
@@ -305,21 +332,25 @@
    {
      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
          .removePendingRequest(messageID);
      if (pendingRequest != null)
      if(ldapConnection != null)
      {
        if (pendingRequest instanceof LDAPFutureResultImpl)
        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
            .removePendingRequest(messageID);
        if (pendingRequest != null)
        {
          final LDAPFutureResultImpl future = (LDAPFutureResultImpl) pendingRequest;
          if (future.getRequest() instanceof ModifyDNRequest)
          if (pendingRequest instanceof LDAPFutureResultImpl)
          {
            future.setResultOrError(result);
            return;
            final LDAPFutureResultImpl future =
                (LDAPFutureResultImpl) pendingRequest;
            if (future.getRequest() instanceof ModifyDNRequest)
            {
              future.setResultOrError(result);
              return;
            }
          }
          throw new UnexpectedResponseException(messageID, result);
        }
        throw new UnexpectedResponseException(messageID, result);
      }
    }
@@ -331,21 +362,25 @@
    {
      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
          .removePendingRequest(messageID);
      if (pendingRequest != null)
      if(ldapConnection != null)
      {
        if (pendingRequest instanceof LDAPFutureResultImpl)
        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
            .removePendingRequest(messageID);
        if (pendingRequest != null)
        {
          final LDAPFutureResultImpl future = (LDAPFutureResultImpl) pendingRequest;
          if (future.getRequest() instanceof ModifyRequest)
          if (pendingRequest instanceof LDAPFutureResultImpl)
          {
            future.setResultOrError(result);
            return;
            final LDAPFutureResultImpl future =
                (LDAPFutureResultImpl) pendingRequest;
            if (future.getRequest() instanceof ModifyRequest)
            {
              future.setResultOrError(result);
              return;
            }
          }
          throw new UnexpectedResponseException(messageID, result);
        }
        throw new UnexpectedResponseException(messageID, result);
      }
    }
@@ -357,19 +392,22 @@
    {
      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
          .removePendingRequest(messageID);
      if (pendingRequest != null)
      if(ldapConnection != null)
      {
        if (pendingRequest instanceof LDAPSearchFutureResultImpl)
        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
            .removePendingRequest(messageID);
        if (pendingRequest != null)
        {
          ((LDAPSearchFutureResultImpl) pendingRequest)
              .setResultOrError(result);
        }
        else
        {
          throw new UnexpectedResponseException(messageID, result);
          if (pendingRequest instanceof LDAPSearchFutureResultImpl)
          {
            ((LDAPSearchFutureResultImpl) pendingRequest)
                .setResultOrError(result);
          }
          else
          {
            throw new UnexpectedResponseException(messageID, result);
          }
        }
      }
    }
@@ -383,18 +421,21 @@
    {
      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
          .getPendingRequest(messageID);
      if (pendingRequest != null)
      if(ldapConnection != null)
      {
        if (pendingRequest instanceof LDAPSearchFutureResultImpl)
        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
            .getPendingRequest(messageID);
        if (pendingRequest != null)
        {
          ((LDAPSearchFutureResultImpl) pendingRequest).handleEntry(entry);
        }
        else
        {
          throw new UnexpectedResponseException(messageID, entry);
          if (pendingRequest instanceof LDAPSearchFutureResultImpl)
          {
            ((LDAPSearchFutureResultImpl) pendingRequest).handleEntry(entry);
          }
          else
          {
            throw new UnexpectedResponseException(messageID, entry);
          }
        }
      }
    }
@@ -408,19 +449,22 @@
    {
      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
          .getPendingRequest(messageID);
      if (pendingRequest != null)
      if(ldapConnection != null)
      {
        if (pendingRequest instanceof LDAPSearchFutureResultImpl)
        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
            .getPendingRequest(messageID);
        if (pendingRequest != null)
        {
          ((LDAPSearchFutureResultImpl) pendingRequest)
              .handleReference(reference);
        }
        else
        {
          throw new UnexpectedResponseException(messageID, reference);
          if (pendingRequest instanceof LDAPSearchFutureResultImpl)
          {
            ((LDAPSearchFutureResultImpl) pendingRequest)
                .handleReference(reference);
          }
          else
          {
            throw new UnexpectedResponseException(messageID, reference);
          }
        }
      }
    }
@@ -445,6 +489,7 @@
            final StartTLSExtendedRequest request = (StartTLSExtendedRequest) future
                .getRequest();
            conn.startTLS(request.getSSLContext(),
                request.getEnabledProtocols(), request.getEnabledCipherSuites(),
                new EmptyCompletionHandler<SSLEngine>()
                {
                  @Override
@@ -521,7 +566,7 @@
    {
      // FIXME: what other sort of IOExceptions can be thrown?
      // FIXME: Is this the best result code?
      errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR)
      errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR)
          .setCause(error);
    }
    ldapConnection.close(null, false, errorResult);
@@ -568,6 +613,16 @@
        ldapReader.decode(asn1Reader, CLIENT_RESPONSE_HANDLER, ctx);
      }
    }
    catch(IOException ioe)
    {
      final LDAPConnection ldapConnection =
          LDAP_CONNECTION_ATTR.get(ctx.getConnection());
      final Result errorResult =
          Responses.newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR)
              .setCause(ioe).setDiagnosticMessage(ioe.getMessage());
      ldapConnection.close(null, false, errorResult);
      throw ioe;
    }
    finally
    {
      asn1Reader.disposeBytesRead();
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnection.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.ldap;
@@ -30,9 +30,9 @@
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -79,8 +79,9 @@
  private boolean bindOrStartTLSInProgress = false;
  private final HashMap<Integer, AbstractLDAPFutureResultImpl<?>>
    pendingRequests = new HashMap<Integer, AbstractLDAPFutureResultImpl<?>>();
  private final ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>>
    pendingRequests =
      new ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>>();
  private final Object stateLock = new Object();
@@ -112,21 +113,7 @@
   */
  public FutureResult<Void> abandon(final AbandonRequest request)
  {
    // First remove the future associated with the request to be abandoned.
    final AbstractLDAPFutureResultImpl<?> pendingRequest = pendingRequests
        .remove(request.getMessageID());
    if (pendingRequest == null)
    {
      // There has never been a request with the specified message ID or the
      // response has already been received and handled. We can ignore this
      // abandon request.
      // Message ID will be -1 since no request was sent.
      return new CompletedFutureResult<Void>((Void) null);
    }
    pendingRequest.cancel(false);
    final AbstractLDAPFutureResultImpl<?> pendingRequest;
    final int messageID = nextMsgID.getAndIncrement();
    synchronized (stateLock)
@@ -144,8 +131,23 @@
        return new CompletedFutureResult<Void>(ErrorResultException
            .wrap(errorResult), messageID);
      }
      // First remove the future associated with the request to be abandoned.
      pendingRequest = pendingRequests.remove(request.getMessageID());
    }
    if (pendingRequest == null)
    {
      // There has never been a request with the specified message ID or the
      // response has already been received and handled. We can ignore this
      // abandon request.
      // Message ID will be -1 since no request was sent.
      return new CompletedFutureResult<Void>((Void) null);
    }
    pendingRequest.cancel(false);
    try
    {
      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
@@ -178,7 +180,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> add(final AddRequest request,
      final ResultHandler<Result> resultHandler,
      final ResultHandler<? super Result> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
  {
    final int messageID = nextMsgID.getAndIncrement();
@@ -256,8 +258,10 @@
    BindClient context;
    try
    {
      context = request
          .createBindClient(connection.getPeerAddress().toString());
      context = request.createBindClient(
          connection.getPeerAddress() instanceof InetSocketAddress ?
              ((InetSocketAddress)connection.getPeerAddress()).getHostName() :
              connection.getPeerAddress().toString());
    }
    catch (final Exception e)
    {
@@ -414,7 +418,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> delete(final DeleteRequest request,
      final ResultHandler<Result> resultHandler,
      final ResultHandler<? super Result> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
  {
    final int messageID = nextMsgID.getAndIncrement();
@@ -568,7 +572,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> modify(final ModifyRequest request,
      final ResultHandler<Result> resultHandler,
      final ResultHandler<? super Result> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
  {
    final int messageID = nextMsgID.getAndIncrement();
@@ -626,7 +630,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> modifyDN(final ModifyDNRequest request,
      final ResultHandler<Result> resultHandler,
      final ResultHandler<? super Result> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
  {
    final int messageID = nextMsgID.getAndIncrement();
@@ -696,14 +700,12 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> search(final SearchRequest request,
      final ResultHandler<Result> resultHandler,
      final SearchResultHandler searchResultHandler,
      final SearchResultHandler resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
  {
    final int messageID = nextMsgID.getAndIncrement();
    final LDAPSearchFutureResultImpl future = new LDAPSearchFutureResultImpl(
        messageID, request, resultHandler, searchResultHandler,
        intermediateResponseHandler, this);
        messageID, request, resultHandler, intermediateResponseHandler, this);
    synchronized (stateLock)
    {
@@ -753,9 +755,17 @@
  int addPendingRequest(final AbstractLDAPFutureResultImpl<?> request)
      throws ErrorResultException
  {
    final int newMsgID = nextMsgID.getAndIncrement();
    pendingRequests.put(newMsgID, request);
    synchronized(stateLock)
    {
      if(connectionInvalidReason != null)
      {
        throw ErrorResultException.wrap(connectionInvalidReason);
      }
      pendingRequests.put(newMsgID, request);
    }
    return newMsgID;
  }
@@ -767,21 +777,20 @@
    long delay = timeout;
    if (timeout > 0)
    {
      synchronized (stateLock)
      for (int requestID : pendingRequests.keySet())
      {
        for (final Iterator<AbstractLDAPFutureResultImpl<?>> i = pendingRequests
            .values().iterator(); i.hasNext();)
        final AbstractLDAPFutureResultImpl<?> future =
            pendingRequests.get(requestID);
        if(future != null)
        {
          final AbstractLDAPFutureResultImpl<?> future = i.next();
          final long diff = (future.getTimestamp() + timeout) - currentTime;
          if (diff <= 0)
          if (diff <= 0 && pendingRequests.remove(requestID) != null)
          {
            StaticUtils.DEBUG_LOG.fine("Cancelling expired future result: "
                + future);
            final Result result = Responses
                .newResult(ResultCode.CLIENT_SIDE_TIMEOUT);
            future.adaptErrorResult(result);
            i.remove();
            abandon(Requests.newAbandonRequest(future.getRequestID()));
          }
@@ -805,7 +814,7 @@
    synchronized (stateLock)
    {
      if (isClosed)
      if (isClosed || connectionInvalidReason != null)
      {
        // Already closed.
        return;
@@ -822,51 +831,29 @@
        notifyErrorOccurred = true;
      }
      if (connectionInvalidReason != null)
      {
        // Already invalid.
        return;
      }
      // Mark the connection as invalid.
      connectionInvalidReason = reason;
      connectionInvalidReason =
          reason.getResultCode() == ResultCode.CLIENT_SIDE_USER_CANCELLED ?
              reason : Responses.newResult(
              ResultCode.CLIENT_SIDE_USER_CANCELLED).setCause(
              ErrorResultException.wrap(reason)).setDiagnosticMessage(
              "Connection closed: " + reason.getDiagnosticMessage());
    }
    // First abort all outstanding requests.
    for (final AbstractLDAPFutureResultImpl<?> future : pendingRequests
        .values())
    for (int requestID : pendingRequests.keySet())
    {
      if (!bindOrStartTLSInProgress)
      final AbstractLDAPFutureResultImpl<?> future =
          pendingRequests.remove(requestID);
      if(future != null)
      {
        final int messageID = nextMsgID.getAndIncrement();
        final AbandonRequest abandon = Requests.newAbandonRequest(future
            .getRequestID());
        try
        {
          final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
          try
          {
            ldapWriter.abandonRequest(asn1Writer, messageID, abandon);
            connection.write(asn1Writer.getBuffer(), null);
          }
          finally
          {
            asn1Writer.recycle();
          }
        }
        catch (final IOException e)
        {
          // Underlying channel probably blown up. Just ignore.
        }
        future.adaptErrorResult(reason);
      }
      future.adaptErrorResult(reason);
    }
    pendingRequests.clear();
    // Now try cleanly closing the connection if possible.
    // Only send unbind if specified.
    if (unbindRequest != null)
    if (unbindRequest != null && !isDisconnectNotification)
    {
      try
      {
@@ -902,7 +889,7 @@
    {
      for (final ConnectionEventListener listener : listeners)
      {
        listener.connectionClosed();
        listener.handleConnectionClosed();
      }
    }
@@ -910,7 +897,7 @@
    {
      for (final ConnectionEventListener listener : listeners)
      {
        listener.connectionErrorOccurred(isDisconnectNotification,
        listener.handleConnectionError(isDisconnectNotification,
            ErrorResultException.wrap(reason));
      }
    }
@@ -942,7 +929,7 @@
    for (final ConnectionEventListener listener : listeners)
    {
      listener.connectionReceivedUnsolicitedNotification(result);
      listener.handleUnsolicitedNotification(result);
    }
  }
@@ -993,6 +980,7 @@
  synchronized void startTLS(final SSLContext sslContext,
      final String[] protocols, final String[] cipherSuites,
      final CompletionHandler<SSLEngine> completionHandler) throws IOException
  {
    if (isTLSEnabled())
@@ -1005,6 +993,8 @@
    sslEngineConfigurator = new SSLEngineConfigurator(sslContext, true, false,
        false);
    sslEngineConfigurator.setEnabledProtocols(protocols);
    sslEngineConfigurator.setEnabledCipherSuites(cipherSuites);
    sslFilter = new SSLFilter(null, sslEngineConfigurator);
    installFilter(sslFilter);
    sslFilter.handshake(connection, completionHandler);
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPConnectionFactoryImpl.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.ldap;
@@ -62,7 +62,7 @@
    implements ConnectionFactory
{
  @SuppressWarnings("unchecked")
  @SuppressWarnings("rawtypes")
  private final class FutureResultImpl implements CompletionHandler<Connection>
  {
    private final FutureResultTransformer<Result, AsynchronousConnection> futureStartTLSResult;
@@ -123,6 +123,8 @@
          {
            final StartTLSExtendedRequest startTLS = Requests
                .newStartTLSExtendedRequest(options.getSSLContext());
            startTLS.setEnabledCipherSuites(options.getEnabledCipherSuites());
            startTLS.setEnabledProtocols(options.getEnabledProtocols());
            return connection.extendedRequest(startTLS, handler);
          }
@@ -131,6 +133,8 @@
            try
            {
              connection.startTLS(options.getSSLContext(),
                  options.getEnabledProtocols(),
                  options.getEnabledCipherSuites(),
                  new EmptyCompletionHandler<SSLEngine>()
                  {
                    @Override
@@ -269,7 +273,7 @@
   */
  @Override
  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
      final ResultHandler<AsynchronousConnection> handler)
      final ResultHandler<? super AsynchronousConnection> handler)
  {
    final FutureResultImpl future = new FutureResultImpl(handler);
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPExtendedFutureResultImpl.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.ldap;
@@ -31,6 +31,7 @@
import org.opends.sdk.*;
import org.opends.sdk.requests.ExtendedRequest;
import org.opends.sdk.requests.StartTLSExtendedRequest;
import org.opends.sdk.responses.ExtendedResult;
@@ -74,6 +75,16 @@
  /**
   * {@inheritDoc}
   */
  @Override
  protected boolean isCancelable() {
    return !request.getOID().equals(StartTLSExtendedRequest.OID);
  }
  R decodeResult(final ExtendedResult result, final DecodeOptions options)
      throws DecodeException
  {
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPFutureResultImpl.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.ldap;
@@ -47,7 +47,7 @@
  LDAPFutureResultImpl(final int messageID, final Request request,
      final ResultHandler<Result> resultHandler,
      final ResultHandler<? super Result> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler,
      final AsynchronousConnection connection)
  {
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPSearchFutureResultImpl.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.ldap;
@@ -53,14 +53,13 @@
  LDAPSearchFutureResultImpl(final int messageID, final SearchRequest request,
      final ResultHandler<Result> resultHandler,
      final SearchResultHandler searchResultHandler,
      final SearchResultHandler resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler,
      final AsynchronousConnection connection)
  {
    super(messageID, resultHandler, intermediateResponseHandler, connection);
    this.request = request;
    this.searchResultHandler = searchResultHandler;
    this.searchResultHandler = resultHandler;
  }
opendj-sdk/sdk/src/com/sun/opends/sdk/ldap/LDAPServerFilter.java
@@ -33,8 +33,7 @@
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.*;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
@@ -66,8 +65,8 @@
  private abstract class AbstractHandler<R extends Result> implements
      IntermediateResponseHandler, ResultHandler<R>
  {
    protected int messageID;
    protected Connection<?> connection;
    protected final int messageID;
    protected final Connection<?> connection;
@@ -80,6 +79,7 @@
    @Override
    public boolean handleIntermediateResponse(
        final IntermediateResponse response)
    {
@@ -91,7 +91,7 @@
      }
      catch (final IOException ioe)
      {
        closeConnection(connection, ioe);
        notifyConnectionException(connection, ioe);
        return false;
      }
      finally
@@ -114,6 +114,7 @@
    @Override
    public void handleErrorResult(final ErrorResultException error)
    {
      handleResult(error.getResult());
@@ -121,6 +122,7 @@
    @Override
    public void handleResult(final Result result)
    {
      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
@@ -131,7 +133,7 @@
      }
      catch (final IOException ioe)
      {
        closeConnection(connection, ioe);
        notifyConnectionException(connection, ioe);
      }
      finally
      {
@@ -151,6 +153,7 @@
    @Override
    public void handleErrorResult(final ErrorResultException error)
    {
      final Result result = error.getResult();
@@ -175,6 +178,7 @@
    @Override
    public void handleResult(final BindResult result)
    {
      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
@@ -185,7 +189,7 @@
      }
      catch (final IOException ioe)
      {
        closeConnection(connection, ioe);
        notifyConnectionException(connection, ioe);
      }
      finally
      {
@@ -198,7 +202,16 @@
  private final class ClientContextImpl implements LDAPClientContext
  {
    protected Connection<?> connection;
    private final Connection<?> connection;
    // Connection state guarded by stateLock.
    private final Object stateLock = new Object();
    private List<ConnectionEventListener> connectionEventListeners = null;
    private boolean isClosed = false;
    private Throwable connectionError = null;
    private ExtendedResult disconnectNotification = null;
    private ServerConnection<Integer> serverConnection = null;
@@ -209,20 +222,64 @@
    public void disconnect(final boolean sendNotification)
    /**
     * {@inheritDoc}
     */
    @Override
    public void addConnectionEventListener(
        final ConnectionEventListener listener) throws NullPointerException
    {
      if (sendNotification)
      Validator.ensureNotNull(listener);
      boolean invokeImmediately = false;
      synchronized (stateLock)
      {
        final GenericExtendedResult notification = Responses
            .newGenericExtendedResult(ResultCode.SUCCESS);
        notification.setOID(OID_NOTICE_OF_DISCONNECTION);
        sendUnsolicitedNotification(notification);
        if (isClosed)
        {
          invokeImmediately = true;
        }
        else
        {
          if (connectionEventListeners == null)
          {
            connectionEventListeners = new LinkedList<ConnectionEventListener>();
          }
          connectionEventListeners.add(listener);
        }
      }
      closeConnection(connection, -1, null);
      // Invoke listener immediately if this connection is already closed.
      if (invokeImmediately)
      {
        invokeListener(listener);
      }
    }
    @Override
    public void disconnect()
    {
      LDAPServerFilter.notifyConnectionClosed(connection, -1, null);
    }
    @Override
    public void disconnect(final ResultCode resultCode, final String message)
    {
      Validator.ensureNotNull(resultCode);
      final GenericExtendedResult notification = Responses
          .newGenericExtendedResult(resultCode)
          .setOID(OID_NOTICE_OF_DISCONNECTION).setDiagnosticMessage(message);
      sendUnsolicitedNotification(notification);
      disconnect();
    }
    @Override
    public InetSocketAddress getLocalAddress()
    {
      return (InetSocketAddress) connection.getLocalAddress();
@@ -230,6 +287,7 @@
    @Override
    public InetSocketAddress getPeerAddress()
    {
      return (InetSocketAddress) connection.getPeerAddress();
@@ -237,6 +295,7 @@
    @Override
    public int getSecurityStrengthFactor()
    {
      int ssf = 0;
@@ -260,6 +319,43 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isClosed()
    {
      final boolean tmp;
      synchronized (stateLock)
      {
        tmp = isClosed;
      }
      return tmp;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void removeConnectionEventListener(
        final ConnectionEventListener listener) throws NullPointerException
    {
      Validator.ensureNotNull(listener);
      synchronized (stateLock)
      {
        if (connectionEventListeners != null)
        {
          connectionEventListeners.remove(listener);
        }
      }
    }
    @Override
    public void sendUnsolicitedNotification(final ExtendedResult notification)
    {
      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
@@ -270,16 +366,49 @@
      }
      catch (final IOException ioe)
      {
        closeConnection(connection, ioe);
        LDAPServerFilter.notifyConnectionException(connection, ioe);
      }
      finally
      {
        asn1Writer.recycle();
      }
      // Update state and notify event listeners if necessary, only if the
      // notification was sent successfully.
      if (notification.getOID().equals(OID_NOTICE_OF_DISCONNECTION))
      {
        // Don't notify listeners yet - wait for disconnect.
        synchronized (stateLock)
        {
          disconnectNotification = notification;
        }
      }
      else
      {
        // Notify listeners.
        List<ConnectionEventListener> tmpList = null;
        synchronized (stateLock)
        {
          if (!isClosed && connectionEventListeners != null)
          {
            tmpList = new ArrayList<ConnectionEventListener>(
                connectionEventListeners);
          }
        }
        if (tmpList != null)
        {
          for (final ConnectionEventListener listener : tmpList)
          {
            listener.handleUnsolicitedNotification(notification);
          }
        }
      }
    }
    @Override
    public void startSASL(final ConnectionSecurityLayer bindContext)
    {
      installFilter(connection, new SASLFilter(bindContext));
@@ -287,15 +416,119 @@
    public void startTLS(final SSLContext sslContext)
    @Override
    public void startTLS(final SSLContext sslContext, final String[] protocols,
        final String[] suites, final boolean wantClientAuth,
        final boolean needClientAuth)
    {
      Validator.ensureNotNull(sslContext);
      SSLEngineConfigurator sslEngineConfigurator;
      sslEngineConfigurator = new SSLEngineConfigurator(sslContext, false,
          false, false);
      sslEngineConfigurator.setEnabledCipherSuites(suites);
      sslEngineConfigurator.setEnabledProtocols(protocols);
      sslEngineConfigurator.setWantClientAuth(wantClientAuth);
      sslEngineConfigurator.setNeedClientAuth(needClientAuth);
      installFilter(connection, new SSLFilter(sslEngineConfigurator, null));
    }
    private ServerConnection<Integer> getServerConnection()
    {
      return serverConnection;
    }
    private void invokeListener(final ConnectionEventListener listener)
    {
      if (connectionError != null)
      {
        final Result result;
        if (connectionError instanceof DecodeException)
        {
          final DecodeException e = (DecodeException) connectionError;
          result = Responses.newResult(ResultCode.PROTOCOL_ERROR)
              .setDiagnosticMessage(e.getMessage()).setCause(connectionError);
        }
        else
        {
          result = Responses.newResult(ResultCode.OTHER)
              .setDiagnosticMessage(connectionError.getMessage())
              .setCause(connectionError);
        }
        listener
            .handleConnectionError(false, ErrorResultException.wrap(result));
      }
      else if (disconnectNotification != null)
      {
        listener.handleConnectionError(true,
            ErrorResultException.wrap(disconnectNotification));
      }
      else
      {
        listener.handleConnectionClosed();
      }
    }
    private void notifyConnectionClosed(final int messageID,
        final UnbindRequest unbindRequest)
    {
      final List<ConnectionEventListener> tmpList;
      synchronized (stateLock)
      {
        if (!isClosed)
        {
          isClosed = true;
        }
        tmpList = connectionEventListeners;
        connectionEventListeners = null;
      }
      if (tmpList != null)
      {
        for (final ConnectionEventListener listener : tmpList)
        {
          invokeListener(listener);
        }
      }
    }
    private void notifyConnectionException(final Throwable error)
    {
      final List<ConnectionEventListener> tmpList;
      synchronized (stateLock)
      {
        if (!isClosed)
        {
          connectionError = error;
          isClosed = true;
        }
        tmpList = connectionEventListeners;
        connectionEventListeners = null;
      }
      if (tmpList != null)
      {
        for (final ConnectionEventListener listener : tmpList)
        {
          invokeListener(listener);
        }
      }
    }
    private void setServerConnection(
        final ServerConnection<Integer> serverConnection)
    {
      this.serverConnection = serverConnection;
    }
  }
@@ -309,6 +542,7 @@
    @Override
    public void handleErrorResult(final ErrorResultException error)
    {
      final Result result = error.getResult();
@@ -333,6 +567,7 @@
    @Override
    public void handleResult(final CompareResult result)
    {
      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
@@ -343,7 +578,7 @@
      }
      catch (final IOException ioe)
      {
        closeConnection(connection, ioe);
        notifyConnectionException(connection, ioe);
      }
      finally
      {
@@ -363,6 +598,7 @@
    @Override
    public void handleErrorResult(final ErrorResultException error)
    {
      handleResult(error.getResult());
@@ -370,6 +606,7 @@
    @Override
    public void handleResult(final Result result)
    {
      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
@@ -380,7 +617,7 @@
      }
      catch (final IOException ioe)
      {
        closeConnection(connection, ioe);
        notifyConnectionException(connection, ioe);
      }
      finally
      {
@@ -401,6 +638,7 @@
    @Override
    public void handleErrorResult(final ErrorResultException error)
    {
      final Result result = error.getResult();
@@ -425,6 +663,7 @@
    @Override
    public void handleResult(final ExtendedResult result)
    {
      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
@@ -435,7 +674,7 @@
      }
      catch (final IOException ioe)
      {
        closeConnection(connection, ioe);
        notifyConnectionException(connection, ioe);
      }
      finally
      {
@@ -455,6 +694,7 @@
    @Override
    public void handleErrorResult(final ErrorResultException error)
    {
      handleResult(error.getResult());
@@ -462,6 +702,7 @@
    @Override
    public void handleResult(final Result result)
    {
      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
@@ -472,7 +713,7 @@
      }
      catch (final IOException ioe)
      {
        closeConnection(connection, ioe);
        notifyConnectionException(connection, ioe);
      }
      finally
      {
@@ -492,6 +733,7 @@
    @Override
    public void handleErrorResult(final ErrorResultException error)
    {
      handleResult(error.getResult());
@@ -499,6 +741,7 @@
    @Override
    public void handleResult(final Result result)
    {
      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
@@ -509,7 +752,7 @@
      }
      catch (final IOException ioe)
      {
        closeConnection(connection, ioe);
        notifyConnectionException(connection, ioe);
      }
      finally
      {
@@ -530,6 +773,7 @@
    @Override
    public boolean handleEntry(final SearchResultEntry entry)
    {
      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
@@ -540,7 +784,7 @@
      }
      catch (final IOException ioe)
      {
        closeConnection(connection, ioe);
        notifyConnectionException(connection, ioe);
        return false;
      }
      finally
@@ -552,6 +796,7 @@
    @Override
    public void handleErrorResult(final ErrorResultException error)
    {
      handleResult(error.getResult());
@@ -559,6 +804,7 @@
    @Override
    public boolean handleReference(final SearchResultReference reference)
    {
      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
@@ -569,7 +815,7 @@
      }
      catch (final IOException ioe)
      {
        closeConnection(connection, ioe);
        notifyConnectionException(connection, ioe);
        return false;
      }
      finally
@@ -581,6 +827,7 @@
    @Override
    public void handleResult(final Result result)
    {
      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
@@ -591,7 +838,7 @@
      }
      catch (final IOException ioe)
      {
        closeConnection(connection, ioe);
        notifyConnectionException(connection, ioe);
      }
      finally
      {
@@ -627,24 +874,101 @@
  private static final LDAPWriter LDAP_WRITER = new LDAPWriter();
  private static final Attribute<ServerConnection<Integer>>
    LDAP_CONNECTION_ATTR = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.
      createAttribute("LDAPServerConnection");
  private static final Attribute<ClientContextImpl> LDAP_CONNECTION_ATTR =
    Grizzly.DEFAULT_ATTRIBUTE_BUILDER
      .createAttribute("LDAPServerConnection");
  private static final Attribute<ASN1BufferReader> LDAP_ASN1_READER_ATTR =
    Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPASN1Reader");
    Grizzly.DEFAULT_ATTRIBUTE_BUILDER
      .createAttribute("LDAPASN1Reader");
  private final AbstractLDAPMessageHandler<FilterChainContext>
    serverRequestHandler = new AbstractLDAPMessageHandler<FilterChainContext>()
  private static void notifyConnectionClosed(final Connection<?> connection,
      final int messageID, final UnbindRequest unbindRequest)
  {
    final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR
        .remove(connection);
    if (clientContext != null)
    {
      // First notify connection event listeners.
      clientContext.notifyConnectionClosed(messageID, unbindRequest);
      // Notify the server connection: it may be null if disconnect is invoked
      // during accept.
      final ServerConnection<Integer> serverConnection = clientContext
          .getServerConnection();
      if (serverConnection != null)
      {
        serverConnection.handleConnectionClosed(messageID, unbindRequest);
      }
      // If this close was a result of an unbind request then the connection
      // won't actually be closed yet. To avoid TIME_WAIT TCP state, let the
      // client disconnect.
      if (unbindRequest != null)
      {
        return;
      }
      // Close the connection.
      try
      {
        connection.close();
      }
      catch (final IOException e)
      {
        StaticUtils.DEBUG_LOG.warning("Error closing connection: " + e);
      }
    }
  }
  private static void notifyConnectionException(final Connection<?> connection,
      final Throwable error)
  {
    final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR
        .remove(connection);
    if (clientContext != null)
    {
      // First notify connection event listeners.
      clientContext.notifyConnectionException(error);
      // Notify the server connection: it may be null if disconnect is invoked
      // during accept.
      final ServerConnection<Integer> serverConnection = clientContext
          .getServerConnection();
      if (serverConnection != null)
      {
        serverConnection.handleConnectionException(error);
      }
      // Close the connection.
      try
      {
        connection.close();
      }
      catch (final IOException e)
      {
        StaticUtils.DEBUG_LOG.warning("Error closing connection: " + e);
      }
    }
  }
  private final AbstractLDAPMessageHandler<FilterChainContext> serverRequestHandler =
    new AbstractLDAPMessageHandler<FilterChainContext>()
  {
    @Override
    public void abandonRequest(final FilterChainContext ctx,
        final int messageID, final AbandonRequest request)
        throws UnexpectedRequestException
    {
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      conn.abandon(messageID, request);
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(
          ctx.getConnection()).getServerConnection();
      conn.handleAbandon(messageID, request);
    }
@@ -653,10 +977,10 @@
    public void addRequest(final FilterChainContext ctx, final int messageID,
        final AddRequest request) throws UnexpectedRequestException
    {
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(
          ctx.getConnection()).getServerConnection();
      final AddHandler handler = new AddHandler(messageID, ctx.getConnection());
      conn.add(messageID, request, handler, handler);
      conn.handleAdd(messageID, request, handler, handler);
    }
@@ -666,11 +990,11 @@
        final int version, final GenericBindRequest bindContext)
        throws UnexpectedRequestException
    {
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final BindHandler handler = new BindHandler(messageID, ctx
          .getConnection());
      conn.bind(messageID, version, bindContext, handler, handler);
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(
          ctx.getConnection()).getServerConnection();
      final BindHandler handler = new BindHandler(messageID,
          ctx.getConnection());
      conn.handleBind(messageID, version, bindContext, handler, handler);
    }
@@ -680,11 +1004,11 @@
        final int messageID, final CompareRequest request)
        throws UnexpectedRequestException
    {
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final CompareHandler handler = new CompareHandler(messageID, ctx
          .getConnection());
      conn.compare(messageID, request, handler, handler);
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(
          ctx.getConnection()).getServerConnection();
      final CompareHandler handler = new CompareHandler(messageID,
          ctx.getConnection());
      conn.handleCompare(messageID, request, handler, handler);
    }
@@ -694,11 +1018,11 @@
        final int messageID, final DeleteRequest request)
        throws UnexpectedRequestException
    {
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final DeleteHandler handler = new DeleteHandler(messageID, ctx
          .getConnection());
      conn.delete(messageID, request, handler, handler);
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(
          ctx.getConnection()).getServerConnection();
      final DeleteHandler handler = new DeleteHandler(messageID,
          ctx.getConnection());
      conn.handleDelete(messageID, request, handler, handler);
    }
@@ -708,12 +1032,12 @@
        final FilterChainContext ctx, final int messageID,
        final ExtendedRequest<R> request) throws UnexpectedRequestException
    {
      final ExtendedHandler<R> handler = new ExtendedHandler<R>(messageID, ctx
          .getConnection());
      final ExtendedHandler<R> handler = new ExtendedHandler<R>(messageID,
          ctx.getConnection());
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      conn.extendedRequest(messageID, request, handler, handler);
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(
          ctx.getConnection()).getServerConnection();
      conn.handleExtendedRequest(messageID, request, handler, handler);
    }
@@ -723,11 +1047,11 @@
        final int messageID, final ModifyDNRequest request)
        throws UnexpectedRequestException
    {
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final ModifyDNHandler handler = new ModifyDNHandler(messageID, ctx
          .getConnection());
      conn.modifyDN(messageID, request, handler, handler);
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(
          ctx.getConnection()).getServerConnection();
      final ModifyDNHandler handler = new ModifyDNHandler(messageID,
          ctx.getConnection());
      conn.handleModifyDN(messageID, request, handler, handler);
    }
@@ -737,11 +1061,11 @@
        final int messageID, final ModifyRequest request)
        throws UnexpectedRequestException
    {
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final ModifyHandler handler = new ModifyHandler(messageID, ctx
          .getConnection());
      conn.modify(messageID, request, handler, handler);
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(
          ctx.getConnection()).getServerConnection();
      final ModifyHandler handler = new ModifyHandler(messageID,
          ctx.getConnection());
      conn.handleModify(messageID, request, handler, handler);
    }
@@ -751,11 +1075,11 @@
        final int messageID, final SearchRequest request)
        throws UnexpectedRequestException
    {
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(ctx
          .getConnection());
      final SearchHandler handler = new SearchHandler(messageID, ctx
          .getConnection());
      conn.search(messageID, request, handler, handler, handler);
      final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR.get(
          ctx.getConnection()).getServerConnection();
      final SearchHandler handler = new SearchHandler(messageID,
          ctx.getConnection());
      conn.handleSearch(messageID, request, handler, handler, handler);
    }
@@ -764,7 +1088,7 @@
    public void unbindRequest(final FilterChainContext ctx,
        final int messageID, final UnbindRequest request)
    {
      closeConnection(ctx.getConnection(), messageID, request);
      notifyConnectionClosed(ctx.getConnection(), messageID, request);
    }
@@ -774,13 +1098,14 @@
        final int messageID, final byte messageTag,
        final ByteString messageBytes)
    {
      closeConnection(ctx.getConnection(), new UnsupportedMessageException(
          messageID, messageTag, messageBytes));
      notifyConnectionException(ctx.getConnection(),
          new UnsupportedMessageException(messageID, messageTag, messageBytes));
    }
  };
  private final int maxASN1ElementSize;
  private final LDAPReader ldapReader;
  private final LDAPListenerImpl listener;
@@ -799,7 +1124,7 @@
  public void exceptionOccurred(final FilterChainContext ctx,
      final Throwable error)
  {
    closeConnection(ctx.getConnection(), error);
    notifyConnectionException(ctx.getConnection(), error);
  }
@@ -810,12 +1135,13 @@
  {
    final Connection<?> connection = ctx.getConnection();
    connection.configureBlocking(true);
    ServerConnection<Integer> serverConn;
    try
    {
      serverConn = listener.getConnectionFactory().accept(
          new ClientContextImpl(connection));
      LDAP_CONNECTION_ATTR.set(connection, serverConn);
      final ClientContextImpl clientContext = new ClientContextImpl(connection);
      final ServerConnection<Integer> serverConn = listener
          .getConnectionFactory().accept(clientContext);
      clientContext.setServerConnection(serverConn);
      LDAP_CONNECTION_ATTR.set(connection, clientContext);
    }
    catch (final ErrorResultException e)
    {
@@ -831,7 +1157,7 @@
  public NextAction handleClose(final FilterChainContext ctx)
      throws IOException
  {
    closeConnection(ctx.getConnection(), -1, null);
    notifyConnectionClosed(ctx.getConnection(), -1, null);
    return ctx.getStopAction();
  }
@@ -867,48 +1193,6 @@
  private void closeConnection(final Connection<?> connection,
      final int messageID, final UnbindRequest unbindRequest)
  {
    final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR
        .remove(connection);
    if (conn != null)
    {
      conn.closed(messageID, unbindRequest);
      try
      {
        connection.close();
      }
      catch (final IOException e)
      {
        StaticUtils.DEBUG_LOG.warning("Error closing connection: " + e);
      }
    }
  }
  private void closeConnection(final Connection<?> connection,
      final Throwable error)
  {
    final ServerConnection<Integer> conn = LDAP_CONNECTION_ATTR
        .remove(connection);
    if (conn != null)
    {
      conn.closed(error);
      try
      {
        connection.close();
      }
      catch (final IOException e)
      {
        StaticUtils.DEBUG_LOG.warning("Error closing connection: " + e);
      }
    }
  }
  private synchronized void installFilter(final Connection<?> connection,
      final com.sun.grizzly.filterchain.Filter filter)
  {
opendj-sdk/sdk/src/com/sun/opends/sdk/messages/messages.properties
@@ -5834,3 +5834,15 @@
 contained the OID '%s', when '%s' was expected
SEVERE_ERR_VIRTUAL_ATTRS_ONLY_INVALID_CONTROL_VALUE=Cannot decode the provided \
 virtual attributes only control because it contains a value
WARN_CLIENT_DUPLICATE_MESSAGE_ID=The Directory Server is already processing \
 another request on the same client connection with the same message ID of %d
INFO_CANCELED_BY_ABANDON_REQUEST=The operation was canceled because the client \
 issued an abandon request (message ID %d) for this operation
INFO_CANCELED_BY_CANCEL_REQUEST=The operation was canceled because the client \
 issued a cancel request (message ID %d) for this operation
INFO_CANCELED_BY_CLIENT_DISCONNECT=The operation was canceled because the \
 client disconnected
INFO_CANCELED_BY_CLIENT_ERROR=The operation was canceled because the \
 client connection failed
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ArgumentParser.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 *      Copyright 2006-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.tools;
@@ -327,7 +327,8 @@
    if (versionArgument != null)
    {
      if (shortID == versionArgument.getShortIdentifier())
      if (shortID != null &&
          shortID.equals(versionArgument.getShortIdentifier()))
      {
        // Update the version argument to not display its short
        // identifier.
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ArgumentParserConnectionFactory.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.tools;
@@ -332,7 +332,7 @@
   */
  @Override
  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
      final ResultHandler<AsynchronousConnection> handler)
      final ResultHandler<? super AsynchronousConnection> handler)
  {
    return connFactory.getAsynchronousConnection(handler);
  }
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/AuthenticatedConnectionFactory.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.tools;
@@ -103,7 +103,7 @@
    public FutureResult<Result> add(final AddRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -113,7 +113,7 @@
    public FutureResult<Result> add(final AddRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -197,7 +197,7 @@
    public FutureResult<Result> delete(final DeleteRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -207,7 +207,7 @@
    public FutureResult<Result> delete(final DeleteRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -283,7 +283,7 @@
    public FutureResult<Result> modify(final ModifyRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -293,7 +293,7 @@
    public FutureResult<Result> modify(final ModifyRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -305,7 +305,7 @@
    public FutureResult<Result> modifyDN(final ModifyDNRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -315,7 +315,7 @@
    public FutureResult<Result> modifyDN(final ModifyDNRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -344,7 +344,7 @@
     * {@inheritDoc}
     */
    public FutureResult<RootDSE> readRootDSE(
        final ResultHandler<RootDSE> handler)
        final ResultHandler<? super RootDSE> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
      return connection.readRootDSE(handler);
@@ -356,7 +356,7 @@
     * {@inheritDoc}
     */
    public FutureResult<Schema> readSchema(final DN name,
        final ResultHandler<Schema> handler)
        final ResultHandler<? super Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
      return connection.readSchema(name, handler);
@@ -368,7 +368,7 @@
     * {@inheritDoc}
     */
    public FutureResult<Schema> readSchemaForEntry(final DN name,
        final ResultHandler<Schema> handler)
        final ResultHandler<? super Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
      return connection.readSchemaForEntry(name, handler);
@@ -448,24 +448,22 @@
    public FutureResult<Result> search(final SearchRequest request,
        final ResultHandler<Result> resultHandler,
        final SearchResultHandler searchResulthandler)
        final SearchResultHandler handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      return connection.search(request, resultHandler, searchResulthandler);
      return connection.search(request, handler);
    }
    public FutureResult<Result> search(final SearchRequest request,
        final ResultHandler<Result> resultHandler,
        final SearchResultHandler searchResulthandler,
        final SearchResultHandler resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      return connection.search(request, resultHandler, searchResulthandler,
      return connection.search(request, resultHandler,
          intermediateResponseHandler);
    }
@@ -592,7 +590,7 @@
    private FutureResultImpl(final BindRequest request,
        final ResultHandler<AsynchronousConnection> handler)
        final ResultHandler<? super AsynchronousConnection> handler)
    {
      this.bindRequest = request;
      this.futureBindResult = new FutureResultTransformer<BindResult, AsynchronousConnection>(
@@ -684,7 +682,7 @@
  @Override
  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
      final ResultHandler<AsynchronousConnection> handler)
      final ResultHandler<? super AsynchronousConnection> handler)
  {
    final FutureResultImpl future = new FutureResultImpl(request, handler);
    future.futureConnectionResult.setFutureResult(parentFactory
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/DataSource.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.tools;
@@ -65,10 +65,17 @@
    {
      lines = new ArrayList<String>();
      final BufferedReader in = new BufferedReader(new FileReader(file));
      String line;
      while ((line = in.readLine()) != null)
      try
      {
        lines.add(line);
        String line;
        while ((line = in.readLine()) != null)
        {
          lines.add(line);
        }
      }
      finally
      {
        in.close();
      }
    }
@@ -151,10 +158,17 @@
      lines = new ArrayList<String>();
      random = new Random(seed);
      final BufferedReader in = new BufferedReader(new FileReader(file));
      String line;
      while ((line = in.readLine()) != null)
      try
      {
        lines.add(line);
        String line;
        while ((line = in.readLine()) != null)
        {
          lines.add(line);
        }
      }
      finally
      {
        in.close();
      }
    }
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/LDAPSearch.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.tools;
@@ -180,6 +180,26 @@
      println(LocalizableMessage.raw(reference.toString()));
      return true;
    }
    /**
     * {@inheritDoc}
     */
    public void handleErrorResult(ErrorResultException error)
    {
      // Ignore.
    }
    /**
     * {@inheritDoc}
     */
    public void handleResult(Result result)
    {
      // Ignore.
    }
  }
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/ModRate.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.tools;
@@ -334,6 +334,10 @@
    try
    {
      if(System.getProperty("org.opends.sdk.ldap.transport.linger") == null)
      {
        System.setProperty("org.opends.sdk.ldap.transport.linger", "0");
      }
      connectionFactory = new ArgumentParserConnectionFactory(argParser, this);
      runner = new ModifyPerformanceRunner(argParser, this);
      propertiesFileArgument = new StringArgument("propertiesFilePath", null,
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/PerformanceRunner.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.tools;
@@ -214,8 +214,8 @@
        if (successCount > 0)
        {
          strings[2] = String.format("%.3f",
              (waitTime - (gcDuration - lastGCDuration)) / successCount
                  / 1000000.0);
              (waitTime - (gcDuration - lastGCDuration))
                  / (double) successCount / 1000000.0);
        }
        else
        {
@@ -224,7 +224,7 @@
        if (totalSuccessCount > 0)
        {
          strings[3] = String.format("%.3f", (totalWaitTime - gcDuration)
              / totalSuccessCount / 1000000.0);
              / (double) totalSuccessCount / 1000000.0);
        }
        else
        {
@@ -438,7 +438,8 @@
      R handler;
      final double targetTimeInMS =
        (1.0 / (targetThroughput / (numThreads * numConnections))) * 1000.0;
        (1.0 / (targetThroughput /
            (double) (numThreads * numConnections))) * 1000.0;
      double sleepTimeInMS = 0;
      long start;
      while (!stopRequested && !(maxIterations > 0 && count >= maxIterations))
@@ -706,7 +707,7 @@
      int parent;
      while (child > start)
      {
        parent = (int) Math.floor((child - 1) / 2);
        parent = (int) Math.floor((child - 1) / 2.0);
        if (get(parent) > get(child))
        {
          swap(parent, child);
@@ -865,14 +866,14 @@
  public void connectionClosed()
  public void handleConnectionClosed()
  {
    // Ignore
  }
  public synchronized void connectionErrorOccurred(
  public synchronized void handleConnectionError(
      final boolean isDisconnectNotification, final ErrorResultException error)
  {
    if (!stopRequested)
@@ -889,7 +890,7 @@
  public void connectionReceivedUnsolicitedNotification(
  public void handleUnsolicitedNotification(
      final ExtendedResult notification)
  {
    // Ignore
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/PromptingTrustManager.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.tools;
@@ -161,7 +161,14 @@
    else
    {
      final FileInputStream fos = new FileInputStream(onDiskTrustStorePath);
      onDiskTrustStore.load(fos, DEFAULT_PASSWORD);
      try
      {
        onDiskTrustStore.load(fos, DEFAULT_PASSWORD);
      }
      finally
      {
        fos.close();
      }
    }
    final TrustManagerFactory tmf = TrustManagerFactory
        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
opendj-sdk/sdk/src/com/sun/opends/sdk/tools/SearchRate.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.tools;
@@ -169,7 +169,7 @@
          sr.setFilter(String.format(filter, data));
          sr.setName(String.format(baseDN, data));
        }
        return connection.search(sr, handler, handler);
        return connection.search(sr, handler);
      }
    }
@@ -393,6 +393,10 @@
    try
    {
      if(System.getProperty("org.opends.sdk.ldap.transport.linger") == null)
      {
        System.setProperty("org.opends.sdk.ldap.transport.linger", "0");
      }
      connectionFactory = new ArgumentParserConnectionFactory(argParser, this);
      runner = new SearchPerformanceRunner(argParser, this);
opendj-sdk/sdk/src/com/sun/opends/sdk/util/AbstractFutureResult.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package com.sun.opends.sdk.util;
@@ -125,7 +125,7 @@
    boolean innerCancel(final boolean mayInterruptIfRunning)
    {
      if (!setStatePending())
      if (!isCancelable() || !setStatePending())
      {
        return false;
      }
@@ -410,6 +410,20 @@
  /**
   * Indicates whether this future result can be canceled.
   *
   * @return {@code true} if this future result is cancelable or {@code false}
   *         otherwise.
   */
  protected boolean isCancelable()
  {
    // Return true by default.
    return true;
  }
  /**
   * Appends a string representation of this future's state to the provided
   * builder.
   *
opendj-sdk/sdk/src/org/opends/sdk/AVA.java
@@ -164,7 +164,7 @@
      return;
    }
    if ((length % 2) == 1)
    if ((length % 2) != 0)
    {
      final LocalizableMessage message = ERR_HEX_DECODE_INVALID_LENGTH
          .get(hexBuffer);
opendj-sdk/sdk/src/org/opends/sdk/AbstractAsynchronousConnection.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
@@ -53,8 +53,7 @@
{
  private static final class SingleEntryFuture implements
      FutureResult<SearchResultEntry>, ResultHandler<Result>,
      SearchResultHandler
      FutureResult<SearchResultEntry>, SearchResultHandler
  {
    private final ResultHandler<? super SearchResultEntry> handler;
@@ -231,7 +230,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> add(final AddRequest request,
      final ResultHandler<Result> handler)
      final ResultHandler<? super Result> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
@@ -280,7 +279,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> delete(final DeleteRequest request,
      final ResultHandler<Result> handler)
      final ResultHandler<? super Result> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
@@ -316,7 +315,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> modify(final ModifyRequest request,
      final ResultHandler<Result> handler)
      final ResultHandler<? super Result> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
@@ -329,7 +328,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> modifyDN(final ModifyDNRequest request,
      final ResultHandler<Result> handler)
      final ResultHandler<? super Result> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
@@ -358,7 +357,8 @@
  /**
   * {@inheritDoc}
   */
  public FutureResult<RootDSE> readRootDSE(final ResultHandler<RootDSE> handler)
  public FutureResult<RootDSE> readRootDSE(
      final ResultHandler<? super RootDSE> handler)
      throws UnsupportedOperationException, IllegalStateException
  {
    return RootDSE.readRootDSE(this, handler);
@@ -370,7 +370,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Schema> readSchema(final DN name,
      final ResultHandler<Schema> handler)
      final ResultHandler<? super Schema> handler)
      throws UnsupportedOperationException, IllegalStateException
  {
    return Schema.readSchema(this, name, handler);
@@ -382,7 +382,7 @@
   * {@inheritDoc}
   */
  public FutureResult<Schema> readSchemaForEntry(final DN name,
      final ResultHandler<Schema> handler)
      final ResultHandler<? super Schema> handler)
      throws UnsupportedOperationException, IllegalStateException
  {
    return Schema.readSchema(this, name, handler);
@@ -394,12 +394,11 @@
   * {@inheritDoc}
   */
  public FutureResult<Result> search(final SearchRequest request,
      final ResultHandler<Result> resultHandler,
      final SearchResultHandler searchResulthandler)
      final SearchResultHandler handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    return search(request, resultHandler, searchResulthandler, null);
    return search(request, handler, null);
  }
@@ -414,8 +413,7 @@
      NullPointerException
  {
    final SingleEntryFuture innerFuture = new SingleEntryFuture(handler);
    final FutureResult<Result> future = search(request, innerFuture,
        innerFuture);
    final FutureResult<Result> future = search(request, innerFuture);
    innerFuture.setResultFuture(future);
    return innerFuture;
  }
opendj-sdk/sdk/src/org/opends/sdk/AbstractConnection.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
@@ -34,9 +34,10 @@
import static com.sun.opends.sdk.messages.Messages.ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.opends.sdk.ldif.ConnectionEntryReader;
import org.opends.sdk.requests.Requests;
import org.opends.sdk.requests.SearchRequest;
import org.opends.sdk.responses.*;
@@ -84,6 +85,26 @@
      return true;
    }
    /**
     * {@inheritDoc}
     */
    public void handleErrorResult(ErrorResultException error)
    {
      // Ignore.
    }
    /**
     * {@inheritDoc}
     */
    public void handleResult(Result result)
    {
      // Ignore.
    }
  }
@@ -353,6 +374,26 @@
        }
        return true;
      }
      /**
       * {@inheritDoc}
       */
      public void handleErrorResult(ErrorResultException error)
      {
        // Ignore.
      }
      /**
       * {@inheritDoc}
       */
      public void handleResult(Result result)
      {
        // Ignore.
      }
    };
    return search(request, handler);
@@ -363,18 +404,16 @@
  /**
   * {@inheritDoc}
   */
  public List<SearchResultEntry> search(final String baseObject,
  public ConnectionEntryReader search(final String baseObject,
      final SearchScope scope, final String filter,
      final String... attributeDescriptions) throws ErrorResultException,
      InterruptedException, LocalizedIllegalArgumentException,
      UnsupportedOperationException, IllegalStateException,
      final String... attributeDescriptions)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    final List<SearchResultEntry> entries = new LinkedList<SearchResultEntry>();
    final BlockingQueue<Response> entries = new LinkedBlockingQueue<Response>();
    final SearchRequest request = Requests.newSearchRequest(baseObject, scope,
        filter, attributeDescriptions);
    search(request, entries);
    return entries;
    return search(request, entries);
  }
opendj-sdk/sdk/src/org/opends/sdk/AbstractConnectionFactory.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
@@ -50,7 +50,7 @@
   * {@inheritDoc}
   */
  public abstract FutureResult<AsynchronousConnection> getAsynchronousConnection(
      ResultHandler<AsynchronousConnection> handler);
      ResultHandler<? super AsynchronousConnection> handler);
opendj-sdk/sdk/src/org/opends/sdk/AsynchronousConnection.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
@@ -120,10 +120,10 @@
   * Abandons the unfinished operation identified in the provided abandon
   * request.
   * <p>
   * Since abandon requests do not have a response, invoking the method {@code
   * get()} on the returned future will not block, nor return anything (it is
   * {@code Void}), but may throw an exception if a problem occurred while
   * sending the abandon request.
   * Since abandon requests do not have a response, invoking the method
   * {@code get()} on the returned future will not block, nor return anything
   * (it is {@code Void}), but may throw an exception if a problem occurred
   * while sending the abandon request.
   * <p>
   * <b>Note:</b> a more convenient approach to abandoning unfinished operations
   * is provided via the {@link FutureResult#cancel(boolean)} method.
@@ -134,8 +134,8 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support abandon operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
@@ -158,12 +158,13 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support add operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  FutureResult<Result> add(AddRequest request, ResultHandler<Result> handler)
  FutureResult<Result> add(AddRequest request,
      ResultHandler<? super Result> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -184,13 +185,13 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support add operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  FutureResult<Result> add(AddRequest request,
      ResultHandler<Result> resultHandler,
      ResultHandler<? super Result> resultHandler,
      IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -206,8 +207,8 @@
   *          The listener which wants to be notified when events occur on this
   *          connection.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If the {@code listener} was {@code null}.
   */
@@ -229,8 +230,8 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support bind operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
@@ -256,8 +257,8 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support bind operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
@@ -329,8 +330,8 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support compare operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
@@ -357,8 +358,8 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support compare operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
@@ -383,14 +384,15 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support delete operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  FutureResult<Result> delete(DeleteRequest request,
      ResultHandler<Result> handler) throws UnsupportedOperationException,
      IllegalStateException, NullPointerException;
      ResultHandler<? super Result> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -410,13 +412,13 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support delete operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  FutureResult<Result> delete(DeleteRequest request,
      ResultHandler<Result> resultHandler,
      ResultHandler<? super Result> resultHandler,
      IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -438,8 +440,8 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support extended operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
@@ -467,8 +469,8 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support extended operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
@@ -505,9 +507,9 @@
  /**
   * Returns {@code true} if this connection has not been closed and no fatal
   * errors have been detected. This method is guaranteed to return {@code
   * false} only when it is called after the method {@code close} has been
   * called.
   * errors have been detected. This method is guaranteed to return
   * {@code false} only when it is called after the method {@code close} has
   * been called.
   *
   * @return {@code true} if the connection is valid, {@code false} otherwise.
   */
@@ -528,14 +530,15 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support modify operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  FutureResult<Result> modify(ModifyRequest request,
      ResultHandler<Result> handler) throws UnsupportedOperationException,
      IllegalStateException, NullPointerException;
      ResultHandler<? super Result> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -555,13 +558,13 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support modify operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  FutureResult<Result> modify(ModifyRequest request,
      ResultHandler<Result> resultHandler,
      ResultHandler<? super Result> resultHandler,
      IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -581,14 +584,15 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support modify DN operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  FutureResult<Result> modifyDN(ModifyDNRequest request,
      ResultHandler<Result> handler) throws UnsupportedOperationException,
      IllegalStateException, NullPointerException;
      ResultHandler<? super Result> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -608,13 +612,13 @@
   * @throws UnsupportedOperationException
   *           If this connection does not support modify DN operations.
   * @throws IllegalStateException
   *           If this connection has already been closed, i.e. if {@code
   *           isClosed() == true}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  FutureResult<Result> modifyDN(ModifyDNRequest request,
      ResultHandler<Result> resultHandler,
      ResultHandler<? super Result> resultHandler,
      IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -649,8 +653,8 @@
   * @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}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If the {@code name} was {@code null}.
   */
@@ -676,10 +680,10 @@
   * @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}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   */
  FutureResult<RootDSE> readRootDSE(ResultHandler<RootDSE> handler)
  FutureResult<RootDSE> readRootDSE(ResultHandler<? super RootDSE> handler)
      throws UnsupportedOperationException, IllegalStateException;
@@ -703,10 +707,10 @@
   * @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}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   */
  FutureResult<Schema> readSchema(DN name, ResultHandler<Schema> handler)
  FutureResult<Schema> readSchema(DN name, ResultHandler<? super Schema> handler)
      throws UnsupportedOperationException, IllegalStateException;
@@ -734,10 +738,11 @@
   * @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}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   */
  FutureResult<Schema> readSchemaForEntry(DN name, ResultHandler<Schema> handler)
  FutureResult<Schema> readSchemaForEntry(DN name,
      ResultHandler<? super Schema> handler)
      throws UnsupportedOperationException, IllegalStateException;
@@ -765,10 +770,7 @@
   *
   * @param request
   *          The search request.
   * @param resultHandler
   *          A result handler which can be used to asynchronously process the
   *          operation result when it is received, may be {@code null}.
   * @param searchResulthandler
   * @param handler
   *          A search result handler which can be used to asynchronously
   *          process the search result entries and references as they are
   *          received, may be {@code null}.
@@ -776,14 +778,13 @@
   * @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}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  FutureResult<Result> search(SearchRequest request,
      ResultHandler<Result> resultHandler,
      SearchResultHandler searchResulthandler)
      SearchResultHandler handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -795,9 +796,6 @@
   * @param request
   *          The search request.
   * @param resultHandler
   *          A result handler which can be used to asynchronously process the
   *          operation result when it is received, may be {@code null}.
   * @param searchResulthandler
   *          A search result handler which can be used to asynchronously
   *          process the search result entries and references as they are
   *          received, may be {@code null}.
@@ -808,14 +806,13 @@
   * @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}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If {@code request} was {@code null}.
   */
  FutureResult<Result> search(SearchRequest request,
      ResultHandler<Result> resultHandler,
      SearchResultHandler searchResulthandler,
      SearchResultHandler resultHandler,
      IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
@@ -841,8 +838,8 @@
   * @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}.
   *           If this connection has already been closed, i.e. if
   *           {@code isClosed() == true}.
   * @throws NullPointerException
   *           If the {@code request} was {@code null}.
   */
opendj-sdk/sdk/src/org/opends/sdk/AuthenticatedConnectionFactory.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
@@ -85,7 +85,7 @@
    public FutureResult<Result> add(final AddRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -95,7 +95,7 @@
    public FutureResult<Result> add(final AddRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -179,7 +179,7 @@
    public FutureResult<Result> delete(final DeleteRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -189,7 +189,7 @@
    public FutureResult<Result> delete(final DeleteRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -254,7 +254,7 @@
    public FutureResult<Result> modify(final ModifyRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -264,7 +264,7 @@
    public FutureResult<Result> modify(final ModifyRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -276,7 +276,7 @@
    public FutureResult<Result> modifyDN(final ModifyDNRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -286,7 +286,7 @@
    public FutureResult<Result> modifyDN(final ModifyDNRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -315,7 +315,7 @@
     * {@inheritDoc}
     */
    public FutureResult<RootDSE> readRootDSE(
        final ResultHandler<RootDSE> handler)
        final ResultHandler<? super RootDSE> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
      return connection.readRootDSE(handler);
@@ -327,7 +327,7 @@
     * {@inheritDoc}
     */
    public FutureResult<Schema> readSchema(final DN name,
        final ResultHandler<Schema> handler)
        final ResultHandler<? super Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
      return connection.readSchema(name, handler);
@@ -339,7 +339,7 @@
     * {@inheritDoc}
     */
    public FutureResult<Schema> readSchemaForEntry(final DN name,
        final ResultHandler<Schema> handler)
        final ResultHandler<? super Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
      return connection.readSchemaForEntry(name, handler);
@@ -356,24 +356,22 @@
    public FutureResult<Result> search(final SearchRequest request,
        final ResultHandler<Result> resultHandler,
        final SearchResultHandler searchResulthandler)
        final SearchResultHandler handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      return connection.search(request, resultHandler, searchResulthandler);
      return connection.search(request, handler);
    }
    public FutureResult<Result> search(final SearchRequest request,
        final ResultHandler<Result> resultHandler,
        final SearchResultHandler searchResulthandler,
        final SearchResultHandler resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      return connection.search(request, resultHandler, searchResulthandler,
      return connection.search(request, resultHandler,
          intermediateResponseHandler);
    }
@@ -496,7 +494,7 @@
   */
  @Override
  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
      final ResultHandler<AsynchronousConnection> handler)
      final ResultHandler<? super AsynchronousConnection> handler)
  {
    final FutureResultImpl future = new FutureResultImpl(request, handler);
    future.futureConnectionResult.setFutureResult(parentFactory
opendj-sdk/sdk/src/org/opends/sdk/Connection.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
@@ -31,8 +31,9 @@
import java.io.Closeable;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import org.opends.sdk.ldif.ConnectionEntryReader;
import org.opends.sdk.requests.*;
import org.opends.sdk.responses.*;
import org.opends.sdk.schema.Schema;
@@ -1102,21 +1103,19 @@
  /**
   * Searches the Directory Server using the provided search parameters. Any
   * matching entries returned by the search will be added to a {@code List}
   * which is returned if the search succeeds. Search result references will be
   * discarded.
   * matching entries returned by the search will be exposed through the
   * {@code EntryReader} interface.
   * <p>
   * <b>Warning:</b> Usage of this method is discouraged if the search request
   * is expected to yield a large number of search results since the entire set
   * of results will be stored in memory, potentially causing an {@code
   * OutOfMemoryError}.
   * <b>Warning:</b> When using a queue with an optional capacity bound,
   * the connection will stop reading responses and wait if necessary for
   * space to become available.
   * <p>
   * This method is equivalent to the following code:
   *
   * <pre>
   * SearchRequest request = new SearchRequest(baseDN, scope, filter,
   *     attributeDescriptions);
   * connection.search(request, new LinkedList&lt;SearchResultEntry&gt;());
   * connection.search(request, new LinkedBlockingQueue&lt;Response&gt;());
   * </pre>
   *
   * @param baseObject
@@ -1129,16 +1128,7 @@
   *          order for an entry to be returned.
   * @param attributeDescriptions
   *          The names of the attributes to be included with each entry.
   * @return A list containing any matching entries returned by the search.
   * @throws ErrorResultException
   *           If the result code indicates that the request failed for some
   *           reason.
   * @throws InterruptedException
   *           If the current thread was interrupted while waiting.
   * @throws LocalizedIllegalArgumentException
   *           If {@code baseObject} could not be decoded using the default
   *           schema or if {@code filter} is not a valid LDAP string
   *           representation of a filter.
   * @return An entry reader exposing the returned entries.
   * @throws UnsupportedOperationException
   *           If this connection does not support search operations.
   * @throws IllegalStateException
@@ -1148,13 +1138,39 @@
   *           If the {@code baseObject}, {@code scope}, or {@code filter} were
   *           {@code null}.
   */
  List<SearchResultEntry> search(String baseObject, SearchScope scope,
  ConnectionEntryReader search(String baseObject, SearchScope scope,
      String filter, String... attributeDescriptions)
      throws ErrorResultException, InterruptedException,
      LocalizedIllegalArgumentException, UnsupportedOperationException,
      throws UnsupportedOperationException,
      IllegalStateException, NullPointerException;
  /**
   * Searches the Directory Server using the provided search parameters. Any
   * matching entries returned by the search will be exposed through the
   * {@code EntryReader} interface.
   * <p>
   * <b>Warning:</b> When using a queue with an optional capacity bound,
   * the connection will stop reading responses and wait if necessary for
   * space to become available.
   *
   * @param request
   *          The search request.
   * @param entries
   *          The queue to which matching entries should be added.
   * @return 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 {@code request} or {@code entries} was {@code null}.
   */
  ConnectionEntryReader search(SearchRequest request,
                               BlockingQueue<Response> entries)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException;
  /**
   * Searches the Directory Server for a single entry using the provided search
opendj-sdk/sdk/src/org/opends/sdk/ConnectionEventListener.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
@@ -39,16 +39,6 @@
 * An object that registers to be notified when a connection is closed by the
 * application, receives an unsolicited notification, or experiences a fatal
 * error.
 * <p>
 * TODO: isolate fatal connection errors as a sub-type of ErrorResultException.
 * <p>
 * TODO: do we need client initiated close notification as in JCA / JDBC? A
 * simpler approach would be for the connection pool to wrap the underlying
 * physical connection with its own. It can then intercept the close request
 * from the client. This has the disadvantage in that we lose any specialized
 * methods exposed by the underlying physical connection (i.e. if the physical
 * connection extends Connection and provides additional methods) since the
 * connection pool effectively hides them via its wrapper.
 */
public interface ConnectionEventListener extends EventListener
{
@@ -58,7 +48,7 @@
   * notified immediately after the application calls the {@code close} method
   * on the associated connection.
   */
  void connectionClosed();
  void handleConnectionClosed();
@@ -69,10 +59,10 @@
   * the provided {@link ErrorResultException} to the application.
   * <p>
   * <b>Note:</b> disconnect notifications are treated as fatal connection
   * errors and are handled by this method. In this case {@code
   * isDisconnectNotification} will be {@code true} and {@code error} will
   * contain the result code and any diagnostic information contained in the
   * notification message.
   * errors and are handled by this method. In this case
   * {@code isDisconnectNotification} will be {@code true} and {@code error}
   * will contain the result code and any diagnostic information contained in
   * the notification message.
   *
   * @param isDisconnectNotification
   *          {@code true} if the error was triggered by a disconnect
@@ -80,7 +70,7 @@
   * @param error
   *          The exception that is about to be thrown to the application.
   */
  void connectionErrorOccurred(boolean isDisconnectNotification,
  void handleConnectionError(boolean isDisconnectNotification,
      ErrorResultException error);
@@ -90,10 +80,10 @@
   * received the provided unsolicited notification from the server.
   * <p>
   * <b>Note:</b> disconnect notifications are treated as fatal connection
   * errors and are handled by the {@link #connectionErrorOccurred} method.
   * errors and are handled by the {@link #handleConnectionError} method.
   *
   * @param notification
   *          The unsolicited notification
   *          The unsolicited notification.
   */
  void connectionReceivedUnsolicitedNotification(ExtendedResult notification);
  void handleUnsolicitedNotification(ExtendedResult notification);
}
opendj-sdk/sdk/src/org/opends/sdk/ConnectionFactory.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
@@ -66,7 +66,7 @@
   * @return A future which can be used to retrieve the asynchronous connection.
   */
  FutureResult<AsynchronousConnection> getAsynchronousConnection(
      ResultHandler<AsynchronousConnection> handler);
      ResultHandler<? super AsynchronousConnection> handler);
opendj-sdk/sdk/src/org/opends/sdk/ConnectionPool.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
@@ -104,7 +104,7 @@
    public FutureResult<Result> add(final AddRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -118,7 +118,7 @@
    public FutureResult<Result> add(final AddRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -254,14 +254,14 @@
    public void connectionClosed()
    public void handleConnectionClosed()
    {
      // Ignore - we intercept close via the close method.
    }
    public void connectionErrorOccurred(final boolean isDisconnectNotification,
    public void handleConnectionError(final boolean isDisconnectNotification,
        final ErrorResultException error)
    {
      // Remove this connection from the pool if its in there. If not,
@@ -289,7 +289,7 @@
    public void connectionReceivedUnsolicitedNotification(
    public void handleUnsolicitedNotification(
        final ExtendedResult notification)
    {
      // Ignore
@@ -298,7 +298,7 @@
    public FutureResult<Result> delete(final DeleteRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -312,7 +312,7 @@
    public FutureResult<Result> delete(final DeleteRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -386,7 +386,7 @@
    public FutureResult<Result> modify(final ModifyRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -400,7 +400,7 @@
    public FutureResult<Result> modify(final ModifyRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -416,7 +416,7 @@
    public FutureResult<Result> modifyDN(final ModifyDNRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -430,7 +430,7 @@
    public FutureResult<Result> modifyDN(final ModifyDNRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -467,7 +467,7 @@
     * {@inheritDoc}
     */
    public FutureResult<RootDSE> readRootDSE(
        final ResultHandler<RootDSE> handler)
        final ResultHandler<? super RootDSE> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
      if (isClosed())
@@ -483,7 +483,7 @@
     * {@inheritDoc}
     */
    public FutureResult<Schema> readSchema(final DN name,
        final ResultHandler<Schema> handler)
        final ResultHandler<? super Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
      if (isClosed())
@@ -499,7 +499,7 @@
     * {@inheritDoc}
     */
    public FutureResult<Schema> readSchemaForEntry(final DN name,
        final ResultHandler<Schema> handler)
        final ResultHandler<? super Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
      if (isClosed())
@@ -523,8 +523,7 @@
    public FutureResult<Result> search(final SearchRequest request,
        final ResultHandler<Result> resultHandler,
        final SearchResultHandler searchResulthandler)
        final SearchResultHandler handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -532,14 +531,13 @@
      {
        throw new IllegalStateException();
      }
      return connection.search(request, resultHandler, searchResulthandler);
      return connection.search(request, handler);
    }
    public FutureResult<Result> search(final SearchRequest request,
        final ResultHandler<Result> resultHandler,
        final SearchResultHandler searchResulthandler,
        final SearchResultHandler resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -548,7 +546,7 @@
      {
        throw new IllegalStateException();
      }
      return connection.search(request, resultHandler, searchResulthandler,
      return connection.search(request, resultHandler,
          intermediateResponseHandler);
    }
@@ -654,7 +652,7 @@
  @Override
  public synchronized FutureResult<AsynchronousConnection> getAsynchronousConnection(
      final ResultHandler<AsynchronousConnection> handler)
      final ResultHandler<? super AsynchronousConnection> handler)
  {
    // This entire method is synchronized to ensure new connects are
    // done synchronously to avoid the "pending connect" case.
opendj-sdk/sdk/src/org/opends/sdk/FailoverLoadBalancingAlgorithm.java
@@ -78,7 +78,7 @@
    @Override
    public FutureResult<AsynchronousConnection> getAsynchronousConnection(
        final ResultHandler<AsynchronousConnection> resultHandler)
        final ResultHandler<? super AsynchronousConnection> resultHandler)
    {
      final ResultHandler<AsynchronousConnection> handler =
        new ResultHandler<AsynchronousConnection>()
opendj-sdk/sdk/src/org/opends/sdk/HeartBeatConnectionFactory.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
@@ -53,7 +53,7 @@
   * operations.
   */
  private final class AsynchronousConnectionImpl implements
      AsynchronousConnection, ConnectionEventListener, ResultHandler<Result>
      AsynchronousConnection, ConnectionEventListener, SearchResultHandler
  {
    private final AsynchronousConnection connection;
@@ -80,7 +80,7 @@
    public FutureResult<Result> add(final AddRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -90,7 +90,7 @@
    public FutureResult<Result> add(final AddRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -179,14 +179,14 @@
    public void connectionClosed()
    public void handleConnectionClosed()
    {
      // Ignore - we intercept close through the close method.
    }
    public void connectionErrorOccurred(final boolean isDisconnectNotification,
    public void handleConnectionError(final boolean isDisconnectNotification,
        final ErrorResultException error)
    {
      synchronized (activeConnections)
@@ -198,7 +198,7 @@
    public void connectionReceivedUnsolicitedNotification(
    public void handleUnsolicitedNotification(
        final ExtendedResult notification)
    {
      // Do nothing
@@ -207,7 +207,7 @@
    public FutureResult<Result> delete(final DeleteRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -217,7 +217,7 @@
    public FutureResult<Result> delete(final DeleteRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -261,6 +261,17 @@
    /**
     * {@inheritDoc}
     */
    public boolean handleEntry(SearchResultEntry entry)
    {
      // Ignore.
      return true;
    }
    public void handleErrorResult(final ErrorResultException error)
    {
      connection.close(Requests.newUnbindRequest(), "Heartbeat retured error: "
@@ -269,6 +280,17 @@
    /**
     * {@inheritDoc}
     */
    public boolean handleReference(SearchResultReference reference)
    {
      // Ignore.
      return true;
    }
    public void handleResult(final Result result)
    {
      lastSuccessfulPing = System.currentTimeMillis();
@@ -299,7 +321,7 @@
    public FutureResult<Result> modify(final ModifyRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -309,7 +331,7 @@
    public FutureResult<Result> modify(final ModifyRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -321,7 +343,7 @@
    public FutureResult<Result> modifyDN(final ModifyDNRequest request,
        final ResultHandler<Result> handler)
        final ResultHandler<? super Result> handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
@@ -331,7 +353,7 @@
    public FutureResult<Result> modifyDN(final ModifyDNRequest request,
        final ResultHandler<Result> resultHandler,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
@@ -360,7 +382,7 @@
     * {@inheritDoc}
     */
    public FutureResult<RootDSE> readRootDSE(
        final ResultHandler<RootDSE> handler)
        final ResultHandler<? super RootDSE> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
      return connection.readRootDSE(handler);
@@ -372,7 +394,7 @@
     * {@inheritDoc}
     */
    public FutureResult<Schema> readSchema(final DN name,
        final ResultHandler<Schema> handler)
        final ResultHandler<? super Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
      return connection.readSchema(name, handler);
@@ -384,7 +406,7 @@
     * {@inheritDoc}
     */
    public FutureResult<Schema> readSchemaForEntry(final DN name,
        final ResultHandler<Schema> handler)
        final ResultHandler<? super Schema> handler)
        throws UnsupportedOperationException, IllegalStateException
    {
      return connection.readSchemaForEntry(name, handler);
@@ -401,24 +423,22 @@
    public FutureResult<Result> search(final SearchRequest request,
        final ResultHandler<Result> resultHandler,
        final SearchResultHandler searchResultHandler)
        final SearchResultHandler handler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      return connection.search(request, resultHandler, searchResultHandler);
      return connection.search(request, handler);
    }
    public FutureResult<Result> search(final SearchRequest request,
        final ResultHandler<Result> resultHandler,
        final SearchResultHandler searchResulthandler,
        final SearchResultHandler resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException, IllegalStateException,
        NullPointerException
    {
      return connection.search(request, resultHandler, searchResulthandler,
      return connection.search(request, resultHandler,
          intermediateResponseHandler);
    }
@@ -590,7 +610,7 @@
  @Override
  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
      final ResultHandler<AsynchronousConnection> handler)
      final ResultHandler<? super AsynchronousConnection> handler)
  {
    final FutureResultImpl future = new FutureResultImpl(handler);
    future.setFutureResult(parentFactory.getAsynchronousConnection(future));
opendj-sdk/sdk/src/org/opends/sdk/InternalConnectionFactory.java
@@ -61,7 +61,7 @@
  @Override
  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
      final ResultHandler<AsynchronousConnection> handler)
      final ResultHandler<? super AsynchronousConnection> handler)
  {
    final ServerConnection<Integer> serverConnection;
    try
opendj-sdk/sdk/src/org/opends/sdk/LDAPClientContext.java
@@ -46,13 +46,45 @@
public interface LDAPClientContext
{
  /**
   * Disconnects the client and optionally sends a disconnect notification.
   * Registers the provided connection event listener so that it will be
   * notified when the underlying connection is closed by the client, receives
   * an unsolicited notification, or experiences a fatal error.
   * <p>
   * This method provides a event notification mechanism which can be used by
   * asynchronous request handler implementations to detect connection
   * termination.
   *
   * @param sendNotification
   *          {@code true} to send a disconnect notification, or {@code false}
   *          otherwise.
   * @param listener
   *          The listener which wants to be notified when events occur on the
   *          underlying connection.
   * @throws NullPointerException
   *           If the {@code listener} was {@code null}.
   * @see #isClosed
   */
  void disconnect(boolean sendNotification);
  void addConnectionEventListener(ConnectionEventListener listener)
      throws NullPointerException;
  /**
   * Disconnects the client without sending a disconnect notification.
   */
  void disconnect();
  /**
   * Disconnects the client and sends a disconnect notification, if possible,
   * containing the provided result code and diagnostic message.
   *
   * @param resultCode
   *          The result code which should be included with the disconnect
   *          notification.
   * @param message
   *          The diagnostic message, which may be empty or {@code null}
   *          indicating that none was provided.
   */
  void disconnect(ResultCode resultCode, String message);
@@ -86,6 +118,39 @@
  /**
   * Returns {@code true} if the underlying connection is closed by the client,
   * receives an unsolicited notification, or experiences a fatal error.
   * <p>
   * This method provides a polling mechanism which can be used by synchronous
   * request handler implementations to detect connection termination.
   *
   * @return {@code true} if the underlying connection is closed by the client,
   *         receives an unsolicited notification, or experiences a fatal error,
   *         otherwise {@code false}.
   * @see #addConnectionEventListener
   */
  boolean isClosed();
  /**
   * Removes the provided connection event listener from this client context so
   * that it will no longer be notified when the underlying connection is closed
   * by the application, receives an unsolicited notification, or experiences a
   * fatal error.
   *
   * @param listener
   *          The listener which no longer wants to be notified when events
   *          occur on the underlying connection.
   * @throws NullPointerException
   *           If the {@code listener} was {@code null}.
   */
  void removeConnectionEventListener(ConnectionEventListener listener)
      throws NullPointerException;
  /**
   * Sends an unsolicited notification to the client.
   *
   * @param notification
@@ -112,7 +177,19 @@
   *
   * @param sslContext
   *          The {@code SSLContext} which should be used to secure the
   *          connection.
   * @param protocols
   *          Names of all the protocols to enable or {@code null} to use the
   *          default protocols.
   * @param suites
   *          Names of all the suites to enable or {@code null} to use the
   *          default cipher suites.
   * @param wantClientAuth
   *          Set to {@code true} if client authentication is requested, or
   *          {@code false} if no client authentication is desired.
   * @param needClientAuth
   *          Set to {@code true} if client authentication is required, or
   *          {@code false} if no client authentication is desired.
   */
  void startTLS(SSLContext sslContext);
  void startTLS(SSLContext sslContext, String[] protocols, String[] suites,
      boolean wantClientAuth, boolean needClientAuth);
}
opendj-sdk/sdk/src/org/opends/sdk/LDAPConnectionFactory.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
@@ -134,7 +134,7 @@
   * {@inheritDoc}
   */
  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
      final ResultHandler<AsynchronousConnection> handler)
      final ResultHandler<? super AsynchronousConnection> handler)
  {
    return impl.getAsynchronousConnection(handler);
  }
opendj-sdk/sdk/src/org/opends/sdk/LDAPOptions.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
@@ -50,6 +50,16 @@
  private DecodeOptions decodeOptions;
  /**
   * The list of cipher suite
   */
  private String[] enabledCipherSuites = null;
  /**
   * the list of protocols
   */
  private String[] enabledProtocols = null;
  /**
@@ -80,6 +90,8 @@
    this.timeoutInMillis = options.timeoutInMillis;
    this.useStartTLS = options.useStartTLS;
    this.decodeOptions = new DecodeOptions(options.decodeOptions);
    this.enabledCipherSuites = options.enabledCipherSuites;
    this.enabledProtocols = options.enabledProtocols;
  }
@@ -224,4 +236,66 @@
    return useStartTLS;
  }
  /**
   * Set the protocol versions enabled for secure connections with the
   * Directory Server.
   *
   * The protocols must be supported by the SSLContext specified in
   * {@link #setSSLContext(SSLContext)}. Following a successful call to
   * this method, only the protocols listed in the protocols parameter are
   * enabled for use.
   *
   * @param protocols Names of all the protocols to enable or {@code null} to
   *                  use the default protocols.
   * @return A reference to this LDAP connection options.
   */
  public final LDAPOptions setEnabledProtocols(String[] protocols)
  {
    this.enabledProtocols = protocols;
    return this;
  }
  /**
   * Set the cipher suites enabled for secure connections with the
   * Directory Server.
   *
   * The suites must be supported by the SSLContext specified in
   * {@link #setSSLContext(SSLContext)}. Following a successful call to
   * this method, only the suites listed in the protocols parameter are
   * enabled for use.
   *
   * @param suites Names of all the suites to enable or {@code null} to
   *                  use the default cipher suites.
   * @return A reference to this LDAP connection options.
   */
  public final LDAPOptions setEnabledCipherSuites(String[] suites)
  {
    this.enabledCipherSuites = suites;
    return this;
  }
  /**
   * Returns the names of the protocol versions which are currently enabled
   * for secure connections with the Directory Server.
   *
   * @return an array of protocols or {@code null} if the default protocols
   * are to be used.
   */
  public final String[] getEnabledProtocols()
  {
    return this.enabledProtocols;
  }
  /**
   * Returns the names of the protocol versions which are currently enabled
   * for secure connections with the Directory Server.
   *
   * @return an array of protocols or {@code null} if the default protocols
   * are to be used.
   */
  public final  String[] getEnabledCipherSuites()
  {
    return this.enabledCipherSuites;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/LDAPUrl.java
@@ -463,7 +463,7 @@
    else
    {
      listenPort = port.intValue();
      if (listenPort < 1 && listenPort > Integer.MAX_VALUE)
      if (listenPort < 1 || listenPort > 65535)
      {
        final LocalizableMessage msg = ERR_LDAPURL_BAD_PORT.get(listenPort);
        throw new LocalizedIllegalArgumentException(msg);
opendj-sdk/sdk/src/org/opends/sdk/LoadBalancingConnectionFactory.java
@@ -54,7 +54,7 @@
  @Override
  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
      final ResultHandler<AsynchronousConnection> resultHandler)
      final ResultHandler<? super AsynchronousConnection> resultHandler)
  {
    ConnectionFactory factory;
opendj-sdk/sdk/src/org/opends/sdk/RootDSE.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
@@ -156,7 +156,7 @@
   */
  public static FutureResult<RootDSE> readRootDSE(
      final AsynchronousConnection connection,
      final ResultHandler<RootDSE> handler)
      final ResultHandler<? super RootDSE> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
opendj-sdk/sdk/src/org/opends/sdk/SearchResultHandler.java
@@ -22,13 +22,14 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import org.opends.sdk.responses.Result;
import org.opends.sdk.responses.SearchResultEntry;
import org.opends.sdk.responses.SearchResultReference;
@@ -48,7 +49,7 @@
 * avoid keeping the invoking thread from dispatching to other completion
 * handlers.
 */
public interface SearchResultHandler
public interface SearchResultHandler extends ResultHandler<Result>
{
  /**
   * Invoked each time a search result entry is returned from an asynchronous
opendj-sdk/sdk/src/org/opends/sdk/SearchResultReferenceIOException.java
New file
@@ -0,0 +1,81 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import java.io.IOException;
import org.opends.sdk.responses.SearchResultReference;
import com.sun.opends.sdk.util.Validator;
/**
 * Thrown when an iteration over a set of search results using a
 * {@code ConnectionEntryReader} encounters a {@code SearchResultReference}.
 */
@SuppressWarnings("serial")
public final class SearchResultReferenceIOException extends IOException
{
  private final SearchResultReference reference;
  /**
   * Creates a new referral result IO exception with the provided
   * {@code SearchResultReference}.
   *
   * @param reference
   *          The {@code SearchResultReference} which may be later retrieved by
   *          the {@link #getReference} method.
   * @throws NullPointerException
   *           If {@code reference} was {@code null}.
   */
  public SearchResultReferenceIOException(final SearchResultReference reference)
      throws NullPointerException
  {
    super(Validator.ensureNotNull(reference).toString());
    this.reference = reference;
  }
  /**
   * Returns the {@code SearchResultReference} which was encountered while
   * processing the search results.
   *
   * @return The {@code SearchResultReference} which was encountered while
   *         processing the search results.
   */
  public SearchResultReference getReference()
  {
    return reference;
  }
}
opendj-sdk/sdk/src/org/opends/sdk/ServerConnection.java
@@ -56,7 +56,7 @@
   * @throws UnsupportedOperationException
   *           If this server connection does not handle abandon requests.
   */
  void abandon(C requestContext, AbandonRequest request)
  void handleAbandon(C requestContext, AbandonRequest request)
      throws UnsupportedOperationException;
@@ -77,8 +77,8 @@
   * @throws UnsupportedOperationException
   *           If this server connection does not handle add requests.
   */
  void add(C requestContext, AddRequest request,
      ResultHandler<Result> resultHandler,
  void handleAdd(C requestContext, AddRequest request,
      ResultHandler<? super Result> resultHandler,
      IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException;
@@ -102,7 +102,7 @@
   * @throws UnsupportedOperationException
   *           If this server connection does not handle bind requests.
   */
  void bind(C requestContext, int version, BindRequest request,
  void handleBind(C requestContext, int version, BindRequest request,
      ResultHandler<? super BindResult> resultHandler,
      IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException;
@@ -110,30 +110,6 @@
  /**
   * Invoked when the client closes the connection, possibly using an unbind
   * request.
   *
   * @param requestContext
   *          The request context.
   * @param request
   *          The unbind request, which may be {@code null} if one was not sent
   *          before the connection was closed.
   */
  void closed(C requestContext, UnbindRequest request);
  /**
   * Invoked when an error occurs on the connection and it is no longer usable.
   *
   * @param error
   *          The exception describing the problem that occurred.
   */
  void closed(Throwable error);
  /**
   * Invoked when a compare request is received from a client.
   *
   * @param requestContext
@@ -149,7 +125,7 @@
   * @throws UnsupportedOperationException
   *           If this server connection does not handle compare requests.
   */
  void compare(C requestContext, CompareRequest request,
  void handleCompare(C requestContext, CompareRequest request,
      ResultHandler<? super CompareResult> resultHandler,
      IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException;
@@ -157,6 +133,30 @@
  /**
   * Invoked when the client closes the connection, possibly using an unbind
   * request.
   *
   * @param requestContext
   *          The request context.
   * @param request
   *          The unbind request, which may be {@code null} if one was not sent
   *          before the connection was closed.
   */
  void handleConnectionClosed(C requestContext, UnbindRequest request);
  /**
   * Invoked when an error occurs on the connection and it is no longer usable.
   *
   * @param error
   *          The exception describing the problem that occurred.
   */
  void handleConnectionException(Throwable error);
  /**
   * Invoked when a delete request is received from a client.
   *
   * @param requestContext
@@ -172,8 +172,8 @@
   * @throws UnsupportedOperationException
   *           If this server connection does not handle delete requests.
   */
  void delete(C requestContext, DeleteRequest request,
      ResultHandler<Result> resultHandler,
  void handleDelete(C requestContext, DeleteRequest request,
      ResultHandler<? super Result> resultHandler,
      IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException;
@@ -197,8 +197,8 @@
   * @throws UnsupportedOperationException
   *           If this server connection does not handle extended requests.
   */
  <R extends ExtendedResult> void extendedRequest(C requestContext,
      ExtendedRequest<R> request, ResultHandler<R> resultHandler,
  <R extends ExtendedResult> void handleExtendedRequest(C requestContext,
      ExtendedRequest<R> request, ResultHandler<? super R> resultHandler,
      IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException;
@@ -220,8 +220,8 @@
   * @throws UnsupportedOperationException
   *           If this server connection does not handle modify requests.
   */
  void modify(C requestContext, ModifyRequest request,
      ResultHandler<Result> resultHandler,
  void handleModify(C requestContext, ModifyRequest request,
      ResultHandler<? super Result> resultHandler,
      IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException;
@@ -243,8 +243,8 @@
   * @throws UnsupportedOperationException
   *           If this server connection does not handle modify DN requests.
   */
  void modifyDN(C requestContext, ModifyDNRequest request,
      ResultHandler<Result> resultHandler,
  void handleModifyDN(C requestContext, ModifyDNRequest request,
      ResultHandler<? super Result> resultHandler,
      IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException;
@@ -269,8 +269,8 @@
   * @throws UnsupportedOperationException
   *           If this server connection does not handle search requests.
   */
  void search(C requestContext, SearchRequest request,
      ResultHandler<Result> resultHandler,
  void handleSearch(C requestContext, SearchRequest request,
      ResultHandler<? super Result> resultHandler,
      SearchResultHandler searchResulthandler,
      IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException;
opendj-sdk/sdk/src/org/opends/sdk/SynchronousConnection.java
@@ -22,22 +22,21 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk;
import org.opends.sdk.ldif.ConnectionEntryReader;
import org.opends.sdk.requests.*;
import org.opends.sdk.responses.BindResult;
import org.opends.sdk.responses.CompareResult;
import org.opends.sdk.responses.ExtendedResult;
import org.opends.sdk.responses.Result;
import org.opends.sdk.responses.*;
import org.opends.sdk.schema.Schema;
import com.sun.opends.sdk.util.Validator;
import java.util.concurrent.BlockingQueue;
/**
@@ -350,8 +349,7 @@
      InterruptedException, UnsupportedOperationException,
      IllegalStateException, NullPointerException
  {
    final FutureResult<Result> future = connection.search(request, null,
        handler);
    final FutureResult<Result> future = connection.search(request, handler);
    try
    {
      return future.get();
@@ -363,4 +361,15 @@
    }
  }
  /**
   * {@inheritDoc}
   */
  public ConnectionEntryReader search(final SearchRequest request,
                            BlockingQueue<Response> entries)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
    return new ConnectionEntryReader(getAsynchronousConnection(),
        request, entries);
  }
}
opendj-sdk/sdk/src/org/opends/sdk/controls/EntryChangeNotificationResponseControl.java
@@ -157,16 +157,19 @@
      final Schema schema = options.getSchemaResolver().resolveSchema(
          previousDNString);
      DN previousDN;
      try
      DN previousDN = null;
      if (previousDNString != null)
      {
        previousDN = DN.valueOf(previousDNString, schema);
      }
      catch (final LocalizedIllegalArgumentException e)
      {
        final LocalizableMessage message = ERR_ECN_INVALID_PREVIOUS_DN
            .get(getExceptionMessage(e));
        throw DecodeException.error(message, e);
        try
        {
          previousDN = DN.valueOf(previousDNString, schema);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          final LocalizableMessage message = ERR_ECN_INVALID_PREVIOUS_DN
              .get(getExceptionMessage(e));
          throw DecodeException.error(message, e);
        }
      }
      return new EntryChangeNotificationResponseControl(control.isCritical(),
opendj-sdk/sdk/src/org/opends/sdk/ldif/ConnectionEntryReader.java
New file
@@ -0,0 +1,311 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2010 Sun Microsystems, Inc.
 */
package org.opends.sdk.ldif;
import java.io.InterruptedIOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.opends.sdk.*;
import org.opends.sdk.requests.SearchRequest;
import org.opends.sdk.responses.*;
import com.sun.opends.sdk.util.Validator;
/**
 * A {@code ConnectionEntryReader} is a bridge from
 * {@code AsynchronousConnection}s to {@code EntryReader}s. A connection entry
 * reader allows applications to iterate over search results as they are
 * returned from the server during a search operation.
 * <p>
 * The Search operation is performed synchronously, blocking until a search
 * result entry is received. If a search result indicates that the search
 * operation has failed for some reason then the error result is propagated to
 * the caller using an {@code ErrorResultIOException}. If a search result
 * reference is returned then it is propagated to the caller using a
 * {@code SearchResultReferenceIOException}.
 * <p>
 * The following code illustrates how a {@code ConnectionEntryReader} may be
 * used:
 *
 * <pre>
 * Connection connection = ...;
 * ConnectionEntryReader results = connection.search(
 *     &quot;dc=example,dc=com&quot;,
 *     SearchScope.WHOLE_SUBTREE,
 *     &quot;(objectClass=person)&quot;);
 * SearchResultEntry entry;
 * try
 * {
 *   while ((entry = results.readEntry()) != null)
 *   {
 *     // Process search result entry.
 *   }
 * }
 * catch (Exception e)
 * {
 *   // Handle exceptions
 * }
 * finally
 * {
 *   results.close();
 * }
 * </pre>
 */
public final class ConnectionEntryReader implements EntryReader
{
  /**
   * Result handler that places all responses in a queue.
   */
  private final static class BufferHandler implements SearchResultHandler
  {
    private final BlockingQueue<Response> responses;
    private volatile boolean isInterrupted = false;
    private BufferHandler(final BlockingQueue<Response> responses)
    {
      this.responses = responses;
    }
    @Override
    public boolean handleEntry(final SearchResultEntry entry)
    {
      try
      {
        responses.put(entry);
        return true;
      }
      catch (final InterruptedException e)
      {
        // Prevent the reader from waiting for a result that will never arrive.
        isInterrupted = true;
        Thread.currentThread().interrupt();
        return false;
      }
    }
    @Override
    public void handleErrorResult(final ErrorResultException error)
    {
      try
      {
        responses.put(error.getResult());
      }
      catch (final InterruptedException e)
      {
        // Prevent the reader from waiting for a result that will never arrive.
        isInterrupted = true;
        Thread.currentThread().interrupt();
      }
    }
    @Override
    public boolean handleReference(final SearchResultReference reference)
    {
      try
      {
        responses.put(reference);
        return true;
      }
      catch (final InterruptedException e)
      {
        // Prevent the reader from waiting for a result that will never arrive.
        isInterrupted = true;
        Thread.currentThread().interrupt();
        return false;
      }
    }
    @Override
    public void handleResult(final Result result)
    {
      try
      {
        responses.put(result);
      }
      catch (final InterruptedException e)
      {
        // Prevent the reader from waiting for a result that will never arrive.
        isInterrupted = true;
        Thread.currentThread().interrupt();
      }
    }
  }
  private final BufferHandler buffer;
  private final FutureResult<Result> future;
  /**
   * Creates a new connection entry reader whose destination is the provided
   * connection using an unbounded {@code LinkedBlockingQueue}.
   *
   * @param connection
   *          The connection to use.
   * @param searchRequest
   *          The search request to retrieve entries with.
   * @throws NullPointerException
   *           If {@code connection} was {@code null}.
   */
  public ConnectionEntryReader(final AsynchronousConnection connection,
      final SearchRequest searchRequest) throws NullPointerException
  {
    this(connection, searchRequest, new LinkedBlockingQueue<Response>());
  }
  /**
   * Creates a new connection entry reader whose destination is the provided
   * connection.
   *
   * @param connection
   *          The connection to use.
   * @param searchRequest
   *          The search request to retrieve entries with.
   * @param entries
   *          The {@code BlockingQueue} implementation to use when queuing the
   *          returned entries.
   * @throws NullPointerException
   *           If {@code connection} was {@code null}.
   */
  public ConnectionEntryReader(final AsynchronousConnection connection,
      final SearchRequest searchRequest, final BlockingQueue<Response> entries)
      throws NullPointerException
  {
    Validator.ensureNotNull(connection);
    buffer = new BufferHandler(entries);
    future = connection.search(searchRequest, buffer);
  }
  /**
   * Closes this connection entry reader, cancelling the search request if it is
   * still active.
   */
  @Override
  public void close()
  {
    // Cancel the search if it is still running.
    future.cancel(true);
  }
  /**
   * Returns the next search result entry contained in the search results,
   * waiting if necessary until one becomes available.
   *
   * @return The next search result entry, or {@code null} if there are no more
   *         entries in the search results.
   * @throws SearchResultReferenceIOException
   *           If the next search response was a search result reference. This
   *           connection entry reader may still contain remaining search
   *           results and references which can be retrieved using additional
   *           calls to this method.
   * @throws ErrorResultIOException
   *           If the result code indicates that the search operation failed for
   *           some reason.
   * @throws InterruptedIOException
   *           If the current thread was interrupted while waiting.
   */
  @Override
  public SearchResultEntry readEntry() throws SearchResultReferenceIOException,
      ErrorResultIOException, InterruptedIOException
  {
    Response r;
    try
    {
      while ((r = buffer.responses.poll(50, TimeUnit.MILLISECONDS)) == null)
      {
        if (buffer.isInterrupted)
        {
          // The worker thread processing the result was interrupted so no
          // result will ever arrive. We don't want to hang this thread forever
          // while we wait, so terminate now.
          r = Responses.newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR);
          break;
        }
      }
    }
    catch (final InterruptedException e)
    {
      throw new InterruptedIOException(e.getMessage());
    }
    if (r instanceof SearchResultEntry)
    {
      return (SearchResultEntry) r;
    }
    else if (r instanceof SearchResultReference)
    {
      throw new SearchResultReferenceIOException((SearchResultReference) r);
    }
    else if (r instanceof Result)
    {
      final Result result = (Result) r;
      if (result.isSuccess())
      {
        return null;
      }
      else
      {
        throw new ErrorResultIOException(ErrorResultException.wrap(result));
      }
    }
    else
    {
      throw new RuntimeException("Unexpected response type: "
          + r.getClass().toString());
    }
  }
}
opendj-sdk/sdk/src/org/opends/sdk/requests/CRAMMD5SASLBindRequestImpl.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk.requests;
@@ -111,27 +111,22 @@
    public boolean evaluateResult(final BindResult result)
        throws ErrorResultException
    {
      if (result.getResultCode() == ResultCode.SASL_BIND_IN_PROGRESS
          && result.getServerSASLCredentials() != null)
      try
      {
        try
        {
          setNextSASLCredentials(saslClient.evaluateChallenge(result
              .getServerSASLCredentials().toByteArray()));
          return false;
        }
        catch (final SaslException e)
        {
          // FIXME: I18N need to have a better error message.
          // FIXME: Is this the best result code?
          throw ErrorResultException.wrap(Responses.newResult(
              ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
              "An error occurred during multi-stage authentication")
              .setCause(e));
        }
        setNextSASLCredentials(saslClient.evaluateChallenge(result
            .getServerSASLCredentials() == null ? new byte[0] :
            result.getServerSASLCredentials().toByteArray()));
        return saslClient.isComplete();
      }
      return true;
      catch (final SaslException e)
      {
        // FIXME: I18N need to have a better error message.
        // FIXME: Is this the best result code?
        throw ErrorResultException.wrap(Responses.newResult(
            ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
            "An error occurred during multi-stage authentication")
            .setCause(e));
      }
    }
opendj-sdk/sdk/src/org/opends/sdk/requests/DigestMD5SASLBindRequestImpl.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk.requests;
@@ -122,26 +122,22 @@
    public boolean evaluateResult(final BindResult result)
        throws ErrorResultException
    {
      if (result.getResultCode() == ResultCode.SASL_BIND_IN_PROGRESS
          && result.getServerSASLCredentials() != null)
      try
      {
        try
        {
          setNextSASLCredentials(saslClient.evaluateChallenge(result
              .getServerSASLCredentials().toByteArray()));
          return false;
        }
        catch (final SaslException e)
        {
          // FIXME: I18N need to have a better error message.
          // FIXME: Is this the best result code?
          throw ErrorResultException.wrap(Responses.newResult(
              ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
              "An error occurred during multi-stage authentication")
              .setCause(e));
        }
        setNextSASLCredentials(saslClient.evaluateChallenge(result
            .getServerSASLCredentials() == null ? new byte[0] :
            result.getServerSASLCredentials().toByteArray()));
        return saslClient.isComplete();
      }
      return true;
      catch (final SaslException e)
      {
        // FIXME: I18N need to have a better error message.
        // FIXME: Is this the best result code?
        throw ErrorResultException.wrap(Responses.newResult(
            ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
            "An error occurred during multi-stage authentication")
            .setCause(e));
      }
    }
opendj-sdk/sdk/src/org/opends/sdk/requests/ExternalSASLBindRequestImpl.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk.requests;
@@ -102,26 +102,22 @@
    public boolean evaluateResult(final BindResult result)
        throws ErrorResultException
    {
      if (result.getResultCode() == ResultCode.SASL_BIND_IN_PROGRESS
          && result.getServerSASLCredentials() != null)
      try
      {
        try
        {
          setNextSASLCredentials(saslClient.evaluateChallenge(result
              .getServerSASLCredentials().toByteArray()));
          return false;
        }
        catch (final SaslException e)
        {
          // FIXME: I18N need to have a better error message.
          // FIXME: Is this the best result code?
          throw ErrorResultException.wrap(Responses.newResult(
              ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
              "An error occurred during multi-stage authentication")
              .setCause(e));
        }
        setNextSASLCredentials(saslClient.evaluateChallenge(result
            .getServerSASLCredentials() == null ? new byte[0] :
            result.getServerSASLCredentials().toByteArray()));
        return saslClient.isComplete();
      }
      return true;
      catch (final SaslException e)
      {
        // FIXME: I18N need to have a better error message.
        // FIXME: Is this the best result code?
        throw ErrorResultException.wrap(Responses.newResult(
            ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
            "An error occurred during multi-stage authentication")
            .setCause(e));
      }
    }
  }
opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequest.java
@@ -117,6 +117,62 @@
  /**
   * Set the protocol versions enabled for secure connections with the
   * Directory Server.
   *
   * The protocols must be supported by the SSLContext specified in
   * {@link #setSSLContext(SSLContext)}. Following a successful call to
   * this method, only the protocols listed in the protocols parameter are
   * enabled for use.
   *
   * @param protocols Names of all the protocols to enable or {@code null} to
   *                  use the default protocols.
   * @return A reference to this LDAP connection options.
   */
  StartTLSExtendedRequest setEnabledProtocols(String[] protocols);
  /**
   * Set the cipher suites enabled for secure connections with the
   * Directory Server.
   *
   * The suites must be supported by the SSLContext specified in
   * {@link #setSSLContext(SSLContext)}. Following a successful call to
   * this method, only the suites listed in the protocols parameter are
   * enabled for use.
   *
   * @param suites Names of all the suites to enable or {@code null} to
   *                  use the default cipher suites.
   * @return A reference to this LDAP connection options.
   */
  StartTLSExtendedRequest setEnabledCipherSuites(String[] suites);
  /**
   * Returns the names of the protocol versions which are currently enabled
   * for secure connections with the Directory Server.
   *
   * @return an array of protocols or {@code null} if the default protocols
   * are to be used.
   */
  String[] getEnabledProtocols();
  /**
   * Returns the names of the protocol versions which are currently enabled
   * for secure connections with the Directory Server.
   *
   * @return an array of protocols or {@code null} if the default protocols
   * are to be used.
   */
  String[] getEnabledCipherSuites();
  /**
   * {@inheritDoc}
   */
  ByteString getValue();
opendj-sdk/sdk/src/org/opends/sdk/requests/StartTLSExtendedRequestImpl.java
@@ -98,6 +98,16 @@
  private SSLContext sslContext;
  /**
   * The list of cipher suite
   */
  private String[] enabledCipherSuites = null;
  /**
   * the list of protocols
   */
  private String[] enabledProtocols = null;
  // No need to expose this.
  private static final ExtendedResultDecoder<ExtendedResult> RESULT_DECODER = new ResultDecoder();
@@ -152,6 +162,48 @@
  /**
   * {@inheritDoc}}
   */
  public StartTLSExtendedRequest setEnabledProtocols(String[] protocols)
  {
    this.enabledProtocols = protocols;
    return this;
  }
  /**
   * {@inheritDoc}}
   */
  public StartTLSExtendedRequest setEnabledCipherSuites(String[] suites)
  {
    this.enabledCipherSuites = suites;
    return this;
  }
  /**
   * {@inheritDoc}}
   */
  public String[] getEnabledProtocols()
  {
    return this.enabledProtocols;
  }
  /**
   * {@inheritDoc}}
   */
  public String[] getEnabledCipherSuites()
  {
    return this.enabledCipherSuites;
  }
  /**
   * {@inheritDoc}
   */
  @Override
opendj-sdk/sdk/src/org/opends/sdk/schema/Schema.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 */
package org.opends.sdk.schema;
@@ -1462,21 +1462,21 @@
  private static volatile Schema defaultSchema = CoreSchemaImpl.getInstance();
  private static final String ATTR_ATTRIBUTE_TYPES = "attributeTypes";
  static final String ATTR_ATTRIBUTE_TYPES = "attributeTypes";
  private static final String ATTR_DIT_CONTENT_RULES = "dITContentRules";
  static final String ATTR_DIT_CONTENT_RULES = "dITContentRules";
  private static final String ATTR_DIT_STRUCTURE_RULES = "dITStructureRules";
  static final String ATTR_DIT_STRUCTURE_RULES = "dITStructureRules";
  private static final String ATTR_LDAP_SYNTAXES = "ldapSyntaxes";
  static final String ATTR_LDAP_SYNTAXES = "ldapSyntaxes";
  private static final String ATTR_MATCHING_RULE_USE = "matchingRuleUse";
  static final String ATTR_MATCHING_RULE_USE = "matchingRuleUse";
  private static final String ATTR_MATCHING_RULES = "matchingRules";
  static final String ATTR_MATCHING_RULES = "matchingRules";
  private static final String ATTR_NAME_FORMS = "nameForms";
  static final String ATTR_NAME_FORMS = "nameForms";
  private static final String ATTR_OBJECT_CLASSES = "objectClasses";
  static final String ATTR_OBJECT_CLASSES = "objectClasses";
  private static final String ATTR_SUBSCHEMA_SUBENTRY = "subschemaSubentry";
@@ -1679,7 +1679,7 @@
   */
  public static FutureResult<Schema> readSchemaForEntry(
      final AsynchronousConnection connection, final DN name,
      final ResultHandler<Schema> handler)
      final ResultHandler<? super Schema> handler)
      throws UnsupportedOperationException, IllegalStateException,
      NullPointerException
  {
@@ -1780,137 +1780,7 @@
   */
  public static Schema valueOf(final Entry entry)
  {
    final SchemaBuilder builder = new SchemaBuilder(entry.getName().toString());
    Attribute attr = entry.getAttribute(ATTR_LDAP_SYNTAXES);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          builder.addSyntax(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          builder.addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(ATTR_ATTRIBUTE_TYPES);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          builder.addAttributeType(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          builder.addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(ATTR_OBJECT_CLASSES);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          builder.addObjectClass(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          builder.addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(ATTR_MATCHING_RULE_USE);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          builder.addMatchingRuleUse(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          builder.addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(ATTR_MATCHING_RULES);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          builder.addMatchingRule(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          builder.addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(ATTR_DIT_CONTENT_RULES);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          builder.addDITContentRule(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          builder.addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(ATTR_DIT_STRUCTURE_RULES);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          builder.addDITStructureRule(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          builder.addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(ATTR_NAME_FORMS);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          builder.addNameForm(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          builder.addWarning(e.getMessageObject());
        }
      }
    }
    return builder.toSchema();
    return new SchemaBuilder(entry).toSchema();
  }
@@ -2641,6 +2511,105 @@
  /**
   * Adds the definitions of all the schema elements contained in this schema to
   * the provided subschema subentry. Any existing attributes (including schema
   * definitions) contained in the provided entry will be preserved.
   *
   * @param entry
   *          The subschema subentry to which all schema definitions should be
   *          added.
   * @return The updated subschema subentry.
   * @throws NullPointerException
   *           If {@code entry} was {@code null}.
   */
  public Entry toEntry(Entry entry) throws NullPointerException
  {
    Attribute attr = new LinkedAttribute(Schema.ATTR_LDAP_SYNTAXES);
    for (Syntax syntax : getSyntaxes())
    {
      attr.add(syntax.toString());
    }
    if (!attr.isEmpty())
    {
      entry.addAttribute(attr);
    }
    attr = new LinkedAttribute(Schema.ATTR_ATTRIBUTE_TYPES);
    for (AttributeType attributeType : getAttributeTypes())
    {
      attr.add(attributeType.toString());
    }
    if (!attr.isEmpty())
    {
      entry.addAttribute(attr);
    }
    attr = new LinkedAttribute(Schema.ATTR_OBJECT_CLASSES);
    for (ObjectClass objectClass : getObjectClasses())
    {
      attr.add(objectClass.toString());
    }
    if (!attr.isEmpty())
    {
      entry.addAttribute(attr);
    }
    attr = new LinkedAttribute(Schema.ATTR_MATCHING_RULE_USE);
    for (MatchingRuleUse matchingRuleUse : getMatchingRuleUses())
    {
      attr.add(matchingRuleUse.toString());
    }
    if (!attr.isEmpty())
    {
      entry.addAttribute(attr);
    }
    attr = new LinkedAttribute(Schema.ATTR_MATCHING_RULES);
    for (MatchingRule matchingRule : getMatchingRules())
    {
      attr.add(matchingRule.toString());
    }
    if (!attr.isEmpty())
    {
      entry.addAttribute(attr);
    }
    attr = new LinkedAttribute(Schema.ATTR_DIT_CONTENT_RULES);
    for (DITContentRule ditContentRule : getDITContentRules())
    {
      attr.add(ditContentRule.toString());
    }
    if (!attr.isEmpty())
    {
      entry.addAttribute(attr);
    }
    attr = new LinkedAttribute(Schema.ATTR_DIT_STRUCTURE_RULES);
    for (DITStructureRule ditStructureRule : getDITStuctureRules())
    {
      attr.add(ditStructureRule.toString());
    }
    if (!attr.isEmpty())
    {
      entry.addAttribute(attr);
    }
    attr = new LinkedAttribute(Schema.ATTR_NAME_FORMS);
    for (NameForm nameForm : getNameForms())
    {
      attr.add(nameForm.toString());
    }
    if (!attr.isEmpty())
    {
      entry.addAttribute(attr);
    }
    return entry;
  }
  SchemaCompatOptions getSchemaCompatOptions()
  {
    return impl.getSchemaCompatOptions();
opendj-sdk/sdk/src/org/opends/sdk/schema/SchemaBuilder.java
@@ -42,9 +42,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import org.opends.sdk.DecodeException;
import org.opends.sdk.LocalizableMessage;
import org.opends.sdk.LocalizedIllegalArgumentException;
import org.opends.sdk.*;
import com.sun.opends.sdk.util.StaticUtils;
import com.sun.opends.sdk.util.SubstringReader;
@@ -116,6 +114,152 @@
  /**
   * Creates a new schema builder containing all of the schema elements
   * contained in the provided a subschema subentry. Any problems encountered
   * while parsing the entry can be retrieved using the returned schema's
   * {@link Schema#getWarnings()} method.
   *
   * @param entry
   *          The subschema subentry to be parsed.
   * @throws NullPointerException
   *           If {@code entry} was {@code null}.
   */
  public SchemaBuilder(final Entry entry) throws NullPointerException
  {
    initBuilder(entry.getName().toString());
    Attribute attr = entry.getAttribute(Schema.ATTR_LDAP_SYNTAXES);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          addSyntax(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          addAttributeType(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(Schema.ATTR_OBJECT_CLASSES);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          addObjectClass(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(Schema.ATTR_MATCHING_RULE_USE);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          addMatchingRuleUse(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(Schema.ATTR_MATCHING_RULES);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          addMatchingRule(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(Schema.ATTR_DIT_CONTENT_RULES);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          addDITContentRule(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          addDITStructureRule(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          addWarning(e.getMessageObject());
        }
      }
    }
    attr = entry.getAttribute(Schema.ATTR_NAME_FORMS);
    if (attr != null)
    {
      for (final ByteString def : attr)
      {
        try
        {
          addNameForm(def.toString(), true);
        }
        catch (final LocalizedIllegalArgumentException e)
        {
          addWarning(e.getMessageObject());
        }
      }
    }
  }
  /**
   * Creates a new schema builder containing all of the schema elements from the
   * provided schema and its compatibility options.
   *
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/AuthenticatedConnectionFactoryTestCase.java
File was deleted
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/ConnectionFactoryTestCase.java
@@ -33,16 +33,21 @@
import static org.testng.Assert.assertTrue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.opends.sdk.requests.Requests;
import org.opends.sdk.requests.SearchRequest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.testng.annotations.DataProvider;
import javax.net.ssl.SSLContext;
/**
 * Tests the connectionfactory classes.
 */
public abstract class ConnectionFactoryTestCase extends SdkTestCase
public class ConnectionFactoryTestCase extends SdkTestCase
{
  class MyResultHandler implements ResultHandler<AsynchronousConnection>
  {
@@ -90,7 +95,63 @@
    TestCaseUtils.startServer();
  }
  @DataProvider(name = "connectionFactories")
  public Object[][] getModifyDNRequests() throws Exception
  {
    Object[][] factories = new Object[7][1];
    // HeartBeatConnectionFactory
    // Use custom search request.
    SearchRequest request = Requests.newSearchRequest(
        "uid=user.0,ou=people,o=test", SearchScope.BASE_OBJECT, "objectclass=*",
        "cn");
    factories[0][0] = new HeartBeatConnectionFactory(
        new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort()),
        1000, TimeUnit.MILLISECONDS, request);
    // InternalConnectionFactory
    factories[1][0] = Connections
      .newInternalConnectionFactory(LDAPServer.getInstance(), null);
    // AuthenticatedConnectionFactory
    factories[2][0] = new AuthenticatedConnectionFactory(
      new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort()),
      Requests.newSimpleBindRequest("", ""));
    // AuthenticatedConnectionFactory with multi-stage SASL
    factories[3][0] = new AuthenticatedConnectionFactory(
      new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort()),
      Requests.newCRAMMD5SASLBindRequest("id:user",
            ByteString.valueOf("password")));
    // LDAPConnectionFactory with default options
    factories[4][0] = new LDAPConnectionFactory(
      "localhost", TestCaseUtils.getLdapPort());
    // LDAPConnectionFactory with startTLS
    SSLContext sslContext = new SSLContextBuilder().
        setTrustManager(TrustManagers.trustAll()).getSSLContext();
    LDAPOptions options = new LDAPOptions().setSSLContext(sslContext).
        setUseStartTLS(true).setEnabledCipherSuites(
        new String[]{"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
                         "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
                         "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
                         "SSL_DH_anon_WITH_DES_CBC_SHA",
                         "SSL_DH_anon_WITH_RC4_128_MD5",
                         "TLS_DH_anon_WITH_AES_128_CBC_SHA",
                         "TLS_DH_anon_WITH_AES_256_CBC_SHA"});
    factories[5][0] = new LDAPConnectionFactory(
        "localhost", TestCaseUtils.getLdapPort(), options);
    // startTLS + SASL confidentiality
    factories[6][0] = new AuthenticatedConnectionFactory(
        new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort(),
            options), Requests.newDigestMD5SASLBindRequest("id:user",
            ByteString.valueOf("password")));
    return factories;
  }
  /**
   * Tests the async connection in the blocking mode. This is not fully async as
@@ -98,10 +159,12 @@
   *
   * @throws Exception
   */
  @Test()
  public void testBlockingFutureNoHandler() throws Exception
  @Test(dataProvider = "connectionFactories")
  public void testBlockingFutureNoHandler(ConnectionFactory factory)
      throws Exception
  {
    final FutureResult<AsynchronousConnection> future = getAsynchronousConnection(null);
    final FutureResult<AsynchronousConnection> future =
        factory.getAsynchronousConnection(null);
    final AsynchronousConnection con = future.get();
    // quickly check if iit is a valid connection.
    // Don't use a result handler.
@@ -116,13 +179,15 @@
   *
   * @throws Exception
   */
  @Test()
  public void testNonBlockingFutureWithHandler() throws Exception
  @Test(dataProvider = "connectionFactories")
  public void testNonBlockingFutureWithHandler(ConnectionFactory factory)
      throws Exception
  {
    // Use the handler to get the result asynchronously.
    final CountDownLatch latch = new CountDownLatch(1);
    final MyResultHandler handler = new MyResultHandler(latch);
    final FutureResult<AsynchronousConnection> future = getAsynchronousConnection(handler);
    final FutureResult<AsynchronousConnection> future =
        factory.getAsynchronousConnection(handler);
    // Since we don't have anything to do, we would rather
    // be notified by the latch when the other thread calls our handler.
    latch.await(); // should do a timed wait rather?
@@ -140,32 +205,14 @@
   *
   * @throws Exception
   */
  @Test()
  public void testSynchronousConnection() throws Exception
  @Test(dataProvider = "connectionFactories")
  public void testSynchronousConnection(ConnectionFactory factory)
      throws Exception
  {
    final Connection con = getConnection();
    final Connection con = factory.getConnection();
    assertNotNull(con);
    // quickly check if iit is a valid connection.
    assertTrue(con.readRootDSE().getEntry().getName().isRootDN());
    con.close();
  }
  /**
   * Gets the future result from the implementations.
   *
   * @return FutureResult.
   */
  protected abstract FutureResult<AsynchronousConnection> getAsynchronousConnection(
      ResultHandler<AsynchronousConnection> handler) throws Exception;
  /**
   * Gets the connection from the implementations.
   *
   * @return Connection
   */
  protected abstract Connection getConnection() throws Exception;
}
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/HeartBeatConnectionFactoryTestCase.java
File was deleted
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/InternalConnectionFactoryTestCase.java
File was deleted
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/LDAPConnectionFactoryTestCase.java
File was deleted
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/LDAPServer.java
@@ -29,13 +29,19 @@
import static com.sun.opends.sdk.ldap.LDAPConstants.TYPE_AUTHENTICATION_SASL;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ssl.SSLContext;
import javax.security.auth.callback.*;
import javax.security.sasl.*;
import org.opends.sdk.asn1.ASN1;
import org.opends.sdk.asn1.ASN1Reader;
import org.opends.sdk.controls.Control;
import org.opends.sdk.controls.ControlDecoder;
import org.opends.sdk.requests.*;
@@ -53,7 +59,7 @@
 * A simple ldap server that manages 1000 entries and used for running
 * testcases. //FIXME: make it MT-safe.
 */
public class LDAPServer implements ServerConnection<Integer>,
public class LDAPServer implements
    ServerConnectionFactory<LDAPClientContext, Integer>
{
  // Creates an abandonable request from the ordinary requests.
@@ -132,6 +138,525 @@
  private class LDAPServerConnection implements ServerConnection<Integer>
  {
    private final LDAPClientContext clientContext;
    private SaslServer saslServer;
    private LDAPServerConnection(LDAPClientContext clientContext)
    {
      this.clientContext = clientContext;
    }
    /**
     * Abandons the request sent by the client.
     *
     * @param context
     * @param request
     * @throws UnsupportedOperationException
     */
    public void handleAbandon(final Integer context,
        final AbandonRequest request) throws UnsupportedOperationException
    {
      // Check if we have any concurrent operation with this message id.
      final AbandonableRequest req = requestsInProgress.get(context);
      if (req == null)
      {
        // Nothing to do here.
        return;
      }
      // Cancel the request
      req.cancel();
      // No response is needed.
    }
    /**
     * Adds the request sent by the client.
     *
     * @param context
     * @param request
     * @param handler
     * @param intermediateResponseHandler
     * @throws UnsupportedOperationException
     */
    public void handleAdd(final Integer context, final AddRequest request,
        final ResultHandler<? super Result> handler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
    {
      Result result = null;
      final AbandonableRequest abReq = new AbandonableRequest(request);
      requestsInProgress.put(context, abReq);
      // Get the DN.
      final DN dn = request.getName();
      if (entryMap.containsKey(dn))
      {
        // duplicate entry.
        result = Responses.newResult(ResultCode.ENTRY_ALREADY_EXISTS);
        final ErrorResultException ere = ErrorResultException.wrap(result);
        handler.handleErrorResult(ere);
        // doesn't matter if it was canceled.
        requestsInProgress.remove(context);
        return;
      }
      // Create an entry out of this request.
      final SearchResultEntry entry = Responses.newSearchResultEntry(dn);
      for (final Control control : request.getControls())
      {
        entry.addControl(control);
      }
      for (final Attribute attr : request.getAllAttributes())
      {
        entry.addAttribute(attr);
      }
      if (abReq.isCanceled())
      {
        result = Responses.newResult(ResultCode.CANCELLED);
        final ErrorResultException ere = ErrorResultException.wrap(result);
        handler.handleErrorResult(ere);
        requestsInProgress.remove(context);
        return;
      }
      // Add this to the map.
      entryMap.put(dn, entry);
      requestsInProgress.remove(context);
      result = Responses.newResult(ResultCode.SUCCESS);
      handler.handleResult(result);
    }
    /**
     * @param context
     * @param version
     * @param request
     * @param resultHandler
     * @param intermediateResponseHandler
     * @throws UnsupportedOperationException
     */
    public void handleBind(final Integer context, final int version,
        final BindRequest request,
        final ResultHandler<? super BindResult> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
    {
      // TODO: all bind types.
      final AbandonableRequest abReq = new AbandonableRequest(request);
      requestsInProgress.put(context, abReq);
      if (request.getAuthenticationType() == TYPE_AUTHENTICATION_SASL
          && request instanceof GenericBindRequest)
      {
        ASN1Reader reader = ASN1.getReader(((GenericBindRequest) request)
            .getAuthenticationValue());
        try
        {
          String saslMech = reader.readOctetStringAsString();
          ByteString saslCred;
          if (reader.hasNextElement())
          {
            saslCred = reader.readOctetString();
          }
          else
          {
            saslCred = ByteString.empty();
          }
          if (saslServer == null
              || !saslServer.getMechanismName().equalsIgnoreCase(saslMech))
          {
            final Map<String, String> props = new HashMap<String, String>();
            props.put(Sasl.QOP, "auth-conf,auth-int,auth");
            saslServer = Sasl.createSaslServer(saslMech, "ldap", clientContext
                .getLocalAddress().getHostName(), props, new CallbackHandler()
            {
              public void handle(Callback[] callbacks) throws IOException,
                  UnsupportedCallbackException
              {
                for (final Callback callback : callbacks)
                {
                  if (callback instanceof NameCallback)
                  {
                    // Do nothing
                  }
                  else if (callback instanceof PasswordCallback)
                  {
                    ((PasswordCallback) callback).setPassword("password"
                        .toCharArray());
                  }
                  else if (callback instanceof AuthorizeCallback)
                  {
                    ((AuthorizeCallback) callback).setAuthorized(true);
                  }
                  else if (callback instanceof RealmCallback)
                  {
                    // Do nothing
                  }
                  else
                  {
                    throw new UnsupportedCallbackException(callback);
                  }
                }
              }
            });
          }
          byte[] challenge = saslServer
              .evaluateResponse(saslCred.toByteArray());
          if (saslServer.isComplete())
          {
            resultHandler.handleResult(Responses.newBindResult(
                ResultCode.SUCCESS).setServerSASLCredentials(
                ByteString.wrap(challenge)));
            String qop = (String) saslServer.getNegotiatedProperty(Sasl.QOP);
            if (qop != null
                && (qop.equalsIgnoreCase("auth-int") || qop
                    .equalsIgnoreCase("auth-conf")))
            {
              ConnectionSecurityLayer csl = new ConnectionSecurityLayer()
              {
                public void dispose()
                {
                  try
                  {
                    saslServer.dispose();
                  }
                  catch (SaslException e)
                  {
                    e.printStackTrace();
                  }
                }
                public byte[] unwrap(byte[] incoming, int offset, int len)
                    throws ErrorResultException
                {
                  try
                  {
                    return saslServer.unwrap(incoming, offset, len);
                  }
                  catch (SaslException e)
                  {
                    throw ErrorResultException.wrap(Responses.newResult(
                        ResultCode.OPERATIONS_ERROR).setCause(e));
                  }
                }
                public byte[] wrap(byte[] outgoing, int offset, int len)
                    throws ErrorResultException
                {
                  try
                  {
                    return saslServer.wrap(outgoing, offset, len);
                  }
                  catch (SaslException e)
                  {
                    throw ErrorResultException.wrap(Responses.newResult(
                        ResultCode.OPERATIONS_ERROR).setCause(e));
                  }
                }
              };
              clientContext.startSASL(csl);
            }
          }
          else
          {
            resultHandler.handleResult(Responses.newBindResult(
                ResultCode.SASL_BIND_IN_PROGRESS).setServerSASLCredentials(
                ByteString.wrap(challenge)));
          }
        }
        catch (Exception e)
        {
          resultHandler.handleErrorResult(ErrorResultException.wrap(Responses
              .newBindResult(ResultCode.OPERATIONS_ERROR).setCause(e)
              .setDiagnosticMessage(e.toString())));
        }
      }
      else
      {
        resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS));
      }
      requestsInProgress.remove(context);
    }
    /**
     * @param context
     * @param request
     */
    public void handleConnectionClosed(final Integer context,
        final UnbindRequest request)
    {
      if (saslServer != null)
      {
        try
        {
          saslServer.dispose();
        }
        catch (SaslException e)
        {
          e.printStackTrace();
        }
      }
    }
    /**
     * @param error
     */
    public void handleConnectionException(final Throwable error)
    {
    }
    /**
     * @param context
     * @param request
     * @param resultHandler
     * @param intermediateResponseHandler
     * @throws UnsupportedOperationException
     */
    public void handleCompare(final Integer context,
        final CompareRequest request,
        final ResultHandler<? super CompareResult> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
    {
      CompareResult result = null;
      final AbandonableRequest abReq = new AbandonableRequest(request);
      requestsInProgress.put(context, abReq);
      // Get the DN.
      final DN dn = request.getName();
      if (!entryMap.containsKey(dn))
      {
        // entry not found.
        result = Responses.newCompareResult(ResultCode.NO_SUCH_ATTRIBUTE);
        final ErrorResultException ere = ErrorResultException.wrap(result);
        resultHandler.handleErrorResult(ere);
        // doesn't matter if it was canceled.
        requestsInProgress.remove(context);
        return;
      }
      // Get the entry.
      final Entry entry = entryMap.get(dn);
      final AttributeDescription attrDesc = request.getAttributeDescription();
      for (final Attribute attr : entry.getAllAttributes(attrDesc))
      {
        final Iterator<ByteString> it = attr.iterator();
        while (it.hasNext())
        {
          final ByteString s = it.next();
          if (abReq.isCanceled())
          {
            final Result r = Responses.newResult(ResultCode.CANCELLED);
            final ErrorResultException ere = ErrorResultException.wrap(r);
            resultHandler.handleErrorResult(ere);
            requestsInProgress.remove(context);
            return;
          }
          if (s.equals(request.getAssertionValue()))
          {
            result = Responses.newCompareResult(ResultCode.COMPARE_TRUE);
            resultHandler.handleResult(result);
          }
        }
      }
      result = Responses.newCompareResult(ResultCode.COMPARE_FALSE);
      resultHandler.handleResult(result);
      requestsInProgress.remove(context);
    }
    /**
     * @param context
     * @param request
     * @param handler
     * @param intermediateResponseHandler
     * @throws UnsupportedOperationException
     */
    public void handleDelete(final Integer context,
        final DeleteRequest request,
        final ResultHandler<? super Result> handler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
    {
      Result result = null;
      final AbandonableRequest abReq = new AbandonableRequest(request);
      requestsInProgress.put(context, abReq);
      // Get the DN.
      final DN dn = request.getName();
      if (!entryMap.containsKey(dn))
      {
        // entry is not found.
        result = Responses.newResult(ResultCode.NO_SUCH_OBJECT);
        final ErrorResultException ere = ErrorResultException.wrap(result);
        handler.handleErrorResult(ere);
        // doesn't matter if it was canceled.
        requestsInProgress.remove(context);
        return;
      }
      if (abReq.isCanceled())
      {
        result = Responses.newResult(ResultCode.CANCELLED);
        final ErrorResultException ere = ErrorResultException.wrap(result);
        handler.handleErrorResult(ere);
        requestsInProgress.remove(context);
        return;
      }
      // Remove this from the map.
      entryMap.remove(dn);
      requestsInProgress.remove(context);
    }
    /**
     * @param context
     * @param request
     * @param resultHandler
     * @param intermediateResponseHandler
     * @throws UnsupportedOperationException
     */
    public <R extends ExtendedResult> void handleExtendedRequest(
        final Integer context, final ExtendedRequest<R> request,
        final ResultHandler<? super R> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
    {
      if (request.getOID().equals(StartTLSExtendedRequest.OID))
      {
        final R result = request.getResultDecoder().adaptExtendedErrorResult(
            ResultCode.SUCCESS, "", "");
        resultHandler.handleResult(result);
        clientContext.startTLS(sslContext, null, sslContext.getSocketFactory()
            .getSupportedCipherSuites(), false, false);
      }
    }
    /**
     * @param context
     * @param request
     * @param resultHandler
     * @param intermediateResponseHandler
     * @throws UnsupportedOperationException
     */
    public void handleModify(final Integer context,
        final ModifyRequest request,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
    {
      // TODO:
    }
    /**
     * @param context
     * @param request
     * @param resultHandler
     * @param intermediateResponseHandler
     * @throws UnsupportedOperationException
     */
    public void handleModifyDN(final Integer context,
        final ModifyDNRequest request,
        final ResultHandler<? super Result> resultHandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
    {
      // TODO
    }
    /**
     * @param context
     * @param request
     * @param resultHandler
     * @param searchResulthandler
     * @param intermediateResponseHandler
     * @throws UnsupportedOperationException
     */
    public void handleSearch(final Integer context,
        final SearchRequest request,
        final ResultHandler<? super Result> resultHandler,
        final SearchResultHandler searchResulthandler,
        final IntermediateResponseHandler intermediateResponseHandler)
        throws UnsupportedOperationException
    {
      Result result = null;
      final AbandonableRequest abReq = new AbandonableRequest(request);
      requestsInProgress.put(context, abReq);
      // Get the DN.
      final DN dn = request.getName();
      if (!entryMap.containsKey(dn))
      {
        // Entry not found.
        result = Responses.newResult(ResultCode.NO_SUCH_OBJECT);
        final ErrorResultException ere = ErrorResultException.wrap(result);
        resultHandler.handleErrorResult(ere);
        // Should searchResultHandler handle anything?
        // doesn't matter if it was canceled.
        requestsInProgress.remove(context);
        return;
      }
      if (abReq.isCanceled())
      {
        result = Responses.newResult(ResultCode.CANCELLED);
        final ErrorResultException ere = ErrorResultException.wrap(result);
        resultHandler.handleErrorResult(ere);
        requestsInProgress.remove(context);
        return;
      }
      final SearchResultEntry e = Responses
          .newSearchResultEntry(new LinkedHashMapEntry(entryMap.get(dn)));
      // Check we have had any controls in the request.
      for (final Control control : request.getControls())
      {
        if (control.getOID().equals(AccountUsabilityRequestControl.OID))
        {
          e.addControl(AccountUsabilityResponseControl.newControl(false, false,
              false, 10, false, 0));
        }
      }
      searchResulthandler.handleEntry(e);
      result = Responses.newResult(ResultCode.SUCCESS);
      resultHandler.handleResult(result);
      requestsInProgress.remove(context);
    }
  }
  // The mapping between entry DNs and the corresponding entries.
  private final ConcurrentHashMap<DN, Entry> entryMap = new ConcurrentHashMap<DN, Entry>();
@@ -152,6 +677,8 @@
  // The Set used for locking dns.
  private final HashSet<DN> lockedDNs = new HashSet<DN>();
  private SSLContext sslContext;
  private LDAPServer()
@@ -177,258 +704,12 @@
  /**
   * Abandons the request sent by the client.
   *
   * @param context
   * @param request
   * @throws UnsupportedOperationException
   */
  public void abandon(final Integer context, final AbandonRequest request)
      throws UnsupportedOperationException
  {
    // Check if we have any concurrent operation with this message id.
    final AbandonableRequest req = requestsInProgress.get(context);
    if (req == null)
    {
      // Nothing to do here.
      return;
    }
    // Cancel the request
    req.cancel();
    // No response is needed.
  }
  /**
   * @param context
   * @return
   */
  public ServerConnection<Integer> accept(final LDAPClientContext context)
  {
    return this;
  }
  /**
   * Adds the request sent by the client.
   *
   * @param context
   * @param request
   * @param handler
   * @param intermediateResponseHandler
   * @throws UnsupportedOperationException
   */
  public void add(final Integer context, final AddRequest request,
      final ResultHandler<Result> handler,
      final IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException
  {
    Result result = null;
    final AbandonableRequest abReq = new AbandonableRequest(request);
    requestsInProgress.put(context, abReq);
    // Get the DN.
    final DN dn = request.getName();
    if (entryMap.containsKey(dn))
    {
      // duplicate entry.
      result = Responses.newResult(ResultCode.ENTRY_ALREADY_EXISTS);
      final ErrorResultException ere = ErrorResultException.wrap(result);
      handler.handleErrorResult(ere);
      // doesn't matter if it was canceled.
      requestsInProgress.remove(context);
      return;
    }
    // Create an entry out of this request.
    final SearchResultEntry entry = Responses.newSearchResultEntry(dn);
    for (final Control control : request.getControls())
    {
      entry.addControl(control);
    }
    for (final Attribute attr : request.getAllAttributes())
    {
      entry.addAttribute(attr);
    }
    if (abReq.isCanceled())
    {
      result = Responses.newResult(ResultCode.CANCELLED);
      final ErrorResultException ere = ErrorResultException.wrap(result);
      handler.handleErrorResult(ere);
      requestsInProgress.remove(context);
      return;
    }
    // Add this to the map.
    entryMap.put(dn, entry);
    requestsInProgress.remove(context);
    result = Responses.newResult(ResultCode.SUCCESS);
    handler.handleResult(result);
  }
  /**
   * @param context
   * @param version
   * @param request
   * @param resultHandler
   * @param intermediateResponseHandler
   * @throws UnsupportedOperationException
   */
  public void bind(final Integer context, final int version,
      final BindRequest request,
      final ResultHandler<? super BindResult> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException
  {
    // TODO: all bind types.
    final AbandonableRequest abReq = new AbandonableRequest(request);
    requestsInProgress.put(context, abReq);
    resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS));
    requestsInProgress.remove(context);
  }
  /**
   * @param context
   * @param request
   */
  public void closed(final Integer context, final UnbindRequest request)
  {
  }
  /**
   * @param error
   */
  public void closed(final Throwable error)
  {
  }
  /**
   * @param context
   * @param request
   * @param resultHandler
   * @param intermediateResponseHandler
   * @throws UnsupportedOperationException
   */
  public void compare(final Integer context, final CompareRequest request,
      final ResultHandler<? super CompareResult> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException
  {
    CompareResult result = null;
    final AbandonableRequest abReq = new AbandonableRequest(request);
    requestsInProgress.put(context, abReq);
    // Get the DN.
    final DN dn = request.getName();
    if (!entryMap.containsKey(dn))
    {
      // entry not found.
      result = Responses.newCompareResult(ResultCode.NO_SUCH_ATTRIBUTE);
      final ErrorResultException ere = ErrorResultException.wrap(result);
      resultHandler.handleErrorResult(ere);
      // doesn't matter if it was canceled.
      requestsInProgress.remove(context);
      return;
    }
    // Get the entry.
    final Entry entry = entryMap.get(dn);
    final AttributeDescription attrDesc = request.getAttributeDescription();
    for (final Attribute attr : entry.getAllAttributes(attrDesc))
    {
      final Iterator<ByteString> it = attr.iterator();
      while (it.hasNext())
      {
        final ByteString s = it.next();
        if (abReq.isCanceled())
        {
          final Result r = Responses.newResult(ResultCode.CANCELLED);
          final ErrorResultException ere = ErrorResultException.wrap(r);
          resultHandler.handleErrorResult(ere);
          requestsInProgress.remove(context);
          return;
        }
        if (s.equals(request.getAssertionValue()))
        {
          result = Responses.newCompareResult(ResultCode.COMPARE_TRUE);
          resultHandler.handleResult(result);
        }
      }
    }
    result = Responses.newCompareResult(ResultCode.COMPARE_FALSE);
    resultHandler.handleResult(result);
    requestsInProgress.remove(context);
  }
  /**
   * @param context
   * @param request
   * @param handler
   * @param intermediateResponseHandler
   * @throws UnsupportedOperationException
   */
  public void delete(final Integer context, final DeleteRequest request,
      final ResultHandler<Result> handler,
      final IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException
  {
    Result result = null;
    final AbandonableRequest abReq = new AbandonableRequest(request);
    requestsInProgress.put(context, abReq);
    // Get the DN.
    final DN dn = request.getName();
    if (!entryMap.containsKey(dn))
    {
      // entry is not found.
      result = Responses.newResult(ResultCode.NO_SUCH_OBJECT);
      final ErrorResultException ere = ErrorResultException.wrap(result);
      handler.handleErrorResult(ere);
      // doesn't matter if it was canceled.
      requestsInProgress.remove(context);
      return;
    }
    if (abReq.isCanceled())
    {
      result = Responses.newResult(ResultCode.CANCELLED);
      final ErrorResultException ere = ErrorResultException.wrap(result);
      handler.handleErrorResult(ere);
      requestsInProgress.remove(context);
      return;
    }
    // Remove this from the map.
    entryMap.remove(dn);
    requestsInProgress.remove(context);
  }
  /**
   * @param context
   * @param request
   * @param resultHandler
   * @param intermediateResponseHandler
   * @throws UnsupportedOperationException
   */
  public <R extends ExtendedResult> void extendedRequest(final Integer context,
      final ExtendedRequest<R> request, final ResultHandler<R> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException
  {
    // TODO:
    return new LDAPServerConnection(context);
  }
@@ -446,113 +727,21 @@
  /**
   * @param context
   * @param request
   * @param resultHandler
   * @param intermediateResponseHandler
   * @throws UnsupportedOperationException
   */
  public void modify(final Integer context, final ModifyRequest request,
      final ResultHandler<Result> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException
  {
    // TODO:
  }
  /**
   * @param context
   * @param request
   * @param resultHandler
   * @param intermediateResponseHandler
   * @throws UnsupportedOperationException
   */
  public void modifyDN(final Integer context, final ModifyDNRequest request,
      final ResultHandler<Result> resultHandler,
      final IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException
  {
    // TODO
  }
  /**
   * @param context
   * @param request
   * @param resultHandler
   * @param searchResulthandler
   * @param intermediateResponseHandler
   * @throws UnsupportedOperationException
   */
  public void search(final Integer context, final SearchRequest request,
      final ResultHandler<Result> resultHandler,
      final SearchResultHandler searchResulthandler,
      final IntermediateResponseHandler intermediateResponseHandler)
      throws UnsupportedOperationException
  {
    Result result = null;
    final AbandonableRequest abReq = new AbandonableRequest(request);
    requestsInProgress.put(context, abReq);
    // Get the DN.
    final DN dn = request.getName();
    if (!entryMap.containsKey(dn))
    {
      // Entry not found.
      result = Responses.newResult(ResultCode.NO_SUCH_OBJECT);
      final ErrorResultException ere = ErrorResultException.wrap(result);
      resultHandler.handleErrorResult(ere);
      // Should searchResultHandler handle anything?
      // doesn't matter if it was canceled.
      requestsInProgress.remove(context);
      return;
    }
    if (abReq.isCanceled())
    {
      result = Responses.newResult(ResultCode.CANCELLED);
      final ErrorResultException ere = ErrorResultException.wrap(result);
      resultHandler.handleErrorResult(ere);
      requestsInProgress.remove(context);
      return;
    }
    final SearchResultEntry e = Responses.newSearchResultEntry(
        new LinkedHashMapEntry(entryMap.get(dn)));
    // Check we have had any controls in the request.
    for (final Control control : request.getControls())
    {
      if (control.getOID().equals(AccountUsabilityRequestControl.OID))
      {
        e.addControl(AccountUsabilityResponseControl.newControl(false, false,
            false, 10, false, 0));
      }
    }
    searchResulthandler.handleEntry(e);
    result = Responses.newResult(ResultCode.SUCCESS);
    resultHandler.handleResult(result);
    requestsInProgress.remove(context);
  }
  /**
   * Starts the server.
   *
   * @param port
   * @exception IOException
   */
  public synchronized void start(final int port) throws IOException
  public synchronized void start(final int port) throws Exception
  {
    if (isRunning)
    {
      return;
    }
    sslContext = new SSLContextBuilder().getSSLContext();
    transport.setSelectorRunnersCount(2);
    listener = new LDAPListener(port, new LDAPServer(),
    listener = new LDAPListener(port, getInstance(),
        new GrizzlyLDAPListenerOptions().setTCPNIOTransport(transport)
            .setBacklog(4096));
    transport.start();
opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/SynchronousConnectionTestCase.java
@@ -29,17 +29,17 @@
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import java.util.List;
import org.opends.sdk.ldif.EntryReader;
import org.opends.sdk.requests.Requests;
import org.opends.sdk.responses.BindResult;
import org.opends.sdk.responses.CompareResult;
import org.opends.sdk.responses.Result;
import org.opends.sdk.responses.SearchResultEntry;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -155,10 +155,11 @@
  public void testSearchRequest() throws Exception
  {
    final SynchronousConnection con = new SynchronousConnection(asyncCon);
    final List<SearchResultEntry> entries = con.search(
    final EntryReader reader = con.search(
        "uid=user.0,ou=people,o=test", SearchScope.BASE_OBJECT,
        "objectclass=*", "cn");
    assertEquals(entries.size(), 1);
    reader.readEntry();
    assertNull(reader.readEntry());
  }
  // TODO: add more tests.
}