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

Ludovic Poitou
22.06.2010 18b64d8efe7da2095468d1937a379ba7d7083d27
Ensure that correct Grizzly MemoryManager is used for SASL and ASN1 filters.

Use perf-tool transport factory for examples as the default one creates too many threads and uses an inefficient work queue.

Cache normalized AVA attribute values for ordering and equality matches.

Use SameThreadStrategy by default and provide "org.opends.sdk.ldap.transport.useWorkerThreads" boolean property to switch to WorkerThreadStrategy.

16 files modified
859 ■■■■■ changed files
sdk/examples/org/opends/sdk/examples/server/proxy/Main.java 6 ●●●●● patch | view | raw | blame | history
sdk/examples/org/opends/sdk/examples/server/store/Main.java 6 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/ASN1BufferReader.java 9 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/LDAPClientFilter.java 6 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/LDAPServerFilter.java 6 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/SASLDecoderTransformer.java 12 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/SASLEncoderTransformer.java 12 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/ldap/SASLFilter.java 8 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/tools/AuthRate.java 188 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/tools/ModRate.java 41 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/tools/PerfToolTCPNIOTransportFactory.java 5 ●●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/tools/PerformanceRunner.java 321 ●●●● patch | view | raw | blame | history
sdk/src/com/sun/opends/sdk/tools/SearchRate.java 48 ●●●● patch | view | raw | blame | history
sdk/src/org/opends/sdk/AVA.java 183 ●●●●● patch | view | raw | blame | history
sdk/tests/unit-tests-testng/src/com/sun/opends/sdk/ldap/ASN1BufferReaderTestCase.java 4 ●●● patch | view | raw | blame | history
sdk/tests/unit-tests-testng/src/com/sun/opends/sdk/ldap/ASN1BufferWriterTestCase.java 4 ●●● patch | view | raw | blame | history
sdk/examples/org/opends/sdk/examples/server/proxy/Main.java
@@ -35,11 +35,14 @@
import java.util.LinkedList;
import java.util.List;
import org.glassfish.grizzly.TransportFactory;
import org.opends.sdk.*;
import org.opends.sdk.controls.ProxiedAuthV2RequestControl;
import org.opends.sdk.requests.*;
import org.opends.sdk.responses.*;
import com.sun.opends.sdk.tools.PerfToolTCPNIOTransportFactory;
/**
@@ -602,6 +605,9 @@
      System.exit(1);
    }
    // Use the same transport factory as the tools.
    TransportFactory.setInstance(new PerfToolTCPNIOTransportFactory());
    // Parse command line arguments.
    final String localAddress = args[0];
    final int localPort = Integer.parseInt(args[1]);
sdk/examples/org/opends/sdk/examples/server/store/Main.java
@@ -39,11 +39,14 @@
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.glassfish.grizzly.TransportFactory;
import org.opends.sdk.*;
import org.opends.sdk.ldif.LDIFEntryReader;
import org.opends.sdk.requests.*;
import org.opends.sdk.responses.*;
import com.sun.opends.sdk.tools.PerfToolTCPNIOTransportFactory;
/**
@@ -488,6 +491,9 @@
      System.exit(1);
    }
    // Use the same transport factory as the tools.
    TransportFactory.setInstance(new PerfToolTCPNIOTransportFactory());
    // Parse command line arguments.
    final String localAddress = args[0];
    final int localPort = Integer.parseInt(args[1]);
sdk/src/com/sun/opends/sdk/ldap/ASN1BufferReader.java
@@ -48,6 +48,8 @@
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.memory.BuffersBuffer;
import org.glassfish.grizzly.memory.CompositeBuffer;
import org.glassfish.grizzly.memory.MemoryManager;
import com.sun.opends.sdk.util.StaticUtils;
@@ -226,13 +228,16 @@
   * @param maxElementSize
   *          The maximum BER element size, or <code>0</code> to indicate that
   *          there is no limit.
   * @param memoryManager
   *          The memory manager to use for buffering.
   */
  ASN1BufferReader(final int maxElementSize)
  ASN1BufferReader(final int maxElementSize,
      final MemoryManager<?> memoryManager)
  {
    this.readLimiter = new RootSequenceLimiter();
    this.stringBuffer = new byte[MAX_STRING_BUFFER_SIZE];
    this.maxElementSize = maxElementSize;
    this.buffer = BuffersBuffer.create();
    this.buffer = BuffersBuffer.create(memoryManager);
  }
sdk/src/com/sun/opends/sdk/ldap/LDAPClientFilter.java
@@ -171,7 +171,8 @@
              {
                // The connection needs to be secured by the SASL
                // mechanism.
                ldapConnection.installFilter(new SASLFilter(l));
                ldapConnection.installFilter(new SASLFilter(l, ctx
                    .getConnection().getTransport().getMemoryManager()));
              }
            }
@@ -601,7 +602,8 @@
        .get(ctx.getConnection());
    if (asn1Reader == null)
    {
      asn1Reader = new ASN1BufferReader(maxASN1ElementSize);
      asn1Reader = new ASN1BufferReader(maxASN1ElementSize, ctx.getConnection()
          .getTransport().getMemoryManager());
      LDAP_ASN1_READER_ATTR.set(ctx.getConnection(), asn1Reader);
    }
    asn1Reader.appendBytesRead(buffer);
sdk/src/com/sun/opends/sdk/ldap/LDAPServerFilter.java
@@ -315,7 +315,8 @@
    @Override
    public void startSASL(final ConnectionSecurityLayer bindContext)
    {
      installFilter(connection, new SASLFilter(bindContext));
      installFilter(connection, new SASLFilter(bindContext, connection
          .getTransport().getMemoryManager()));
    }
@@ -1095,7 +1096,8 @@
        .get(ctx.getConnection());
    if (asn1Reader == null)
    {
      asn1Reader = new ASN1BufferReader(maxASN1ElementSize);
      asn1Reader = new ASN1BufferReader(maxASN1ElementSize, ctx.getConnection()
          .getTransport().getMemoryManager());
      LDAP_ASN1_READER_ATTR.set(ctx.getConnection(), asn1Reader);
    }
    asn1Reader.appendBytesRead(buffer);
sdk/src/com/sun/opends/sdk/ldap/SASLDecoderTransformer.java
@@ -49,20 +49,12 @@
  private final byte[] buffer = new byte[BUFFER_SIZE];
  private final ConnectionSecurityLayer bindContext;
  private final MemoryManager<Buffer> memoryManager;
  @SuppressWarnings("unchecked")
  public SASLDecoderTransformer(final ConnectionSecurityLayer bindContext)
  {
    this(bindContext, TransportFactory.getInstance().getDefaultMemoryManager());
  }
  private final MemoryManager<?> memoryManager;
  public SASLDecoderTransformer(final ConnectionSecurityLayer bindContext,
      final MemoryManager<Buffer> memoryManager)
      final MemoryManager<?> memoryManager)
  {
    this.bindContext = bindContext;
    this.memoryManager = memoryManager;
sdk/src/com/sun/opends/sdk/ldap/SASLEncoderTransformer.java
@@ -49,20 +49,12 @@
  private final byte[] buffer = new byte[BUFFER_SIZE];
  private final ConnectionSecurityLayer bindContext;
  private final MemoryManager<Buffer> memoryManager;
  @SuppressWarnings("unchecked")
  public SASLEncoderTransformer(final ConnectionSecurityLayer bindContext)
  {
    this(bindContext, TransportFactory.getInstance().getDefaultMemoryManager());
  }
  private final MemoryManager<?> memoryManager;
  public SASLEncoderTransformer(final ConnectionSecurityLayer bindContext,
      final MemoryManager<Buffer> memoryManager)
      final MemoryManager<?> memoryManager)
  {
    this.bindContext = bindContext;
    this.memoryManager = memoryManager;
sdk/src/com/sun/opends/sdk/ldap/SASLFilter.java
@@ -33,6 +33,7 @@
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.filterchain.AbstractCodecFilter;
import org.glassfish.grizzly.memory.MemoryManager;
@@ -41,9 +42,10 @@
 */
final class SASLFilter extends AbstractCodecFilter<Buffer, Buffer>
{
  public SASLFilter(final ConnectionSecurityLayer bindContext)
  public SASLFilter(final ConnectionSecurityLayer bindContext,
      final MemoryManager<?> memoryManager)
  {
    super(new SASLDecoderTransformer(bindContext), new SASLEncoderTransformer(
        bindContext));
    super(new SASLDecoderTransformer(bindContext, memoryManager),
        new SASLEncoderTransformer(bindContext, memoryManager));
  }
}
sdk/src/com/sun/opends/sdk/tools/AuthRate.java
@@ -27,13 +27,11 @@
package com.sun.opends.sdk.tools;
import com.sun.opends.sdk.util.RecursiveFutureResult;
import org.glassfish.grizzly.TransportFactory;
import org.opends.sdk.*;
import org.opends.sdk.requests.*;
import org.opends.sdk.responses.BindResult;
import org.opends.sdk.responses.SearchResultEntry;
import static com.sun.opends.sdk.messages.Messages.*;
import static com.sun.opends.sdk.tools.ToolConstants.*;
import static com.sun.opends.sdk.tools.Utils.filterExitCode;
import java.io.InputStream;
import java.io.OutputStream;
@@ -44,28 +42,31 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import static com.sun.opends.sdk.messages.Messages.*;
import static com.sun.opends.sdk.tools.ToolConstants.*;
import static com.sun.opends.sdk.tools.Utils.filterExitCode;
import org.glassfish.grizzly.TransportFactory;
import org.opends.sdk.*;
import org.opends.sdk.requests.*;
import org.opends.sdk.responses.BindResult;
import org.opends.sdk.responses.SearchResultEntry;
import com.sun.opends.sdk.util.RecursiveFutureResult;
/**
 * A load generation tool that can be used to load a Directory Server with
 * Bind requests using one or more LDAP connections.
 * A load generation tool that can be used to load a Directory Server with Bind
 * requests using one or more LDAP connections.
 */
public final class AuthRate extends ConsoleApplication
{
  private final class BindPerformanceRunner extends PerformanceRunner
  {
    private final AtomicLong searchWaitRecentTime = new AtomicLong();
    private final AtomicInteger invalidCredRecentCount = new AtomicInteger();
    private final class BindStatsThread extends StatsThread
    {
      private final String[] extraColumn;
      private BindStatsThread(boolean extraFieldRequired)
      private BindStatsThread(final boolean extraFieldRequired)
      {
        super(extraFieldRequired ? new String[] { "bind time %" }
            : new String[0]);
@@ -93,15 +94,16 @@
    private final class BindUpdateStatsResultHandler extends
        UpdateStatsResultHandler<BindResult>
    {
      private BindUpdateStatsResultHandler(long startTime)
      private BindUpdateStatsResultHandler(final long startTime,
          final AsynchronousConnection connection, final ConnectionWorker worker)
      {
        super(startTime);
        super(startTime, connection, worker);
      }
      @Override
      public void handleErrorResult(ErrorResultException error)
      public void handleErrorResult(final ErrorResultException error)
      {
        super.handleErrorResult(error);
@@ -112,7 +114,9 @@
      }
    }
    private final class BindWorkerThread extends WorkerThread
    private final class BindWorkerThread extends ConnectionWorker
    {
      private SearchRequest sr;
      private BindRequest br;
@@ -122,6 +126,7 @@
      private final ThreadLocal<Random> rng = new ThreadLocal<Random>()
      {
        @Override
        protected Random initialValue()
        {
          return new Random();
@@ -130,6 +135,7 @@
      };
      private BindWorkerThread(final AsynchronousConnection connection,
          final ConnectionFactory connectionFactory)
      {
@@ -146,14 +152,14 @@
        if (dataSources != null)
        {
          data = DataSource.generateData(dataSources, data);
          if(data.length == dataSources.length)
          if (data.length == dataSources.length)
          {
            Object[] newData = new Object[data.length + 1];
            final Object[] newData = new Object[data.length + 1];
            System.arraycopy(data, 0, newData, 0, data.length);
            data = newData;
          }
        }
        if(filter != null && baseDN != null)
        if (filter != null && baseDN != null)
        {
          if (sr == null)
          {
@@ -163,8 +169,8 @@
            }
            else
            {
              sr = Requests.newSearchRequest(String.format(baseDN, data), scope,
                  String.format(filter, data), attributes);
              sr = Requests.newSearchRequest(String.format(baseDN, data),
                  scope, String.format(filter, data), attributes);
            }
            sr.setDereferenceAliasesPolicy(dereferencesAliasesPolicy);
          }
@@ -174,32 +180,32 @@
            sr.setName(String.format(baseDN, data));
          }
          RecursiveFutureResult<SearchResultEntry, BindResult> future =
              new RecursiveFutureResult<SearchResultEntry, BindResult>(
                  new BindUpdateStatsResultHandler(startTime))
          final RecursiveFutureResult<SearchResultEntry, BindResult> future =
            new RecursiveFutureResult<SearchResultEntry, BindResult>(
              new BindUpdateStatsResultHandler(startTime, connection, this))
          {
            @Override
            protected FutureResult<? extends BindResult> chainResult(
                final SearchResultEntry innerResult,
                final ResultHandler<? super BindResult> resultHandler)
                throws ErrorResultException
            {
              searchWaitRecentTime.getAndAdd(System.nanoTime() - startTime);
              if (data == null)
              {
                @Override
                protected FutureResult<? extends BindResult> chainResult(
                    SearchResultEntry innerResult,
                    ResultHandler<? super BindResult> resultHandler)
                    throws ErrorResultException
                {
                  searchWaitRecentTime.getAndAdd(System.nanoTime() - startTime);
                  if(data == null)
                  {
                    data = new Object[1];
                  }
                  data[data.length-1] = innerResult.getName().toString();
                  return performBind(connection, data, resultHandler);
                }
              };
                data = new Object[1];
              }
              data[data.length - 1] = innerResult.getName().toString();
              return performBind(connection, data, resultHandler);
            }
          };
          connection.searchSingleEntry(sr, future);
          return future;
        }
        else
        {
          return performBind(connection, data,
              new BindUpdateStatsResultHandler(startTime));
              new BindUpdateStatsResultHandler(startTime, connection, this));
        }
      }
@@ -229,13 +235,13 @@
        if (bindRequest instanceof SimpleBindRequest)
        {
          SimpleBindRequest o = (SimpleBindRequest) bindRequest;
          final SimpleBindRequest o = (SimpleBindRequest) bindRequest;
          if (br == null)
          {
            br = Requests.copyOfSimpleBindRequest(o);
          }
          SimpleBindRequest sbr = (SimpleBindRequest) br;
          final SimpleBindRequest sbr = (SimpleBindRequest) br;
          if (data != null && o.getName() != null)
          {
            sbr.setName(String.format(o.getName(), data));
@@ -251,13 +257,13 @@
        }
        else if (bindRequest instanceof DigestMD5SASLBindRequest)
        {
          DigestMD5SASLBindRequest o = (DigestMD5SASLBindRequest) bindRequest;
          final DigestMD5SASLBindRequest o = (DigestMD5SASLBindRequest) bindRequest;
          if (br == null)
          {
            br = Requests.copyOfDigestMD5SASLBindRequest(o);
          }
          DigestMD5SASLBindRequest sbr = (DigestMD5SASLBindRequest) br;
          final DigestMD5SASLBindRequest sbr = (DigestMD5SASLBindRequest) br;
          if (data != null)
          {
            if (o.getAuthenticationID() != null)
@@ -281,13 +287,13 @@
        }
        else if (bindRequest instanceof CRAMMD5SASLBindRequest)
        {
          CRAMMD5SASLBindRequest o = (CRAMMD5SASLBindRequest) bindRequest;
          final CRAMMD5SASLBindRequest o = (CRAMMD5SASLBindRequest) bindRequest;
          if (br == null)
          {
            br = Requests.copyOfCRAMMD5SASLBindRequest(o);
          }
          CRAMMD5SASLBindRequest sbr = (CRAMMD5SASLBindRequest) br;
          final CRAMMD5SASLBindRequest sbr = (CRAMMD5SASLBindRequest) br;
          if (data != null && o.getAuthenticationID() != null)
          {
            sbr.setAuthenticationID(String.format(o.getAuthenticationID(), data));
@@ -303,13 +309,13 @@
        }
        else if (bindRequest instanceof GSSAPISASLBindRequest)
        {
          GSSAPISASLBindRequest o = (GSSAPISASLBindRequest) bindRequest;
          final GSSAPISASLBindRequest o = (GSSAPISASLBindRequest) bindRequest;
          if (br == null)
          {
            br = Requests.copyOfGSSAPISASLBindRequest(o);
          }
          GSSAPISASLBindRequest sbr = (GSSAPISASLBindRequest) br;
          final GSSAPISASLBindRequest sbr = (GSSAPISASLBindRequest) br;
          if (data != null)
          {
            if (o.getAuthenticationID() != null)
@@ -333,13 +339,13 @@
        }
        else if (bindRequest instanceof ExternalSASLBindRequest)
        {
          ExternalSASLBindRequest o = (ExternalSASLBindRequest) bindRequest;
          final ExternalSASLBindRequest o = (ExternalSASLBindRequest) bindRequest;
          if (br == null)
          {
            br = Requests.copyOfExternalSASLBindRequest(o);
          }
          ExternalSASLBindRequest sbr = (ExternalSASLBindRequest) br;
          final ExternalSASLBindRequest sbr = (ExternalSASLBindRequest) br;
          if (data != null && o.getAuthorizationID() != null)
          {
            sbr.setAuthorizationID(String.format(o.getAuthorizationID(), data));
@@ -347,13 +353,13 @@
        }
        else if (bindRequest instanceof PlainSASLBindRequest)
        {
          PlainSASLBindRequest o = (PlainSASLBindRequest) bindRequest;
          final PlainSASLBindRequest o = (PlainSASLBindRequest) bindRequest;
          if (br == null)
          {
            br = Requests.copyOfPlainSASLBindRequest(o);
          }
          PlainSASLBindRequest sbr = (PlainSASLBindRequest) br;
          final PlainSASLBindRequest sbr = (PlainSASLBindRequest) br;
          if (data != null)
          {
            if (o.getAuthenticationID() != null)
@@ -382,6 +388,10 @@
    private final AtomicLong searchWaitRecentTime = new AtomicLong();
    private final AtomicInteger invalidCredRecentCount = new AtomicInteger();
    private String filter;
    private String baseDN;
@@ -407,20 +417,24 @@
    @Override
    StatsThread newStatsThread()
    ConnectionWorker newConnectionWorker(
        final AsynchronousConnection connection,
        final ConnectionFactory connectionFactory)
    {
      return new BindStatsThread(filter != null && baseDN != null);
      return new BindWorkerThread(connection, connectionFactory);
    }
    @Override
    WorkerThread newWorkerThread(final AsynchronousConnection connection,
        final ConnectionFactory connectionFactory)
    StatsThread newStatsThread()
    {
      return new BindWorkerThread(connection, connectionFactory);
      return new BindStatsThread(filter != null && baseDN != null);
    }
  }
  /**
   * The main method for AuthRate tool.
   *
@@ -485,7 +499,6 @@
  private AuthRate(final InputStream in, final OutputStream out,
      final OutputStream err)
  {
@@ -583,10 +596,10 @@
  {
    // Create the command-line argument parser for use with this
    // program.
    final LocalizableMessage toolDescription =
        INFO_AUTHRATE_TOOL_DESCRIPTION.get();
    final ArgumentParser argParser = new ArgumentParser(AuthRate.class
        .getName(), toolDescription, false, true, 0, 0,
    final LocalizableMessage toolDescription = INFO_AUTHRATE_TOOL_DESCRIPTION
        .get();
    final ArgumentParser argParser = new ArgumentParser(
        AuthRate.class.getName(), toolDescription, false, true, 0, 0,
        "[filter format string] [attributes ...]");
    ConnectionFactoryProvider connectionFactoryProvider;
@@ -604,8 +617,7 @@
    try
    {
      TransportFactory.setInstance(new PerfToolTCPNIOTransportFactory());
      connectionFactoryProvider =
        new ConnectionFactoryProvider(argParser, this);
      connectionFactoryProvider = new ConnectionFactoryProvider(argParser, this);
      runner = new BindPerformanceRunner(argParser, this);
      propertiesFileArgument = new StringArgument("propertiesFilePath", null,
@@ -627,34 +639,35 @@
      argParser.setUsageArgument(showUsage, getOutputStream());
      baseDN = new StringArgument("baseDN", OPTION_SHORT_BASEDN,
          OPTION_LONG_BASEDN, false, false, true, INFO_BASEDN_PLACEHOLDER.get(),
          null, null, INFO_SEARCHRATE_TOOL_DESCRIPTION_BASEDN.get());
          OPTION_LONG_BASEDN, false, false, true,
          INFO_BASEDN_PLACEHOLDER.get(), null, null,
          INFO_SEARCHRATE_TOOL_DESCRIPTION_BASEDN.get());
      baseDN.setPropertyName(OPTION_LONG_BASEDN);
      argParser.addArgument(baseDN);
      searchScope = new MultiChoiceArgument<SearchScope>("searchScope", 's',
          "searchScope", false, true, INFO_SEARCH_SCOPE_PLACEHOLDER.get(),
          SearchScope.values(), false, INFO_SEARCH_DESCRIPTION_SEARCH_SCOPE
              .get());
          SearchScope.values(), false,
          INFO_SEARCH_DESCRIPTION_SEARCH_SCOPE.get());
      searchScope.setPropertyName("searchScope");
      searchScope.setDefaultValue(SearchScope.WHOLE_SUBTREE);
      argParser.addArgument(searchScope);
      dereferencePolicy = new MultiChoiceArgument<DereferenceAliasesPolicy>(
          "derefpolicy", 'a', "dereferencePolicy", false, true,
          INFO_DEREFERENCE_POLICE_PLACEHOLDER.get(), DereferenceAliasesPolicy
              .values(), false, INFO_SEARCH_DESCRIPTION_DEREFERENCE_POLICY
              .get());
          INFO_DEREFERENCE_POLICE_PLACEHOLDER.get(),
          DereferenceAliasesPolicy.values(), false,
          INFO_SEARCH_DESCRIPTION_DEREFERENCE_POLICY.get());
      dereferencePolicy.setPropertyName("dereferencePolicy");
      dereferencePolicy.setDefaultValue(DereferenceAliasesPolicy.NEVER);
      argParser.addArgument(dereferencePolicy);
      invalidCredPercent = new IntegerArgument("invalidPassword", 'I',
        "invalidPassword", false, false, true, LocalizableMessage
            .raw("{invalidPassword}"), 0, null, true, 0, true, 100,
        LocalizableMessage
            .raw("Percent of bind operations with simulated " +
            "invalid password"));
          "invalidPassword", false, false, true,
          LocalizableMessage.raw("{invalidPassword}"), 0, null, true, 0, true,
          100,
          LocalizableMessage.raw("Percent of bind operations with simulated "
              + "invalid password"));
      invalidCredPercent.setPropertyName("invalidPassword");
      argParser.addArgument(invalidCredPercent);
@@ -688,15 +701,15 @@
        return 0;
      }
      connectionFactory =
          connectionFactoryProvider.getConnectionFactory();
      connectionFactory = connectionFactoryProvider.getConnectionFactory();
      runner.validate();
      runner.bindRequest = connectionFactoryProvider.getBindRequest();
      if(runner.bindRequest == null)
      if (runner.bindRequest == null)
      {
        throw new ArgumentException(LocalizableMessage.raw(
            "Authentication information must be provided to use this tool"));
        throw new ArgumentException(
            LocalizableMessage
                .raw("Authentication information must be provided to use this tool"));
      }
    }
    catch (final ArgumentException ae)
@@ -739,11 +752,11 @@
    // Try it out to make sure the format string and data sources
    // match.
    final Object[] data = DataSource.generateData(runner.getDataSources(),
        null);
    final Object[] data = DataSource
        .generateData(runner.getDataSources(), null);
    try
    {
      if(runner.baseDN != null && runner.filter != null)
      if (runner.baseDN != null && runner.filter != null)
      {
        String.format(runner.filter, data);
        String.format(runner.baseDN, data);
@@ -759,4 +772,3 @@
    return runner.run(connectionFactory);
  }
}
sdk/src/com/sun/opends/sdk/tools/ModRate.java
@@ -52,7 +52,7 @@
{
  private static final class ModifyPerformanceRunner extends PerformanceRunner
  {
    private final class ModifyWorkerThread extends WorkerThread
    private final class ModifyWorkerThread extends ConnectionWorker
    {
      private ModifyRequest mr;
      private Object[] data;
@@ -70,15 +70,15 @@
      @Override
      public FutureResult<?> performOperation(
          final AsynchronousConnection connection,
          final DataSource[] dataSources, long startTime)
          final DataSource[] dataSources, final long startTime)
      {
        if (dataSources != null)
        {
          data = DataSource.generateData(dataSources, data);
        }
        mr = newModifyRequest(data);
        return connection.modify(mr,
            new UpdateStatsResultHandler<Result>(startTime));
        return connection.modify(mr, new UpdateStatsResultHandler<Result>(
            startTime, connection, this));
      }
@@ -109,9 +109,9 @@
          colonPos = formattedString.indexOf(':');
          if (colonPos > 0)
          {
            mr.addModification(ModificationType.REPLACE, formattedString
                .substring(0, colonPos), formattedString
                .substring(colonPos + 1));
            mr.addModification(ModificationType.REPLACE,
                formattedString.substring(0, colonPos),
                formattedString.substring(colonPos + 1));
          }
        }
        return mr;
@@ -135,18 +135,19 @@
    @Override
    StatsThread newStatsThread()
    ConnectionWorker newConnectionWorker(
        final AsynchronousConnection connection,
        final ConnectionFactory connectionFactory)
    {
      return new StatsThread(new String[0]);
      return new ModifyWorkerThread(connection, connectionFactory);
    }
    @Override
    WorkerThread newWorkerThread(final AsynchronousConnection connection,
        final ConnectionFactory connectionFactory)
    StatsThread newStatsThread()
    {
      return new ModifyWorkerThread(connection, connectionFactory);
      return new StatsThread(new String[0]);
    }
  }
@@ -313,8 +314,8 @@
  {
    // Create the command-line argument parser for use with this
    // program.
    final LocalizableMessage toolDescription =
        INFO_MODRATE_TOOL_DESCRIPTION.get();
    final LocalizableMessage toolDescription = INFO_MODRATE_TOOL_DESCRIPTION
        .get();
    final ArgumentParser argParser = new ArgumentParser(
        ModRate.class.getName(), toolDescription, false, true, 1, 0,
        "[(attribute:value format string) ...]");
@@ -330,8 +331,7 @@
    try
    {
      TransportFactory.setInstance(new PerfToolTCPNIOTransportFactory());
      connectionFactoryProvider =
          new ConnectionFactoryProvider(argParser, this);
      connectionFactoryProvider = new ConnectionFactoryProvider(argParser, this);
      runner = new ModifyPerformanceRunner(argParser, this);
      propertiesFileArgument = new StringArgument("propertiesFilePath", null,
          OPTION_LONG_PROP_FILE_PATH, false, false, true,
@@ -347,8 +347,9 @@
      argParser.setNoPropertiesFileArgument(noPropertiesFileArgument);
      baseDN = new StringArgument("targetDN", OPTION_SHORT_BASEDN,
          OPTION_LONG_TARGETDN, true, false, true, INFO_TARGETDN_PLACEHOLDER.get(),
          null, null, INFO_MODRATE_TOOL_DESCRIPTION_TARGETDN.get());
          OPTION_LONG_TARGETDN, true, false, true,
          INFO_TARGETDN_PLACEHOLDER.get(), null, null,
          INFO_MODRATE_TOOL_DESCRIPTION_TARGETDN.get());
      baseDN.setPropertyName(OPTION_LONG_BASEDN);
      argParser.addArgument(baseDN);
@@ -387,8 +388,8 @@
        return 0;
      }
      connectionFactory =
          connectionFactoryProvider.getAuthenticatedConnectionFactory();
      connectionFactory = connectionFactoryProvider
          .getAuthenticatedConnectionFactory();
      runner.validate();
    }
    catch (final ArgumentException ae)
sdk/src/com/sun/opends/sdk/tools/PerfToolTCPNIOTransportFactory.java
@@ -46,7 +46,8 @@
/**
 * The TCPNIOTransportFactory which performance tools will use.
 */
final class PerfToolTCPNIOTransportFactory extends DefaultNIOTransportFactory
public final class PerfToolTCPNIOTransportFactory extends
    DefaultNIOTransportFactory
{
  private int selectors;
@@ -115,7 +116,7 @@
    }
    final String selectorsStr = System
        .getProperty("org.opends.sdk.ldap.transport.selectors");
    if (threadsStr != null)
    if (selectorsStr != null)
    {
      selectors = Integer.parseInt(selectorsStr);
    }
sdk/src/com/sun/opends/sdk/tools/PerformanceRunner.java
@@ -33,16 +33,18 @@
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import com.sun.opends.sdk.util.StaticUtils;
import org.opends.sdk.*;
import org.opends.sdk.responses.BindResult;
import org.opends.sdk.responses.ExtendedResult;
import org.opends.sdk.responses.Result;
import com.sun.opends.sdk.tools.AuthenticatedConnectionFactory.AuthenticatedAsynchronousConnection;
import com.sun.opends.sdk.util.StaticUtils;
@@ -51,6 +53,170 @@
 */
abstract class PerformanceRunner implements ConnectionEventListener
{
  abstract class ConnectionWorker
  {
    private final AtomicInteger operationsInFlight = new AtomicInteger();
    private volatile int count;
    private final AsynchronousConnection staticConnection;
    private final ConnectionFactory connectionFactory;
    private final CountDownLatch latch = new CountDownLatch(1);
    ConnectionWorker(final AsynchronousConnection staticConnection,
        final ConnectionFactory connectionFactory)
    {
      this.staticConnection = staticConnection;
      this.connectionFactory = connectionFactory;
    }
    public void operationCompleted(final AsynchronousConnection connection)
    {
      if (operationsInFlight.decrementAndGet() == 0
          && this.staticConnection == null)
      {
        connection.close();
      }
      startWork();
    }
    public abstract FutureResult<?> performOperation(
        final AsynchronousConnection connection,
        final DataSource[] dataSources, final long startTime);
    public void startWork()
    {
      if (!stopRequested && !(maxIterations > 0 && count >= maxIterations))
      {
        if (this.staticConnection == null)
        {
          connectionFactory
              .getAsynchronousConnection(new ResultHandler<AsynchronousConnection>()
              {
                public void handleErrorResult(final ErrorResultException e)
                {
                  app.println(LocalizableMessage.raw(e.getResult()
                      .getDiagnosticMessage()));
                  if (e.getCause() != null && app.isVerbose())
                  {
                    e.getCause().printStackTrace(app.getErrorStream());
                  }
                  stopRequested = true;
                }
                public void handleResult(final AsynchronousConnection result)
                {
                  doWork(result);
                }
              });
        }
        else
        {
          if (!noRebind
              && this.staticConnection instanceof AuthenticatedAsynchronousConnection)
          {
            final AuthenticatedAsynchronousConnection ac =
              (AuthenticatedAsynchronousConnection) this.staticConnection;
            ac.rebind(new ResultHandler<BindResult>()
            {
              public void handleErrorResult(final ErrorResultException e)
              {
                app.println(LocalizableMessage.raw(e.getResult().toString()));
                if (e.getCause() != null && app.isVerbose())
                {
                  e.getCause().printStackTrace(app.getErrorStream());
                }
                stopRequested = true;
              }
              public void handleResult(final BindResult result)
              {
                doWork(staticConnection);
              }
            });
          }
          else
          {
            doWork(staticConnection);
          }
        }
      }
      else
      {
        latch.countDown();
      }
    }
    public void waitFor() throws InterruptedException
    {
      latch.await();
    }
    private void doWork(final AsynchronousConnection connection)
    {
      long start;
      double sleepTimeInMS = 0;
      final int opsToPerform = isAsync ? numConcurrentTasks : numConcurrentTasks
          - operationsInFlight.get();
      for (int i = 0; i < opsToPerform; i++)
      {
        if (maxIterations > 0 && count >= maxIterations)
        {
          break;
        }
        start = System.nanoTime();
        performOperation(connection, dataSources.get(), start);
        operationRecentCount.getAndIncrement();
        operationsInFlight.getAndIncrement();
        count++;
        if (targetThroughput > 0)
        {
          try
          {
            if (sleepTimeInMS > 1)
            {
              Thread.sleep((long) Math.floor(sleepTimeInMS));
            }
          }
          catch (final InterruptedException e)
          {
            continue;
          }
          sleepTimeInMS += targetTimeInMS
              - ((System.nanoTime() - start) / 1000000.0);
          if (sleepTimeInMS < -60000)
          {
            // If we fall behind by 60 seconds, just forget about
            // catching up
            sleepTimeInMS = -60000;
          }
        }
      }
    }
  }
  /**
   * Statistics thread base implementation.
   */
@@ -263,8 +429,8 @@
        if (resultCount > 0)
        {
          strings[2] = String.format("%.3f",
              (waitTime - (gcDuration - lastGCDuration))
                  / (double) resultCount / 1000000.0);
              (waitTime - (gcDuration - lastGCDuration)) / (double) resultCount
                  / 1000000.0);
        }
        else
        {
@@ -370,7 +536,7 @@
        {
          // Script-friendly.
          app.getOutputStream().print(averageDuration);
          for (String s : strings)
          for (final String s : strings)
          {
            app.getOutputStream().print(",");
            app.getOutputStream().print(s);
@@ -399,12 +565,17 @@
  class UpdateStatsResultHandler<S extends Result> implements ResultHandler<S>
  {
    private final long startTime;
    private final AsynchronousConnection connection;
    private final ConnectionWorker worker;
    UpdateStatsResultHandler(final long startTime)
    UpdateStatsResultHandler(final long startTime,
        final AsynchronousConnection connection, final ConnectionWorker worker)
    {
      this.startTime = startTime;
      this.connection = connection;
      this.worker = worker;
    }
@@ -418,6 +589,8 @@
      {
        app.println(LocalizableMessage.raw(error.getResult().toString()));
      }
      worker.operationCompleted(connection);
    }
@@ -426,6 +599,7 @@
    {
      successRecentCount.getAndIncrement();
      updateStats();
      worker.operationCompleted(connection);
    }
@@ -487,8 +661,7 @@
      AsynchronousConnection connection;
      final double targetTimeInMS =
        (1.0 / (targetThroughput /
            (double) (numThreads * numConnections))) * 1000.0;
        (1.0 / (targetThroughput / (double) (numConcurrentTasks * numConnections))) * 1000.0;
      double sleepTimeInMS = 0;
      long start;
      while (!stopRequested && !(maxIterations > 0 && count >= maxIterations))
@@ -797,20 +970,20 @@
  private final AtomicLong waitRecentTime = new AtomicLong();
  private final AtomicReference<ReversableArray> eTimeBuffer =
    new AtomicReference<ReversableArray>(new ReversableArray(100000));
  private final AtomicReference<ReversableArray> eTimeBuffer = new AtomicReference<ReversableArray>(
      new ReversableArray(100000));
  private final ConsoleApplication app;
  private DataSource[] dataSourcePrototypes;
  // Thread local copies of the data sources
  private final ThreadLocal<DataSource[]> dataSources =
    new ThreadLocal<DataSource[]>()
  private final ThreadLocal<DataSource[]> dataSources = new ThreadLocal<DataSource[]>()
  {
    /**
     * {@inheritDoc}
     */
    @Override
    protected DataSource[] initialValue()
    {
      final DataSource[] prototypes = getDataSources();
@@ -827,7 +1000,7 @@
  private volatile boolean stopRequested;
  private int numThreads;
  private int numConcurrentTasks;
  private int numConnections;
@@ -841,7 +1014,9 @@
  private int statsInterval;
  private final IntegerArgument numThreadsArgument;
  private double targetTimeInMS;
  private final IntegerArgument numConcurrentTasksArgument;
  private final IntegerArgument maxIterationsArgument;
@@ -864,52 +1039,52 @@
  PerformanceRunner(final ArgumentParser argParser,
                    final ConsoleApplication app,
                    boolean neverRebind, boolean neverAsynchronous,
                    boolean alwaysSingleThreaded)
      final ConsoleApplication app, final boolean neverRebind,
      final boolean neverAsynchronous, final boolean alwaysSingleThreaded)
      throws ArgumentException
  {
    this.app = app;
    numThreadsArgument = new IntegerArgument("numThreads", 't', "numThreads",
        false, false, true, LocalizableMessage.raw("{numThreads}"), 1, null,
        true, 1, false, 0, LocalizableMessage
            .raw("Number of worker threads per connection"));
    numThreadsArgument.setPropertyName("numThreads");
    if(!alwaysSingleThreaded)
    numConcurrentTasksArgument = new IntegerArgument("numConcurrentTasks", 't',
        "numConcurrentTasks", false, false, true,
        LocalizableMessage.raw("{numConcurrentTasks}"), 1, null, true, 1,
        false, 0,
        LocalizableMessage.raw("Number of concurrent tasks per connection"));
    numConcurrentTasksArgument.setPropertyName("numConcurrentTasks");
    if (!alwaysSingleThreaded)
    {
      argParser.addArgument(numThreadsArgument);
      argParser.addArgument(numConcurrentTasksArgument);
    }
    else
    {
      numThreadsArgument.addValue("1");
      numConcurrentTasksArgument.addValue("1");
    }
    numConnectionsArgument = new IntegerArgument("numConnections", 'c',
        "numConnections", false, false, true, LocalizableMessage
            .raw("{numConnections}"), 1, null, true, 1, false, 0,
        "numConnections", false, false, true,
        LocalizableMessage.raw("{numConnections}"), 1, null, true, 1, false, 0,
        LocalizableMessage.raw("Number of connections"));
    numConnectionsArgument.setPropertyName("numConnections");
    argParser.addArgument(numConnectionsArgument);
    maxIterationsArgument = new IntegerArgument("maxIterations", 'm',
        "maxIterations", false, false, true, LocalizableMessage
            .raw("{maxIterations}"), 0, null, LocalizableMessage
            .raw("Max iterations, 0 for unlimited"));
        "maxIterations", false, false, true,
        LocalizableMessage.raw("{maxIterations}"), 0, null,
        LocalizableMessage.raw("Max iterations, 0 for unlimited"));
    maxIterationsArgument.setPropertyName("maxIterations");
    argParser.addArgument(maxIterationsArgument);
    statsIntervalArgument = new IntegerArgument("statInterval", 'i',
        "statInterval", false, false, true, LocalizableMessage
            .raw("{statInterval}"), 5, null, true, 1, false, 0,
        "statInterval", false, false, true,
        LocalizableMessage.raw("{statInterval}"), 5, null, true, 1, false, 0,
        LocalizableMessage
            .raw("Display results each specified number of seconds"));
    statsIntervalArgument.setPropertyName("statInterval");
    argParser.addArgument(statsIntervalArgument);
    targetThroughputArgument = new IntegerArgument("targetThroughput", 'M',
        "targetThroughput", false, false, true, LocalizableMessage
            .raw("{targetThroughput}"), 0, null, LocalizableMessage
            .raw("Target average throughput to achieve"));
        "targetThroughput", false, false, true,
        LocalizableMessage.raw("{targetThroughput}"), 0, null,
        LocalizableMessage.raw("Target average throughput to achieve"));
    targetThroughputArgument.setPropertyName("targetThroughput");
    argParser.addArgument(targetThroughputArgument);
@@ -929,7 +1104,7 @@
    noRebindArgument = new BooleanArgument("noRebind", 'F', "noRebind",
        LocalizableMessage.raw("Keep connections open and don't rebind"));
    noRebindArgument.setPropertyName("noRebind");
    if(!neverRebind)
    if (!neverRebind)
    {
      argParser.addArgument(noRebindArgument);
    }
@@ -939,24 +1114,30 @@
    }
    asyncArgument = new BooleanArgument("asynchronous", 'A', "asynchronous",
        LocalizableMessage.raw("Use asynchronous mode and don't " +
            "wait for results before sending the next request"));
        LocalizableMessage.raw("Use asynchronous mode and don't "
            + "wait for results before sending the next request"));
    asyncArgument.setPropertyName("asynchronous");
    if(!neverAsynchronous)
    if (!neverAsynchronous)
    {
      argParser.addArgument(asyncArgument);
    }
    arguments = new StringArgument("argument", 'g', "argument", false, true,
        true, LocalizableMessage.raw("{generator function or static string}"),
        null, null,
        LocalizableMessage.raw("Argument used to evaluate the Java " +
            "style format strings in program parameters (ie. Base DN, " +
            "Search Filter). The set of all arguments provided form the " +
            "the argument list in order. Besides static string " +
            "arguments, they can be generated per iteration with the " +
            "following functions: " + StaticUtils.EOL +
            DataSource.getUsage()));
    arguments = new StringArgument(
        "argument",
        'g',
        "argument",
        false,
        true,
        true,
        LocalizableMessage.raw("{generator function or static string}"),
        null,
        null,
        LocalizableMessage.raw("Argument used to evaluate the Java "
            + "style format strings in program parameters (ie. Base DN, "
            + "Search Filter). The set of all arguments provided form the "
            + "the argument list in order. Besides static string "
            + "arguments, they can be generated per iteration with the "
            + "following functions: " + StaticUtils.EOL + DataSource.getUsage()));
    argParser.addArgument(arguments);
  }
@@ -986,8 +1167,7 @@
  public void handleUnsolicitedNotification(
      final ExtendedResult notification)
  public void handleUnsolicitedNotification(final ExtendedResult notification)
  {
    // Ignore
  }
@@ -997,20 +1177,19 @@
  public final void validate() throws ArgumentException
  {
    numConnections = numConnectionsArgument.getIntValue();
    numThreads = numThreadsArgument.getIntValue();
    maxIterations = maxIterationsArgument.getIntValue() /
        numConnections / numThreads;
    numConcurrentTasks = numConcurrentTasksArgument.getIntValue();
    maxIterations = maxIterationsArgument.getIntValue() / numConnections;
    statsInterval = statsIntervalArgument.getIntValue() * 1000;
    targetThroughput = targetThroughputArgument.getIntValue();
    isAsync = asyncArgument.isPresent();
    noRebind = noRebindArgument.isPresent();
    if (!noRebindArgument.isPresent() && this.numThreads > 1)
    if (!noRebindArgument.isPresent() && this.numConcurrentTasks > 1)
    {
      throw new ArgumentException(LocalizableMessage.raw("--"
          + noRebindArgument.getLongIdentifier() + " must be used if --"
          + numThreadsArgument.getLongIdentifier() + " is > 1"));
          + numConcurrentTasksArgument.getLongIdentifier() + " is > 1"));
    }
    if (!noRebindArgument.isPresent() && asyncArgument.isPresent())
@@ -1021,6 +1200,9 @@
    }
    dataSourcePrototypes = DataSource.parse(arguments.getValues());
    targetTimeInMS =
      (1.0 / (targetThroughput / (double) (numConcurrentTasks * numConnections))) * 1000.0;
  }
@@ -1037,22 +1219,22 @@
  abstract ConnectionWorker newConnectionWorker(
      final AsynchronousConnection connection,
      final ConnectionFactory connectionFactory);
  abstract StatsThread newStatsThread();
  abstract WorkerThread newWorkerThread(AsynchronousConnection connection,
      ConnectionFactory connectionFactory);
  final int run(final ConnectionFactory connectionFactory)
  {
    final List<Thread> threads = new ArrayList<Thread>();
    final List<ConnectionWorker> workers = new ArrayList<ConnectionWorker>();
    final List<AsynchronousConnection> connections = new ArrayList<AsynchronousConnection>();
    AsynchronousConnection connection = null;
    Thread thread;
    try
    {
      for (int i = 0; i < numConnections; i++)
@@ -1063,21 +1245,18 @@
          connection.addConnectionEventListener(this);
          connections.add(connection);
        }
        for (int j = 0; j < numThreads; j++)
        {
          thread = newWorkerThread(connection, connectionFactory);
          threads.add(thread);
          thread.start();
        }
        final ConnectionWorker worker = newConnectionWorker(connection,
            connectionFactory);
        workers.add(worker);
        worker.startWork();
      }
      final Thread statsThread = newStatsThread();
      statsThread.start();
      for (final Thread t : threads)
      for (final ConnectionWorker w : workers)
      {
        t.join();
        w.waitFor();
      }
      stopRequested = true;
      statsThread.join();
sdk/src/com/sun/opends/sdk/tools/SearchRate.java
@@ -61,13 +61,15 @@
    private final class SearchStatsHandler extends
        UpdateStatsResultHandler<Result> implements SearchResultHandler
    {
      private SearchStatsHandler(final long startTime)
      private SearchStatsHandler(final long startTime,
          final AsynchronousConnection connection, final ConnectionWorker worker)
      {
        super(startTime);
        super(startTime, connection, worker);
      }
      @Override
      public boolean handleEntry(final SearchResultEntry entry)
      {
        entryRecentCount.getAndIncrement();
@@ -76,6 +78,7 @@
      @Override
      public boolean handleReference(final SearchResultReference reference)
      {
        return true;
@@ -117,7 +120,7 @@
    private final class SearchWorkerThread extends WorkerThread
    private final class SearchWorkerThread extends ConnectionWorker
    {
      private SearchRequest sr;
@@ -158,7 +161,8 @@
          sr.setFilter(String.format(filter, data));
          sr.setName(String.format(baseDN, data));
        }
        return connection.search(sr, new SearchStatsHandler(startTime));
        return connection.search(sr, new SearchStatsHandler(startTime,
            connection, this));
      }
    }
@@ -185,18 +189,19 @@
    @Override
    StatsThread newStatsThread()
    ConnectionWorker newConnectionWorker(
        final AsynchronousConnection connection,
        final ConnectionFactory connectionFactory)
    {
      return new SearchStatsThread();
      return new SearchWorkerThread(connection, connectionFactory);
    }
    @Override
    WorkerThread newWorkerThread(final AsynchronousConnection connection,
        final ConnectionFactory connectionFactory)
    StatsThread newStatsThread()
    {
      return new SearchWorkerThread(connection, connectionFactory);
      return new SearchStatsThread();
    }
  }
@@ -365,10 +370,10 @@
  {
    // Create the command-line argument parser for use with this
    // program.
    final LocalizableMessage toolDescription =
        INFO_SEARCHRATE_TOOL_DESCRIPTION.get();
    final ArgumentParser argParser = new ArgumentParser(SearchRate.class
        .getName(), toolDescription, false, true, 1, 0,
    final LocalizableMessage toolDescription = INFO_SEARCHRATE_TOOL_DESCRIPTION
        .get();
    final ArgumentParser argParser = new ArgumentParser(
        SearchRate.class.getName(), toolDescription, false, true, 1, 0,
        "[filter format string] [attributes ...]");
    ConnectionFactoryProvider connectionFactoryProvider;
@@ -385,8 +390,7 @@
    try
    {
      TransportFactory.setInstance(new PerfToolTCPNIOTransportFactory());
      connectionFactoryProvider =
          new ConnectionFactoryProvider(argParser, this);
      connectionFactoryProvider = new ConnectionFactoryProvider(argParser, this);
      runner = new SearchPerformanceRunner(argParser, this);
      propertiesFileArgument = new StringArgument("propertiesFilePath", null,
@@ -415,17 +419,17 @@
      searchScope = new MultiChoiceArgument<SearchScope>("searchScope", 's',
          "searchScope", false, true, INFO_SEARCH_SCOPE_PLACEHOLDER.get(),
          SearchScope.values(), false, INFO_SEARCH_DESCRIPTION_SEARCH_SCOPE
              .get());
          SearchScope.values(), false,
          INFO_SEARCH_DESCRIPTION_SEARCH_SCOPE.get());
      searchScope.setPropertyName("searchScope");
      searchScope.setDefaultValue(SearchScope.WHOLE_SUBTREE);
      argParser.addArgument(searchScope);
      dereferencePolicy = new MultiChoiceArgument<DereferenceAliasesPolicy>(
          "derefpolicy", 'a', "dereferencePolicy", false, true,
          INFO_DEREFERENCE_POLICE_PLACEHOLDER.get(), DereferenceAliasesPolicy
              .values(), false, INFO_SEARCH_DESCRIPTION_DEREFERENCE_POLICY
              .get());
          INFO_DEREFERENCE_POLICE_PLACEHOLDER.get(),
          DereferenceAliasesPolicy.values(), false,
          INFO_SEARCH_DESCRIPTION_DEREFERENCE_POLICY.get());
      dereferencePolicy.setPropertyName("dereferencePolicy");
      dereferencePolicy.setDefaultValue(DereferenceAliasesPolicy.NEVER);
      argParser.addArgument(dereferencePolicy);
@@ -460,8 +464,8 @@
        return 0;
      }
      connectionFactory =
          connectionFactoryProvider.getAuthenticatedConnectionFactory();
      connectionFactory = connectionFactoryProvider
          .getAuthenticatedConnectionFactory();
      runner.validate();
    }
    catch (final ArgumentException ae)
sdk/src/org/opends/sdk/AVA.java
@@ -32,6 +32,8 @@
import static com.sun.opends.sdk.messages.Messages.*;
import static com.sun.opends.sdk.util.StaticUtils.*;
import java.util.Comparator;
import org.opends.sdk.schema.*;
import com.sun.opends.sdk.util.StaticUtils;
@@ -105,8 +107,8 @@
    }
    catch (final UnknownSchemaElementException e)
    {
      final LocalizableMessage message = ERR_RDN_TYPE_NOT_FOUND.get(ava, e
          .getMessageObject());
      final LocalizableMessage message = ERR_RDN_TYPE_NOT_FOUND.get(ava,
          e.getMessageObject());
      throw new LocalizedIllegalArgumentException(message);
    }
  }
@@ -138,8 +140,8 @@
    char c;
    if ((c = reader.read()) != '=')
    {
      final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_NO_EQUAL.get(reader
          .getString(), attribute.getNameOrOID(), c);
      final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_NO_EQUAL.get(
          reader.getString(), attribute.getNameOrOID(), c);
      throw new LocalizedIllegalArgumentException(message);
    }
@@ -665,6 +667,12 @@
  private final ByteString attributeValue;
  // Cached normalized value using equality matching rule.
  private ByteString equalityNormalizedAttributeValue = null;
  // Cached normalized value using ordering matching rule.
  private ByteString orderingNormalizedAttributeValue = null;
  /**
@@ -676,8 +684,8 @@
   * @param attributeValue
   *          The attribute value.
   * @throws NullPointerException
   *           If {@code attributeType} or {@code attributeValue} was {@code
   *           null}.
   *           If {@code attributeType} or {@code attributeValue} was
   *           {@code null}.
   */
  public AVA(final AttributeType attributeType, final ByteString attributeValue)
      throws NullPointerException
@@ -704,8 +712,8 @@
   * @throws UnknownSchemaElementException
   *           If {@code attributeType} was not found in the default schema.
   * @throws NullPointerException
   *           If {@code attributeType} or {@code attributeValue} was {@code
   *           null}.
   *           If {@code attributeType} or {@code attributeValue} was
   *           {@code null}.
   */
  public AVA(final String attributeType, final Object attributeValue)
      throws UnknownSchemaElementException, NullPointerException
@@ -722,55 +730,27 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public int compareTo(final AVA ava)
  {
    int result = attributeType.compareTo(ava.attributeType);
    final int result = attributeType.compareTo(ava.attributeType);
    if (result != 0)
    {
      return result > 0 ? 1 : -1;
    }
    final ByteString normalizedValue = getNormalizeValue();
    final ByteString normalizedValue = getOrderingNormalizedValue();
    final ByteString otherNormalizedValue = ava.getOrderingNormalizedValue();
    final MatchingRule rule = attributeType.getOrderingMatchingRule();
    try
    if (rule != null)
    {
      if (rule != null)
      {
        // Check equality assertion first.
        final Assertion lteAssertion = rule
            .getLessOrEqualAssertion(ava.attributeValue);
        final ConditionResult lteResult = lteAssertion.matches(normalizedValue);
        final Assertion gteAssertion = rule
            .getGreaterOrEqualAssertion(ava.attributeValue);
        final ConditionResult gteResult = gteAssertion.matches(normalizedValue);
        if (lteResult.equals(gteResult))
        {
          // it is equal to the assertion value.
          return 0;
        }
        else if (lteResult == ConditionResult.TRUE)
        {
          return -1;
        }
        else
        {
          return 1;
        }
      }
      final Comparator<ByteSequence> comparator = rule.comparator();
      return comparator.compare(normalizedValue, otherNormalizedValue);
    }
    catch (final DecodeException de)
    else
    {
      // use the bytestring comparison as default.
      return normalizedValue.compareTo(otherNormalizedValue);
    }
    if (result == 0)
    {
      final ByteString nv1 = normalizedValue;
      final ByteString nv2 = ava.getNormalizeValue();
      result = nv1.compareTo(nv2);
    }
    return result;
  }
@@ -787,7 +767,26 @@
    }
    else if (obj instanceof AVA)
    {
      return compareTo((AVA) obj) == 0;
      final AVA ava = (AVA) obj;
      if (!attributeType.equals(ava.attributeType))
      {
        return false;
      }
      final ByteString normalizedValue = getEqualityNormalizedValue();
      final ByteString otherNormalizedValue = ava.getEqualityNormalizedValue();
      final MatchingRule rule = attributeType.getEqualityMatchingRule();
      if (rule != null)
      {
        final Comparator<ByteSequence> comparator = rule.comparator();
        return comparator.compare(normalizedValue, otherNormalizedValue) != 0 ? false
            : true;
      }
      else
      {
        return normalizedValue.equals(otherNormalizedValue);
      }
    }
    else
    {
@@ -827,7 +826,8 @@
  @Override
  public int hashCode()
  {
    return attributeType.hashCode() * 31 + getNormalizeValue().hashCode();
    return attributeType.hashCode() * 31
        + getEqualityNormalizedValue().hashCode();
  }
@@ -844,25 +844,6 @@
  private ByteString getNormalizeValue()
  {
    final MatchingRule matchingRule = attributeType.getEqualityMatchingRule();
    if (matchingRule != null)
    {
      try
      {
        return matchingRule.normalizeAttributeValue(attributeValue);
      }
      catch (final DecodeException de)
      {
        // Ignore - we'll drop back to the user provided value.
      }
    }
    return attributeValue;
  }
  StringBuilder toString(final StringBuilder builder)
  {
    if (!attributeType.getNames().iterator().hasNext())
@@ -925,4 +906,72 @@
    }
    return builder;
  }
  private ByteString getEqualityNormalizedValue()
  {
    final ByteString normalizedValue = equalityNormalizedAttributeValue;
    if (normalizedValue != null)
    {
      return normalizedValue;
    }
    final MatchingRule matchingRule = attributeType.getEqualityMatchingRule();
    if (matchingRule != null)
    {
      try
      {
        equalityNormalizedAttributeValue = matchingRule
            .normalizeAttributeValue(attributeValue);
      }
      catch (final DecodeException de)
      {
        // Unable to normalize, so default to byte-wise comparison.
        equalityNormalizedAttributeValue = attributeValue;
      }
    }
    else
    {
      // No matching rule, so default to byte-wise comparison.
      equalityNormalizedAttributeValue = attributeValue;
    }
    return equalityNormalizedAttributeValue;
  }
  private ByteString getOrderingNormalizedValue()
  {
    final ByteString normalizedValue = orderingNormalizedAttributeValue;
    if (normalizedValue != null)
    {
      return normalizedValue;
    }
    final MatchingRule matchingRule = attributeType.getEqualityMatchingRule();
    if (matchingRule != null)
    {
      try
      {
        orderingNormalizedAttributeValue = matchingRule
            .normalizeAttributeValue(attributeValue);
      }
      catch (final DecodeException de)
      {
        // Unable to normalize, so default to equality matching.
        orderingNormalizedAttributeValue = getEqualityNormalizedValue();
      }
    }
    else
    {
      // No matching rule, so default to equality matching.
      orderingNormalizedAttributeValue = getEqualityNormalizedValue();
    }
    return orderingNormalizedAttributeValue;
  }
}
sdk/tests/unit-tests-testng/src/com/sun/opends/sdk/ldap/ASN1BufferReaderTestCase.java
@@ -35,6 +35,7 @@
import org.opends.sdk.asn1.ASN1Reader;
import org.opends.sdk.asn1.ASN1ReaderTestCase;
import org.glassfish.grizzly.TransportFactory;
import org.glassfish.grizzly.memory.ByteBufferWrapper;
@@ -49,7 +50,8 @@
      throws IOException
  {
    final ByteBufferWrapper buffer = new ByteBufferWrapper(ByteBuffer.wrap(b));
    final ASN1BufferReader reader = new ASN1BufferReader(maxElementSize);
    final ASN1BufferReader reader = new ASN1BufferReader(maxElementSize,
        TransportFactory.getInstance().getDefaultMemoryManager());
    reader.appendBytesRead(buffer);
    return reader;
  }
sdk/tests/unit-tests-testng/src/com/sun/opends/sdk/ldap/ASN1BufferWriterTestCase.java
@@ -38,6 +38,7 @@
import org.opends.sdk.asn1.ASN1WriterTestCase;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.TransportFactory;
import org.glassfish.grizzly.memory.ByteBufferWrapper;
@@ -68,7 +69,8 @@
      throws DecodeException, IOException
  {
    final ByteBufferWrapper buffer = new ByteBufferWrapper(ByteBuffer.wrap(encodedBytes));
    final ASN1BufferReader reader = new ASN1BufferReader(0);
    final ASN1BufferReader reader = new ASN1BufferReader(0, TransportFactory
        .getInstance().getDefaultMemoryManager());
    reader.appendBytesRead(buffer);
    return reader;
  }