From ea900ba71bf5eb5e4126583e1852c6982f9ce5a7 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Tue, 14 Oct 2014 15:44:44 +0000
Subject: [PATCH] (CR-4811) Converted opendj3 code to use SearchRequest like API

---
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExtensionTestUtils.java                                     |   90 -
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/GoverningStructureRuleVirtualAttributeProviderTestCase.java |   45 
 opendj3-server-dev/src/server/org/opends/server/protocols/internal/Requests.java                                                               |  169 +++
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/crypto/CryptoManagerTestCase.java                                      |   26 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java                             |   17 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperationTestCase.java                   |   23 
 opendj3-server-dev/src/server/org/opends/server/admin/AdministrationDataSync.java                                                              |   43 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java                                   |   54 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/tasks/TasksTestCase.java                                               |   11 
 opendj3-server-dev/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java                                                   |   20 
 opendj3-server-dev/src/server/org/opends/server/extensions/DynamicGroupSearchThread.java                                                       |   43 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProviderTestCase.java      |   94 -
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/ChangelogBackendTestCase.java                                 |   58 
 opendj3-server-dev/src/server/org/opends/server/protocols/internal/InternalClientConnection.java                                               |  379 ------
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntityTagVirtualAttributeProviderTestCase.java              |   12 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalSearchOperationTestCase.java                |   72 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java                   |    5 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java                      |   11 
 opendj3-server-dev/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java                               |   20 
 opendj3-server-dev/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java                                                  |  104 -
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProviderTestCase.java        |  115 -
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordExpirationTimeVirtualAttributeProviderTestCase.java |   41 
 opendj3-server-dev/src/server/org/opends/server/extensions/RegularExpressionIdentityMapper.java                                                |   20 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java               |   86 -
 opendj3-server-dev/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java                                      |   18 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java                                    |   50 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/controls/PersistentSearchControlTest.java                              |   26 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/StructuralObjectClassVirtualAttributeProviderTestCase.java  |   43 
 opendj3-server-dev/src/server/org/opends/server/protocols/internal/AbstractRequestImpl.java                                                    |  132 ++
 opendj3-server-dev/src/server/org/opends/server/crypto/CryptoManagerImpl.java                                                                  |   97 -
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProviderTestCase.java                |   75 -
 opendj3-server-dev/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java                                                        |   18 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java                                      |   86 -
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java                        |   12 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/InitOnLineTest.java                                        |   10 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProviderTestCase.java        |   54 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java                            |    7 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java                                  |   84 -
 opendj3-server-dev/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java                                                       |   20 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProviderTestCase.java            |   79 -
 opendj3-server-dev/src/server/org/opends/server/plugins/UniqueAttributePlugin.java                                                             |   16 
 opendj3-server-dev/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java                                           |   22 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProviderTestCase.java              |   31 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/BackendConfigManagerTestCase.java                                 |   63 
 opendj3-server-dev/src/server/org/opends/server/authorization/dseecompat/UserAttr.java                                                         |   32 
 opendj3-server-dev/src/server/org/opends/server/config/JMXMBean.java                                                                           |  132 +-
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java                                      |  104 -
 opendj3-server-dev/src/server/org/opends/server/protocols/internal/SearchRequest.java                                                          |  358 ++++++
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/ResourceLimitsPolicyTest.java                       |   26 
 opendj3-server-dev/src/server/org/opends/server/replication/plugin/PersistentServerState.java                                                  |   24 
 50 files changed, 1,414 insertions(+), 1,763 deletions(-)

diff --git a/opendj3-server-dev/src/server/org/opends/server/admin/AdministrationDataSync.java b/opendj3-server-dev/src/server/org/opends/server/admin/AdministrationDataSync.java
index f1627cb..b70a0a0 100644
--- a/opendj3-server-dev/src/server/org/opends/server/admin/AdministrationDataSync.java
+++ b/opendj3-server-dev/src/server/org/opends/server/admin/AdministrationDataSync.java
@@ -26,26 +26,23 @@
  */
 package org.opends.server.admin;
 
-import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 
-import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.ModificationType;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.protocols.ldap.LDAPFilter;
+import org.opends.server.protocols.internal.Requests;
+import org.opends.server.protocols.internal.SearchRequest;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.Attributes;
 import org.opends.server.types.DN;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.Entry;
-import org.opends.server.types.LDAPException;
 import org.opends.server.types.Modification;
 import org.opends.server.types.SearchResultEntry;
 
@@ -266,13 +263,21 @@
    */
   private String getAttr(String baseDN, String attrName)
   {
-    // Prepare the ldap search
-    LDAPFilter filter;
+    InternalSearchOperation search;
     try
     {
-      filter = LDAPFilter.decode("objectclass=*");
+      SearchRequest request = Requests.newSearchRequest(baseDN, SearchScope.BASE_OBJECT, "objectclass=*")
+          .addAttribute(attrName);
+      search = internalConnection.processSearch(request);
+      if (search.getResultCode() != ResultCode.SUCCESS)
+      {
+        // can not happen
+        // best effort.
+        // TODO Log an Error.
+        return null;
+      }
     }
-    catch (LDAPException e)
+    catch (DirectoryException e)
     {
       // can not happen
       // best effort.
@@ -280,25 +285,8 @@
       return null;
     }
 
-    LinkedHashSet<String> attributes = new LinkedHashSet<String>(1);
-    attributes.add(attrName);
-    InternalSearchOperation search = internalConnection.processSearch(
-        ByteString.valueOf(baseDN), SearchScope.BASE_OBJECT,
-        DereferenceAliasesPolicy.ALWAYS, 0, 0, false, filter, attributes);
-
-    if ((search.getResultCode() != ResultCode.SUCCESS))
-    {
-      // can not happen
-      // best effort.
-      // TODO Log an Error.
-      return null;
-    }
-
+    // Read the port from the PORT attribute
     SearchResultEntry adminConnectorEntry = null;
-
-    /*
-     * Read the port from the PORT attribute
-     */
     LinkedList<SearchResultEntry> result = search.getSearchEntries();
     if (!result.isEmpty())
     {
@@ -312,7 +300,6 @@
     }
 
     List<Attribute> attrs = adminConnectorEntry.getAttribute(attrType);
-
     if (attrs == null)
     {
       // can not happen
diff --git a/opendj3-server-dev/src/server/org/opends/server/authorization/dseecompat/UserAttr.java b/opendj3-server-dev/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
index efaaad4..de9cb49 100644
--- a/opendj3-server-dev/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
+++ b/opendj3-server-dev/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
@@ -26,20 +26,20 @@
  */
 package org.opends.server.authorization.dseecompat;
 
-import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.*;
 
 import static org.opends.messages.AccessControlMessages.*;
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 
 /*
  * TODO Evaluate making this class more efficient.
@@ -207,13 +207,8 @@
         AttributeType attrType;
         if((attrType = DirectoryServer.getAttributeType(attrStr)) == null)
             attrType = DirectoryServer.getDefaultAttributeType(attrStr);
-        InternalClientConnection conn =
-                InternalClientConnection.getRootConnection();
-        InternalSearchOperation op =
-                conn.processSearch(evalCtx.getClientDN(),
-                        SearchScope.BASE_OBJECT,
-                        DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                        filter, null);
+        final SearchRequest request = newSearchRequest(evalCtx.getClientDN(), SearchScope.BASE_OBJECT, filter);
+        InternalSearchOperation op = getRootConnection().processSearch(request);
         LinkedList<SearchResultEntry> result = op.getSearchEntries();
         if (!result.isEmpty()) {
             ByteString val= ByteString.valueOf(attrVal);
@@ -344,20 +339,13 @@
                         stop=true;
                 }
             } else {
-                DN pDN=
-                        getDNParentLevel(levels[i], evalCtx.getResourceDN());
+                DN pDN = getDNParentLevel(levels[i], evalCtx.getResourceDN());
                 if(pDN == null)
                     continue;
-                LinkedHashSet<String> reqAttrs = new LinkedHashSet<String>(1);
-                reqAttrs.add(parentInheritance.getAttrTypeStr());
-                InternalClientConnection conn =
-                        InternalClientConnection.getRootConnection();
-                InternalSearchOperation op = conn.processSearch(pDN,
-                        SearchScope.BASE_OBJECT,
-                        DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                        filter, reqAttrs);
-                LinkedList<SearchResultEntry> result =
-                        op.getSearchEntries();
+                final SearchRequest request = newSearchRequest(pDN, SearchScope.BASE_OBJECT, filter)
+                    .addAttribute(parentInheritance.getAttrTypeStr());
+                InternalSearchOperation op = getRootConnection().processSearch(request);
+                LinkedList<SearchResultEntry> result = op.getSearchEntries();
                 if (!result.isEmpty()) {
                     Entry e = result.getFirst();
                     if(e.hasAttribute(attrType)) {
diff --git a/opendj3-server-dev/src/server/org/opends/server/config/JMXMBean.java b/opendj3-server-dev/src/server/org/opends/server/config/JMXMBean.java
index 7212081..cb16e87 100644
--- a/opendj3-server-dev/src/server/org/opends/server/config/JMXMBean.java
+++ b/opendj3-server-dev/src/server/org/opends/server/config/JMXMBean.java
@@ -37,8 +37,8 @@
 import javax.management.AttributeList;
 import javax.management.AttributeNotFoundException;
 import javax.management.DynamicMBean;
-import javax.management.MBeanAttributeInfo;
 import javax.management.InvalidAttributeValueException;
+import javax.management.MBeanAttributeInfo;
 import javax.management.MBeanConstructorInfo;
 import javax.management.MBeanException;
 import javax.management.MBeanInfo;
@@ -50,6 +50,7 @@
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.admin.std.server.MonitorProviderCfg;
 import org.opends.server.api.AlertGenerator;
@@ -60,13 +61,18 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
 import org.opends.server.protocols.jmx.Credential;
 import org.opends.server.protocols.jmx.JmxClientConnection;
 import org.opends.server.protocols.ldap.LDAPFilter;
-import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.InvokableMethod;
+import org.opends.server.types.LDAPException;
 
 import static org.opends.messages.ConfigMessages.*;
+import static org.opends.server.protocols.internal.Requests.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
@@ -470,49 +476,36 @@
     //
     // prepare the ldap search
 
-    LDAPFilter filter;
     try
     {
-      filter = LDAPFilter.decode("objectclass=*");
-    }
-    catch (LDAPException e)
-    {
-      logger.traceException(e);
-
-      LocalizableMessage message = ERR_CONFIG_JMX_CANNOT_GET_ATTRIBUTE.
-          get(attributeName, configEntryDN, getExceptionMessage(e));
-      throw new AttributeNotFoundException(message.toString());
-    }
-
-    //
-    // Perform the Ldap operation for
-    //  - ACI Check
-    //  - Loggin purpose
-    InternalSearchOperation op=null;
-    if (clientConnection instanceof JmxClientConnection) {
+      //
+      // Perform the Ldap operation for
+      //  - ACI Check
+      //  - Loggin purpose
+      InternalSearchOperation op=null;
+      if (clientConnection instanceof JmxClientConnection) {
         op = ((JmxClientConnection)clientConnection).processSearch(
             ByteString.valueOf(configEntryDN.toString()),
-             SearchScope.BASE_OBJECT, filter);
-    }
-    else if (clientConnection instanceof InternalClientConnection) {
-        op = ((InternalClientConnection)clientConnection).processSearch(
-            ByteString.valueOf(configEntryDN.toString()),
-             SearchScope.BASE_OBJECT, filter);
-    }
-    // BUG : op may be null
-    ResultCode rc = op.getResultCode();
-    if (rc != ResultCode.SUCCESS) {
-       clientConnection = null ;
+                SearchScope.BASE_OBJECT, getTrueFilter());
+      }
+      else if (clientConnection instanceof InternalClientConnection) {
+        SearchRequest request = newSearchRequest(configEntryDN, SearchScope.BASE_OBJECT, "(objectclass=*)");
+        op = ((InternalClientConnection) clientConnection).processSearch(request);
+      }
+      // BUG : op may be null
+      ResultCode rc = op.getResultCode();
+      if (rc != ResultCode.SUCCESS) {
+        LocalizableMessage message = ERR_CONFIG_JMX_CANNOT_GET_ATTRIBUTE.
+            get(attributeName, configEntryDN, op.getErrorMessage());
+        throw new AttributeNotFoundException(message.toString());
+      }
 
-       LocalizableMessage message = ERR_CONFIG_JMX_CANNOT_GET_ATTRIBUTE.
-         get(attributeName, configEntryDN, op.getErrorMessage());
-       throw new AttributeNotFoundException(message.toString());
-    }
-
-    try
-    {
       return getJmxAttribute(attributeName);
     }
+    catch (AttributeNotFoundException e)
+    {
+      throw e;
+    }
     catch (Exception e)
     {
       logger.traceException(e);
@@ -523,6 +516,20 @@
     }
   }
 
+  private LDAPFilter getTrueFilter()
+  {
+    try
+    {
+      return LDAPFilter.decode("(objectclass=*)");
+    }
+    catch (LDAPException e)
+    {
+      // can never happen
+      logger.traceException(e);
+      return null;
+    }
+  }
+
   /**
    * Set the value of a specific attribute of the Dynamic MBean.  In this case,
    * it will always throw {@code InvalidAttributeValueException} because setting
@@ -564,37 +571,35 @@
     }
 
     //
-    // prepare the ldap search
-    LDAPFilter filter;
-    try
-    {
-      filter = LDAPFilter.decode("objectclass=*");
+    // Perform the Ldap operation for
+    //  - ACI Check
+    //  - Loggin purpose
+    InternalSearchOperation op = null;
+    if (clientConnection instanceof JmxClientConnection) {
+      op = ((JmxClientConnection)clientConnection).processSearch(
+          ByteString.valueOf(configEntryDN.toString()),
+              SearchScope.BASE_OBJECT, getTrueFilter());
     }
-    catch (LDAPException e)
+    else if (clientConnection instanceof InternalClientConnection) {
+      try
+      {
+        SearchRequest request = newSearchRequest(configEntryDN, SearchScope.BASE_OBJECT, "(objectclass=*)");
+        op = ((InternalClientConnection) clientConnection).processSearch(request);
+      }
+      catch (DirectoryException e)
+      {
+        logger.traceException(e);
+      }
+    }
+
+    if (op == null)
     {
       return null;
     }
 
-    //
-    // Perform the Ldap operation for
-    //  - ACI Check
-    //  - Loggin purpose
-    InternalSearchOperation op=null;
-    if (clientConnection instanceof JmxClientConnection) {
-      op = ((JmxClientConnection)clientConnection).processSearch(
-          ByteString.valueOf(configEntryDN.toString()),
-        SearchScope.BASE_OBJECT, filter);
-    }
-    else if (clientConnection instanceof InternalClientConnection) {
-      op = ((InternalClientConnection)clientConnection).processSearch(
-          ByteString.valueOf(configEntryDN.toString()),
-        SearchScope.BASE_OBJECT, filter);
-    }
-    // BUG: op may be null
     ResultCode rc = op.getResultCode();
     if (rc != ResultCode.SUCCESS)
     {
-      clientConnection = null ;
       return null;
     }
 
@@ -668,7 +673,6 @@
     }
 
     return attrList;
-
   }
 
   /**
@@ -865,5 +869,3 @@
     return clientConnection;
   }
 }
-
-
diff --git a/opendj3-server-dev/src/server/org/opends/server/crypto/CryptoManagerImpl.java b/opendj3-server-dev/src/server/org/opends/server/crypto/CryptoManagerImpl.java
index 108217f..336688c 100644
--- a/opendj3-server-dev/src/server/org/opends/server/crypto/CryptoManagerImpl.java
+++ b/opendj3-server-dev/src/server/org/opends/server/crypto/CryptoManagerImpl.java
@@ -55,7 +55,6 @@
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.ModificationType;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
@@ -72,6 +71,8 @@
 import org.opends.server.core.ServerContext;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.protocols.ldap.ExtendedRequestProtocolOp;
 import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp;
 import org.opends.server.protocols.ldap.LDAPMessage;
@@ -94,6 +95,7 @@
 
 import static org.opends.messages.CoreMessages.*;
 import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
@@ -507,14 +509,10 @@
     // Construct the search filter.
     final String FILTER_OC_INSTANCE_KEY = "(objectclass=" + ocInstanceKey.getNameOrOID() + ")";
     // Construct the attribute list.
-    final LinkedHashSet<String> requestedAttributes
-            = new LinkedHashSet<String>();
-    requestedAttributes.add(
-            attrPublicKeyCertificate.getNameOrOID() + ";binary");
+    String requestedAttribute = attrPublicKeyCertificate.getNameOrOID() + ";binary";
 
     // Retrieve the certificate from the entry.
-    final InternalClientConnection icc
-            = InternalClientConnection.getRootConnection();
+    final InternalClientConnection icc = getRootConnection();
     byte[] certificate = null;
     try {
       for (int i = 0; i < 2; ++i) {
@@ -523,15 +521,9 @@
              backend, add it using a special object class that induces
              the backend to create the public-key certificate
              attribute, then repeat the search. */
-          InternalSearchOperation searchOp = icc.processSearch(
-                  entryDN,
-                  SearchScope.BASE_OBJECT,
-                  DereferenceAliasesPolicy.NEVER,
-                  /* size limit */ 0, /* time limit */ 0,
-                  /* types only */ false,
-                  SearchFilter.createFilterFromString(
-                          FILTER_OC_INSTANCE_KEY),
-                  requestedAttributes);
+          final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, FILTER_OC_INSTANCE_KEY)
+              .addAttribute(requestedAttribute);
+          InternalSearchOperation searchOp = icc.processSearch(request);
           for (Entry e : searchOp.getSearchEntries()) {
             /* attribute ds-cfg-public-key-certificate is a MUST in
                the schema */
@@ -633,46 +625,31 @@
    */
   static void publishInstanceKeyEntryInADS()
           throws CryptoManagerException {
-    final byte[] instanceKeyCertificate
-            = getInstanceKeyCertificateFromLocalTruststore();
-    final String instanceKeyID
-            = getInstanceKeyID(instanceKeyCertificate);
+    final byte[] instanceKeyCertificate = getInstanceKeyCertificateFromLocalTruststore();
+    final String instanceKeyID = getInstanceKeyID(instanceKeyCertificate);
     // Construct the key entry DN.
     final ByteString distinguishedValue = ByteString.valueOf(instanceKeyID);
     final DN entryDN = instanceKeysDN.child(
          RDN.create(attrKeyID, distinguishedValue));
-    // Construct the search filter.
-    final String FILTER_OC_INSTANCE_KEY = "(objectclass=" + ocInstanceKey.getNameOrOID() + ")";
-    // Construct the attribute list.
-    final LinkedHashSet<String> requestedAttributes
-            = new LinkedHashSet<String>();
-    requestedAttributes.add("dn");
 
     // Check for the entry. If it does not exist, create it.
-    final InternalClientConnection icc
-            = InternalClientConnection.getRootConnection();
+    final String FILTER_OC_INSTANCE_KEY = "(objectclass=" + ocInstanceKey.getNameOrOID() + ")";
+    final InternalClientConnection icc = getRootConnection();
     try {
-      final InternalSearchOperation searchOp
-              = icc.processSearch( entryDN, SearchScope.BASE_OBJECT,
-              DereferenceAliasesPolicy.NEVER,
-              /* size limit */ 0, /* time limit */ 0,
-              /* types only */ false,
-              SearchFilter.createFilterFromString(
-                      FILTER_OC_INSTANCE_KEY),
-              requestedAttributes);
+      final SearchRequest request =
+          newSearchRequest(entryDN, SearchScope.BASE_OBJECT, FILTER_OC_INSTANCE_KEY).addAttribute("dn");
+      final InternalSearchOperation searchOp = icc.processSearch(request);
       if (0 == searchOp.getSearchEntries().size()) {
         final Entry entry = new Entry(entryDN, null, null, null);
         entry.addObjectClass(DirectoryServer.getTopObjectClass());
         entry.addObjectClass(ocInstanceKey);
 
         // Add the key ID attribute.
-        final Attribute keyIDAttr = Attributes.create(attrKeyID,
-            distinguishedValue);
+        final Attribute keyIDAttr = Attributes.create(attrKeyID, distinguishedValue);
         entry.addAttribute(keyIDAttr, new ArrayList<ByteString>(0));
 
         // Add the public key certificate attribute.
-        AttributeBuilder builder = new AttributeBuilder(
-            attrPublicKeyCertificate);
+        AttributeBuilder builder = new AttributeBuilder(attrPublicKeyCertificate);
         builder.setOption("binary");
         builder.add(ByteString.wrap(instanceKeyCertificate));
         final Attribute certificateAttr = builder.toAttribute();
@@ -705,33 +682,16 @@
    search operation.
    @see org.opends.admin.ads.ADSContext#getTrustedCertificates()
    */
-  private Map<String, byte[]> getTrustedCertificates()
-          throws CryptoManagerException {
-    final Map<String, byte[]> certificateMap
-            = new HashMap<String, byte[]>();
+  private Map<String, byte[]> getTrustedCertificates() throws CryptoManagerException {
+    final Map<String, byte[]> certificateMap = new HashMap<String, byte[]>();
     try {
       // Construct the search filter.
       final String FILTER_OC_INSTANCE_KEY = "(objectclass=" + ocInstanceKey.getNameOrOID() + ")";
       final String FILTER_NOT_COMPROMISED = "(!(" + attrCompromisedTime.getNameOrOID() + "=*))";
       final String searchFilter = "(&" + FILTER_OC_INSTANCE_KEY + FILTER_NOT_COMPROMISED + ")";
-      // Construct the attribute list.
-      final LinkedHashSet<String> requestedAttributes
-              = new LinkedHashSet<String>();
-      requestedAttributes.add(attrKeyID.getNameOrOID());
-      requestedAttributes.add(
-              attrPublicKeyCertificate.getNameOrOID() + ";binary");
-      // Invoke the search operation.
-      final InternalClientConnection icc
-              = InternalClientConnection.getRootConnection();
-      InternalSearchOperation searchOp = icc.processSearch(
-              instanceKeysDN,
-              SearchScope.SINGLE_LEVEL,
-              DereferenceAliasesPolicy.NEVER,
-              /* size limit */ 0, /* time limit */ 0,
-              /* types only */ false,
-              SearchFilter.createFilterFromString(searchFilter),
-              requestedAttributes);
-      // Evaluate the search response.
+      final SearchRequest request = newSearchRequest(instanceKeysDN, SearchScope.SINGLE_LEVEL, searchFilter)
+          .addAttribute(attrKeyID.getNameOrOID(), attrPublicKeyCertificate.getNameOrOID() + ";binary");
+      InternalSearchOperation searchOp = getRootConnection().processSearch(request);
       for (Entry e : searchOp.getSearchEntries()) {
         /* attribute ds-cfg-key-id is the RDN and attribute
            ds-cfg-public-key-certificate is a MUST in the schema */
@@ -993,8 +953,7 @@
    */
   private String getSymmetricKey(Set<String> symmetricKeys)
   {
-    InternalClientConnection internalConnection =
-         InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     for (String symmetricKey : symmetricKeys)
     {
       try
@@ -1004,13 +963,9 @@
         String instanceKeyID = elements[0];
 
         // Find the server entry from the instance key ID.
-        String filter = "(" +
-             ConfigConstants.ATTR_CRYPTO_KEY_ID + "=" +
-             instanceKeyID + ")";
-        InternalSearchOperation internalSearch =
-             internalConnection.processSearch(
-                  serversDN, SearchScope.SUBORDINATES,
-                  SearchFilter.createFilterFromString(filter));
+        String filter = "(" + ATTR_CRYPTO_KEY_ID + "=" + instanceKeyID + ")";
+        final SearchRequest request = newSearchRequest(serversDN, SearchScope.SUBORDINATES, filter);
+        InternalSearchOperation internalSearch = conn.processSearch(request);
         if (internalSearch.getResultCode() != ResultCode.SUCCESS)
         {
           continue;
diff --git a/opendj3-server-dev/src/server/org/opends/server/extensions/DynamicGroupSearchThread.java b/opendj3-server-dev/src/server/org/opends/server/extensions/DynamicGroupSearchThread.java
index 7c9e93b..c0b8d49 100644
--- a/opendj3-server-dev/src/server/org/opends/server/extensions/DynamicGroupSearchThread.java
+++ b/opendj3-server-dev/src/server/org/opends/server/extensions/DynamicGroupSearchThread.java
@@ -25,30 +25,28 @@
  *      Portions Copyright 2014 ForgeRock AS
  */
 package org.opends.server.extensions;
+
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
-
-
-
-import java.util.LinkedHashSet;
-
+import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.api.DirectoryThread;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchListener;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
-import org.opends.server.types.DirectoryException;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
 import org.opends.server.types.LDAPURL;
 import org.opends.server.types.MembershipException;
-import org.forgerock.opendj.ldap.ResultCode;
 import org.opends.server.types.SearchFilter;
 import org.opends.server.types.SearchResultEntry;
 import org.opends.server.types.SearchResultReference;
-import org.forgerock.opendj.ldap.SearchScope;
 
 import static org.opends.messages.ExtensionMessages.*;
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 
 /**
  * This class implements a Directory Server thread that will be used to perform
@@ -114,28 +112,25 @@
    * Performs the set of searches and provides the results to the associated
    * member list.
    */
+  @Override
   public void run()
   {
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    LinkedHashSet<String> attributes = new LinkedHashSet<String>(0);
-    //Include all the user attributes along with the ismemberof.
-    attributes.add("*");
-    attributes.add("ismemberof");
+    InternalClientConnection conn = getRootConnection();
     for (searchCounter = 0; searchCounter < baseDNs.length; searchCounter++)
     {
-      InternalSearchOperation searchOperation =
-           conn.processSearch(baseDNs[searchCounter], SearchScope.WHOLE_SUBTREE,
-                              DereferenceAliasesPolicy.NEVER, 0, 0,
-                              false, searchFilters[searchCounter], attributes,
-                              this);
+      DN baseDN = baseDNs[searchCounter];
+      SearchFilter filter = searchFilters[searchCounter];
+      // Include all the user attributes along with the ismemberof.
+      final SearchRequest request = newSearchRequest(baseDN, SearchScope.WHOLE_SUBTREE, filter)
+          .addAttribute("*", "ismemberof");
+      InternalSearchOperation searchOperation = conn.processSearch(request, this);
 
       ResultCode resultCode = searchOperation.getResultCode();
       if (resultCode != ResultCode.SUCCESS)
       {
         if (resultCode == ResultCode.NO_SUCH_OBJECT)
         {
-          logger.warn(WARN_DYNAMICGROUP_NONEXISTENT_BASE_DN, baseDNs[searchCounter],
+          logger.warn(WARN_DYNAMICGROUP_NONEXISTENT_BASE_DN, baseDN,
                   memberList.getDynamicGroupDN());
           continue;
         }
@@ -143,8 +138,8 @@
         {
           LocalizableMessage message =
                ERR_DYNAMICGROUP_INTERNAL_SEARCH_FAILED.get(
-                       baseDNs[searchCounter],
-                       searchFilters[searchCounter],
+                       baseDN,
+                       filter,
                        memberList.getDynamicGroupDN(),
                        resultCode,
                        searchOperation.getErrorMessage());
@@ -166,6 +161,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void handleInternalSearchEntry(InternalSearchOperation searchOperation,
                                         SearchResultEntry searchEntry)
          throws DirectoryException
@@ -191,6 +187,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void handleInternalSearchReference(
                    InternalSearchOperation searchOperation,
                    SearchResultReference searchReference)
diff --git a/opendj3-server-dev/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java b/opendj3-server-dev/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java
index e29e3fe..fbc9c04 100644
--- a/opendj3-server-dev/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java
+++ b/opendj3-server-dev/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java
@@ -35,22 +35,24 @@
 import java.util.Set;
 
 import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.server.ExactMatchIdentityMapperCfg;
 import org.opends.server.admin.std.server.IdentityMapperCfg;
 import org.opends.server.api.Backend;
 import org.opends.server.api.IdentityMapper;
-import org.forgerock.opendj.config.server.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
 
 import static org.opends.messages.ExtensionMessages.*;
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 
 /**
  * This class provides an implementation of a Directory Server identity mapper
@@ -208,14 +210,14 @@
     }
 
     SearchResultEntry matchingEntry = null;
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     for (DN baseDN : baseDNs)
     {
-      InternalSearchOperation internalSearch =
-           conn.processSearch(baseDN, SearchScope.WHOLE_SUBTREE,
-                              DereferenceAliasesPolicy.NEVER, 1, 10,
-                              false, filter, requestedAttributes);
+      final SearchRequest request = newSearchRequest(baseDN, SearchScope.WHOLE_SUBTREE, filter)
+          .setSizeLimit(1)
+          .setTimeLimit(10)
+          .addAttribute(requestedAttributes);
+      InternalSearchOperation internalSearch = conn.processSearch(request);
 
       switch (internalSearch.getResultCode().asEnum())
       {
diff --git a/opendj3-server-dev/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java b/opendj3-server-dev/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java
index f84df46..fe3b99b 100644
--- a/opendj3-server-dev/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java
+++ b/opendj3-server-dev/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java
@@ -35,22 +35,24 @@
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.server.CertificateMapperCfg;
 import org.opends.server.admin.std.server.FingerprintCertificateMapperCfg;
 import org.opends.server.api.Backend;
 import org.opends.server.api.CertificateMapper;
-import org.forgerock.opendj.config.server.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
 
 import static org.opends.messages.ExtensionMessages.*;
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.util.StaticUtils.*;
 
 /**
@@ -233,14 +235,14 @@
     // For each base DN, issue an internal search in an attempt to map the
     // certificate.
     Entry userEntry = null;
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     for (DN baseDN : baseDNs)
     {
-      InternalSearchOperation searchOperation =
-           conn.processSearch(baseDN, SearchScope.WHOLE_SUBTREE,
-                              DereferenceAliasesPolicy.NEVER, 1, 10,
-                              false, filter, requestedAttributes);
+      final SearchRequest request = newSearchRequest(baseDN, SearchScope.WHOLE_SUBTREE, filter)
+          .setSizeLimit(1)
+          .setTimeLimit(10)
+          .addAttribute(requestedAttributes);
+      InternalSearchOperation searchOperation = conn.processSearch(request);
 
       switch (searchOperation.getResultCode().asEnum())
       {
diff --git a/opendj3-server-dev/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java b/opendj3-server-dev/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java
index fd4d672..ad5ec2a 100644
--- a/opendj3-server-dev/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java
+++ b/opendj3-server-dev/src/server/org/opends/server/extensions/PasswordPolicyStateExtendedOperation.java
@@ -33,24 +33,25 @@
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.io.ASN1;
 import org.forgerock.opendj.io.ASN1Reader;
 import org.forgerock.opendj.io.ASN1Writer;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.ByteStringBuilder;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.admin.std.server.PasswordPolicyStateExtendedOperationHandlerCfg;
 import org.opends.server.api.AuthenticationPolicy;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ExtendedOperationHandler;
-import org.forgerock.opendj.config.server.ConfigException;
 import org.opends.server.core.*;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.schema.GeneralizedTimeSyntax;
 import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
 
 import static org.opends.messages.CoreMessages.*;
 import static org.opends.messages.ExtensionMessages.*;
@@ -576,12 +577,10 @@
                               ExtendedOperation operation,
                               DN targetDN)
   {
-    Entry entry;
-
-    InternalSearchOperation internalSearch =
-         conn.processSearch(targetDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 1, 0,
-                            false, userFilter, requestAttributes, null);
+    final SearchRequest request = newSearchRequest(targetDN, SearchScope.BASE_OBJECT, userFilter)
+        .setSizeLimit(1)
+        .addAttribute(requestAttributes);
+    InternalSearchOperation internalSearch = conn.processSearch(request);
     if (internalSearch.getResultCode() != ResultCode.SUCCESS)
     {
       operation.setResultCode(internalSearch.getResultCode());
@@ -605,11 +604,8 @@
     }
     else
     {
-      entry = matchingEntries.get(0);
+      return matchingEntries.get(0);
     }
-
-    return entry;
-
   }
 
   /**
diff --git a/opendj3-server-dev/src/server/org/opends/server/extensions/RegularExpressionIdentityMapper.java b/opendj3-server-dev/src/server/org/opends/server/extensions/RegularExpressionIdentityMapper.java
index 5ab1b49..e26ef269 100644
--- a/opendj3-server-dev/src/server/org/opends/server/extensions/RegularExpressionIdentityMapper.java
+++ b/opendj3-server-dev/src/server/org/opends/server/extensions/RegularExpressionIdentityMapper.java
@@ -38,22 +38,24 @@
 import java.util.regex.PatternSyntaxException;
 
 import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.server.IdentityMapperCfg;
 import org.opends.server.admin.std.server.RegularExpressionIdentityMapperCfg;
 import org.opends.server.api.Backend;
 import org.opends.server.api.IdentityMapper;
-import org.forgerock.opendj.config.server.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
 
 import static org.opends.messages.ExtensionMessages.*;
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 
 /**
  * This class provides an implementation of a Directory Server identity mapper
@@ -229,14 +231,14 @@
     }
 
     SearchResultEntry matchingEntry = null;
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     for (DN baseDN : baseDNs)
     {
-      InternalSearchOperation internalSearch =
-           conn.processSearch(baseDN, SearchScope.WHOLE_SUBTREE,
-                              DereferenceAliasesPolicy.NEVER, 1, 10,
-                              false, filter, requestedAttributes);
+      final SearchRequest request = newSearchRequest(baseDN, SearchScope.WHOLE_SUBTREE, filter)
+          .setSizeLimit(1)
+          .setTimeLimit(10)
+          .addAttribute(requestedAttributes);
+      InternalSearchOperation internalSearch = conn.processSearch(request);
 
       switch (internalSearch.getResultCode().asEnum())
       {
diff --git a/opendj3-server-dev/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java b/opendj3-server-dev/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java
index e495a7b..2af9842 100644
--- a/opendj3-server-dev/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java
+++ b/opendj3-server-dev/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java
@@ -35,21 +35,23 @@
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
+import org.forgerock.opendj.config.server.ConfigException;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.server.CertificateMapperCfg;
 import org.opends.server.admin.std.server.SubjectAttributeToUserAttributeCertificateMapperCfg;
 import org.opends.server.api.Backend;
 import org.opends.server.api.CertificateMapper;
-import org.forgerock.opendj.config.server.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
 
 import static org.opends.messages.ExtensionMessages.*;
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.util.StaticUtils.*;
 
 /**
@@ -292,14 +294,14 @@
     // For each base DN, issue an internal search in an attempt to map the
     // certificate.
     Entry userEntry = null;
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     for (DN baseDN : baseDNs)
     {
-      InternalSearchOperation searchOperation =
-           conn.processSearch(baseDN, SearchScope.WHOLE_SUBTREE,
-                              DereferenceAliasesPolicy.NEVER, 1, 10,
-                              false, filter, requestedAttributes);
+      final SearchRequest request = newSearchRequest(baseDN, SearchScope.WHOLE_SUBTREE, filter)
+          .setSizeLimit(1)
+          .setTimeLimit(10)
+          .addAttribute(requestedAttributes);
+      InternalSearchOperation searchOperation = conn.processSearch(request);
 
       switch (searchOperation.getResultCode().asEnum())
       {
diff --git a/opendj3-server-dev/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java b/opendj3-server-dev/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java
index 5bd7c6d..44b89ea 100644
--- a/opendj3-server-dev/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java
+++ b/opendj3-server-dev/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java
@@ -37,8 +37,8 @@
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.admin.server.ConfigurationChangeListener;
@@ -46,13 +46,15 @@
 import org.opends.server.admin.std.server.SubjectDNToUserAttributeCertificateMapperCfg;
 import org.opends.server.api.Backend;
 import org.opends.server.api.CertificateMapper;
-import org.forgerock.opendj.config.server.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 
 /**
  * This class implements a very simple Directory Server certificate mapper that
@@ -199,14 +201,14 @@
     // For each base DN, issue an internal search in an attempt to map the
     // certificate.
     Entry userEntry = null;
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     for (DN baseDN : baseDNs)
     {
-      InternalSearchOperation searchOperation =
-           conn.processSearch(baseDN, SearchScope.WHOLE_SUBTREE,
-                              DereferenceAliasesPolicy.NEVER, 1, 10,
-                              false, filter, requestedAttributes);
+      final SearchRequest request = newSearchRequest(baseDN, SearchScope.WHOLE_SUBTREE, filter)
+          .setSizeLimit(1)
+          .setTimeLimit(10)
+          .addAttribute(requestedAttributes);
+      InternalSearchOperation searchOperation = conn.processSearch(request);
       switch (searchOperation.getResultCode().asEnum())
       {
         case SUCCESS:
diff --git a/opendj3-server-dev/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java b/opendj3-server-dev/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java
index ee27932..6da82a6 100644
--- a/opendj3-server-dev/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java
+++ b/opendj3-server-dev/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java
@@ -45,8 +45,8 @@
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.ModificationType;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
@@ -62,20 +62,22 @@
 import org.opends.server.api.plugin.DirectoryServerPlugin;
 import org.opends.server.api.plugin.PluginResult;
 import org.opends.server.api.plugin.PluginType;
-import org.forgerock.opendj.config.server.ConfigException;
 import org.opends.server.core.DeleteOperation;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.*;
-import org.opends.server.types.operation.SubordinateModifyDNOperation;
-import org.opends.server.types.operation.PostOperationModifyDNOperation;
 import org.opends.server.types.operation.PostOperationDeleteOperation;
+import org.opends.server.types.operation.PostOperationModifyDNOperation;
 import org.opends.server.types.operation.PreOperationAddOperation;
 import org.opends.server.types.operation.PreOperationModifyOperation;
+import org.opends.server.types.operation.SubordinateModifyDNOperation;
 
 import static org.opends.messages.PluginMessages.*;
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.schema.SchemaConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
@@ -699,11 +701,9 @@
           ByteString.valueOf(oldEntryDN.toString())));
     }
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation operation = conn.processSearch(baseDN,
-         SearchScope.WHOLE_SUBTREE, DereferenceAliasesPolicy.NEVER, 0, 0,
-         false, SearchFilter.createORFilter(componentFilters), null);
+    SearchFilter orFilter = SearchFilter.createORFilter(componentFilters);
+    final SearchRequest request = newSearchRequest(baseDN, SearchScope.WHOLE_SUBTREE, orFilter);
+    InternalSearchOperation operation = getRootConnection().processSearch(request);
 
     switch (operation.getResultCode().asEnum())
     {
diff --git a/opendj3-server-dev/src/server/org/opends/server/plugins/UniqueAttributePlugin.java b/opendj3-server-dev/src/server/org/opends/server/plugins/UniqueAttributePlugin.java
index 484d6f7..d09a88e 100644
--- a/opendj3-server-dev/src/server/org/opends/server/plugins/UniqueAttributePlugin.java
+++ b/opendj3-server-dev/src/server/org/opends/server/plugins/UniqueAttributePlugin.java
@@ -33,7 +33,6 @@
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.admin.server.ConfigurationChangeListener;
@@ -48,11 +47,14 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.schema.SchemaConstants;
 import org.opends.server.types.*;
 import org.opends.server.types.operation.*;
 
 import static org.opends.messages.PluginMessages.*;
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.util.ServerConstants.*;
 
 /**
@@ -651,15 +653,13 @@
       filter = SearchFilter.createORFilter(equalityFilters);
     }
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-
+    InternalClientConnection conn = getRootConnection();
     for (DN baseDN : baseDNs)
     {
-      InternalSearchOperation searchOperation =
-           conn.processSearch(baseDN, SearchScope.WHOLE_SUBTREE,
-                              DereferenceAliasesPolicy.NEVER, 2, 0,
-                              false, filter, SEARCH_ATTRS);
+      final SearchRequest request = newSearchRequest(baseDN, SearchScope.WHOLE_SUBTREE, filter)
+          .setSizeLimit(2)
+          .addAttribute(SEARCH_ATTRS);
+      InternalSearchOperation searchOperation = conn.processSearch(request);
       for (SearchResultEntry e : searchOperation.getSearchEntries())
       {
         if (! e.getName().equals(targetDN))
diff --git a/opendj3-server-dev/src/server/org/opends/server/protocols/internal/AbstractRequestImpl.java b/opendj3-server-dev/src/server/org/opends/server/protocols/internal/AbstractRequestImpl.java
new file mode 100644
index 0000000..709fbf8
--- /dev/null
+++ b/opendj3-server-dev/src/server/org/opends/server/protocols/internal/AbstractRequestImpl.java
@@ -0,0 +1,132 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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.
+ *      Portions copyright 2012-2014 ForgeRock AS.
+ */
+package org.opends.server.protocols.internal;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.forgerock.util.Reject;
+import org.opends.server.types.Control;
+
+/**
+ * Abstract request implementation.
+ *
+ * @see org.forgerock.opendj.ldap.requests.AbstractRequestImpl
+ */
+abstract class AbstractRequestImpl {
+
+    /**
+     * To be removed
+     *
+     * @param controls
+     *          the controls
+     * @param oid
+     *          the oid
+     * @return a new control object
+     * @see org.forgerock.opendj.ldap.requests.AbstractRequestImpl#getControl(
+     *      org.forgerock.opendj.ldap.controls.ControlDecoder, org.forgerock.opendj.ldap.DecodeOptions)
+     */
+    static Control getControl(final List<Control> controls, final String oid) {
+        // Avoid creating an iterator if possible.
+        if (!controls.isEmpty()) {
+            for (final Control control : controls) {
+                if (control.getOID().equals(oid)) {
+                    return control;
+                }
+            }
+        }
+        return null;
+    }
+
+    private final List<Control> controls = new LinkedList<Control>();
+
+    /** Default constructor. */
+    AbstractRequestImpl() {
+        // No implementation required.
+    }
+
+    /**
+     * To be removed
+     *
+     * @param control
+     *          the control
+     * @return the current object
+     * @see org.forgerock.opendj.ldap.requests.AbstractRequestImpl#addControl(
+     *      org.forgerock.opendj.ldap.controls.Control)
+     */
+    public AbstractRequestImpl addControl(final Control control) {
+        Reject.ifNull(control);
+        controls.add(control);
+        return this;
+    }
+
+    /**
+     * To be removed
+     *
+     * @param controls
+     *          the controls
+     * @return the current object
+     * @see org.forgerock.opendj.ldap.requests.AbstractRequestImpl#addControl(
+     *      org.forgerock.opendj.ldap.controls.Control)
+     */
+    public AbstractRequestImpl addControl(final Collection<Control> controls) {
+        if (controls != null) {
+            for (Control c : controls) {
+                addControl(c);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * To be removed
+     *
+     * @param oid
+     *          the oid
+     * @return the current object
+     * @see org.forgerock.opendj.ldap.requests.AbstractRequestImpl#containsControl(String)
+     */
+    public boolean containsControl(final String oid) {
+        return getControl(controls, oid) != null;
+    }
+
+    /**
+     * To be removed
+     *
+     * @return the controls
+     * @see org.forgerock.opendj.ldap.requests.AbstractRequestImpl#getControls()
+     */
+    public final List<Control> getControls() {
+        return controls;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public abstract String toString();
+
+}
diff --git a/opendj3-server-dev/src/server/org/opends/server/protocols/internal/InternalClientConnection.java b/opendj3-server-dev/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
index 3bc5f69..16761c8 100644
--- a/opendj3-server-dev/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
+++ b/opendj3-server-dev/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
@@ -35,13 +35,13 @@
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ConnectionHandler;
 import org.opends.server.core.*;
 import org.opends.server.core.networkgroups.NetworkGroup;
 import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
 import org.opends.server.util.AddChangeRecordEntry;
 import org.opends.server.util.DeleteChangeRecordEntry;
 import org.opends.server.util.ModifyChangeRecordEntry;
@@ -2015,259 +2015,7 @@
                                       String filterString)
          throws DirectoryException
   {
-    RawFilter rawFilter;
-    try
-    {
-      rawFilter = RawFilter.create(filterString);
-    }
-    catch (LDAPException le)
-    {
-      throw new DirectoryException(
-                     ResultCode.valueOf(le.getResultCode()),
-                     le.getErrorMessage(), le);
-    }
-
-    return processSearch(ByteString.valueOf(rawBaseDN), scope, rawFilter);
-  }
-
-
-
-  /**
-   * Processes an internal search operation with the provided
-   * information.
-   *
-   * @param  rawBaseDN     The base DN for the search.
-   * @param  scope         The scope for the search.
-   * @param  derefPolicy   The alias dereferencing policy for the
-   *                       search.
-   * @param  sizeLimit     The size limit for the search.
-   * @param  timeLimit     The time limit for the search.
-   * @param  typesOnly     The typesOnly flag for the search.
-   * @param  filterString  The string representation of the filter for
-   *                       the search.
-   * @param  attributes    The set of requested attributes for the
-   *                       search.
-   *
-   * @return  A reference to the internal search operation that was
-   *          processed and contains information about the result of
-   *          the processing as well as lists of the matching entries
-   *          and search references.
-   *
-   * @throws  DirectoryException  If the provided filter string cannot
-   *                              be decoded as a search filter.
-   */
-  public InternalSearchOperation
-              processSearch(String rawBaseDN, SearchScope scope,
-                            DereferenceAliasesPolicy derefPolicy,
-                            int sizeLimit, int timeLimit,
-                            boolean typesOnly, String filterString,
-                            Set<String> attributes)
-         throws DirectoryException
-  {
-    return processSearch(rawBaseDN, scope, derefPolicy, sizeLimit,
-                         timeLimit, typesOnly, filterString,
-                         attributes, null, null);
-  }
-
-
-
-  /**
-   * Processes an internal search operation with the provided
-   * information.
-   *
-   * @param  rawBaseDN       The base DN for the search.
-   * @param  scope           The scope for the search.
-   * @param  derefPolicy     The alias dereferencing policy for the
-   *                         search.
-   * @param  sizeLimit       The size limit for the search.
-   * @param  timeLimit       The time limit for the search.
-   * @param  typesOnly       The typesOnly flag for the search.
-   * @param  filterString    The string representation of the filter
-   *                         for the search.
-   * @param  attributes      The set of requested attributes for the
-   *                         search.
-   * @param  searchListener  The internal search listener that should
-   *                         be used to handle the matching entries
-   *                         and references.
-   *
-   * @return  A reference to the internal search operation that was
-   *          processed and contains information about the result of
-   *          the processing as well as lists of the matching entries
-   *          and search references.
-   *
-   * @throws  DirectoryException  If the provided filter string cannot
-   *                              be decoded as a search filter.
-   */
-  public InternalSearchOperation
-              processSearch(String rawBaseDN, SearchScope scope,
-                            DereferenceAliasesPolicy derefPolicy,
-                            int sizeLimit, int timeLimit,
-                            boolean typesOnly, String filterString,
-                            Set<String> attributes,
-                            InternalSearchListener searchListener)
-         throws DirectoryException
-  {
-    return processSearch(rawBaseDN, scope, derefPolicy, sizeLimit,
-                         timeLimit, typesOnly, filterString,
-                         attributes, null, searchListener);
-  }
-
-
-
-  /**
-   * Processes an internal search operation with the provided
-   * information.
-   *
-   * @param  rawBaseDN       The base DN for the search.
-   * @param  scope           The scope for the search.
-   * @param  derefPolicy     The alias dereferencing policy for the
-   *                         search.
-   * @param  sizeLimit       The size limit for the search.
-   * @param  timeLimit       The time limit for the search.
-   * @param  typesOnly       The typesOnly flag for the search.
-   * @param  filterString    The string representation of the filter
-   *                         for the search.
-   * @param  attributes      The set of requested attributes for the
-   *                         search.
-   * @param  controls        The set of controls to include in the
-   *                         request.
-   * @param  searchListener  The internal search listener that should
-   *                         be used to handle the matching entries
-   *                         and references.
-   *
-   * @return  A reference to the internal search operation that was
-   *          processed and contains information about the result of
-   *          the processing as well as lists of the matching entries
-   *          and search references.
-   *
-   * @throws  DirectoryException  If the provided filter string cannot
-   *                              be decoded as a search filter.
-   */
-  public InternalSearchOperation
-              processSearch(String rawBaseDN, SearchScope scope,
-                            DereferenceAliasesPolicy derefPolicy,
-                            int sizeLimit, int timeLimit,
-                            boolean typesOnly, String filterString,
-                            Set<String> attributes,
-                            List<Control> controls,
-                            InternalSearchListener searchListener)
-         throws DirectoryException
-  {
-    RawFilter rawFilter;
-    try
-    {
-      rawFilter = RawFilter.create(filterString);
-    }
-    catch (LDAPException le)
-    {
-      throw new DirectoryException(
-                     ResultCode.valueOf(le.getResultCode()),
-                     le.getErrorMessage(), le);
-    }
-
-    return processSearch(ByteString.valueOf(rawBaseDN), scope,
-                         derefPolicy, sizeLimit, timeLimit, typesOnly,
-                         rawFilter, attributes, controls,
-                         searchListener);
-  }
-
-
-
-  /**
-   * Processes an internal search operation with the provided
-   * information.  It will not dereference any aliases, will not
-   * request a size or time limit, and will retrieve all user
-   * attributes.
-   *
-   * @param  rawBaseDN  The base DN for the search.
-   * @param  scope      The scope for the search.
-   * @param  filter     The filter for the search.
-   *
-   * @return  A reference to the internal search operation that was
-   *          processed and contains information about the result of
-   *          the processing as well as lists of the matching entries
-   *          and search references.
-   */
-  public InternalSearchOperation processSearch(ByteString rawBaseDN,
-                                      SearchScope scope,
-                                      RawFilter filter)
-  {
-    return processSearch(rawBaseDN, scope,
-                         DereferenceAliasesPolicy.NEVER, 0, 0,
-                         false, filter, new LinkedHashSet<String>(0));
-  }
-
-
-
-  /**
-   * Processes an internal search operation with the provided
-   * information.
-   *
-   * @param  rawBaseDN    The base DN for the search.
-   * @param  scope        The scope for the search.
-   * @param  derefPolicy  The alias dereferencing policy for the
-   *                      search.
-   * @param  sizeLimit    The size limit for the search.
-   * @param  timeLimit    The time limit for the search.
-   * @param  typesOnly    The typesOnly flag for the search.
-   * @param  filter       The filter for the search.
-   * @param  attributes   The set of requested attributes for the
-   *                      search.
-   *
-   * @return  A reference to the internal search operation that was
-   *          processed and contains information about the result of
-   *          the processing as well as lists of the matching entries
-   *          and search references.
-   */
-  public InternalSearchOperation
-              processSearch(ByteString rawBaseDN,
-                            SearchScope scope,
-                            DereferenceAliasesPolicy derefPolicy,
-                            int sizeLimit, int timeLimit,
-                            boolean typesOnly, RawFilter filter,
-                            Set<String> attributes)
-  {
-    return processSearch(rawBaseDN, scope, derefPolicy, sizeLimit,
-                         timeLimit, typesOnly, filter, attributes,
-                         null, null);
-  }
-
-
-
-  /**
-   * Processes an internal search operation with the provided
-   * information.
-   *
-   * @param  rawBaseDN       The base DN for the search.
-   * @param  scope           The scope for the search.
-   * @param  derefPolicy     The alias dereferencing policy for the
-   *                         search.
-   * @param  sizeLimit       The size limit for the search.
-   * @param  timeLimit       The time limit for the search.
-   * @param  typesOnly       The typesOnly flag for the search.
-   * @param  filter          The filter for the search.
-   * @param  attributes      The set of requested attributes for the
-   *                         search.
-   * @param  searchListener  The internal search listener that should
-   *                         be used to handle the matching entries
-   *                         and references.
-   *
-   * @return  A reference to the internal search operation that was
-   *          processed and contains information about the result of
-   *          the processing.
-   */
-  public InternalSearchOperation
-              processSearch(ByteString rawBaseDN,
-                            SearchScope scope,
-                            DereferenceAliasesPolicy derefPolicy,
-                            int sizeLimit, int timeLimit,
-                            boolean typesOnly, RawFilter filter,
-                            Set<String> attributes,
-                            InternalSearchListener searchListener)
-  {
-    return processSearch(rawBaseDN, scope, derefPolicy, sizeLimit,
-                         timeLimit, typesOnly, filter, attributes,
-                         null, searchListener);
+    return processSearch(Requests.newSearchRequest(rawBaseDN, scope, filterString), null);
   }
 
 
@@ -2322,97 +2070,16 @@
 
   /**
    * Processes an internal search operation with the provided
-   * information.  It will not dereference any aliases, will not
-   * request a size or time limit, and will retrieve all user
-   * attributes.
-   *
-   * @param  baseDN  The base DN for the search.
-   * @param  scope   The scope for the search.
-   * @param  filter  The filter for the search.
-   *
-   * @return  A reference to the internal search operation that was
-   *          processed and contains information about the result of
-   *          the processing as well as lists of the matching entries
-   *          and search references.
-   */
-  public InternalSearchOperation processSearch(DN baseDN,
-                                      SearchScope scope,
-                                      SearchFilter filter)
-  {
-    return processSearch(baseDN, scope,
-                         DereferenceAliasesPolicy.NEVER, 0, 0,
-                         false, filter, new LinkedHashSet<String>(0));
-  }
-
-
-
-  /**
-   * Processes an internal search operation with the provided
    * information.
    *
-   * @param  baseDN       The base DN for the search.
-   * @param  scope        The scope for the search.
-   * @param  derefPolicy  The alias dereferencing policy for the
-   *                      search.
-   * @param  sizeLimit    The size limit for the search.
-   * @param  timeLimit    The time limit for the search.
-   * @param  typesOnly    The typesOnly flag for the search.
-   * @param  filter       The filter for the search.
-   * @param  attributes   The set of requested attributes for the
-   *                      search.
-   *
-   * @return  A reference to the internal search operation that was
-   *          processed and contains information about the result of
-   *          the processing as well as lists of the matching entries
-   *          and search references.
-   */
-  public InternalSearchOperation
-              processSearch(DN baseDN, SearchScope scope,
-                            DereferenceAliasesPolicy derefPolicy,
-                            int sizeLimit, int timeLimit,
-                            boolean typesOnly, SearchFilter filter,
-                            Set<String> attributes)
-  {
-    return processSearch(baseDN, scope, derefPolicy, sizeLimit,
-                         timeLimit, typesOnly, filter, attributes,
-                         null, null);
-  }
-
-
-
-  /**
-   * Processes an internal search operation with the provided
-   * information.
-   *
-   * @param  baseDN          The base DN for the search.
-   * @param  scope           The scope for the search.
-   * @param  derefPolicy     The alias dereferencing policy for the
-   *                         search.
-   * @param  sizeLimit       The size limit for the search.
-   * @param  timeLimit       The time limit for the search.
-   * @param  typesOnly       The typesOnly flag for the search.
-   * @param  filter          The filter for the search.
-   * @param  attributes      The set of requested attributes for the
-   *                         search.
-   * @param  searchListener  The internal search listener that should
-   *                         be used to handle the matching entries
-   *                         and references.
-   *
+   * @param  request         The search request.
    * @return  A reference to the internal search operation that was
    *          processed and contains information about the result of
    *          the processing.
    */
-  public InternalSearchOperation
-              processSearch(DN baseDN, SearchScope scope,
-                            DereferenceAliasesPolicy derefPolicy,
-                            int sizeLimit, int timeLimit,
-                            boolean typesOnly, SearchFilter filter,
-                            Set<String> attributes,
-                            InternalSearchListener searchListener)
+  public InternalSearchOperation processSearch(final SearchRequest request)
   {
-    return processSearch(baseDN, scope, derefPolicy, sizeLimit,
-                         timeLimit, typesOnly, filter, attributes,
-                         null, searchListener);
+    return processSearch(request, null);
   }
 
 
@@ -2421,43 +2088,22 @@
    * Processes an internal search operation with the provided
    * information.
    *
-   * @param  baseDN          The base DN for the search.
-   * @param  scope           The scope for the search.
-   * @param  derefPolicy     The alias dereferencing policy for the
-   *                         search.
-   * @param  sizeLimit       The size limit for the search.
-   * @param  timeLimit       The time limit for the search.
-   * @param  typesOnly       The typesOnly flag for the search.
-   * @param  filter          The filter for the search.
-   * @param  attributes      The set of requested attributes for the
-   *                         search.
-   * @param  controls        The set of controls to include in the
-   *                         request.
+   * @param  request         The search request.
    * @param  searchListener  The internal search listener that should
    *                         be used to handle the matching entries
    *                         and references.
-   *
    * @return  A reference to the internal search operation that was
    *          processed and contains information about the result of
    *          the processing.
    */
-  public InternalSearchOperation
-              processSearch(DN baseDN, SearchScope scope,
-                            DereferenceAliasesPolicy derefPolicy,
-                            int sizeLimit, int timeLimit,
-                            boolean typesOnly, SearchFilter filter,
-                            Set<String> attributes,
-                            List<Control> controls,
-                            InternalSearchListener searchListener)
+  public InternalSearchOperation processSearch(final SearchRequest request, InternalSearchListener searchListener)
   {
     InternalSearchOperation searchOperation =
-         new InternalSearchOperation(this, nextOperationID(),
-                                     nextMessageID(), controls,
-                                     baseDN, scope, derefPolicy,
-                                     sizeLimit, timeLimit,
-                                     typesOnly, filter, attributes,
-                                     searchListener);
-
+         new InternalSearchOperation(this, nextOperationID(), nextMessageID(),
+             request.getControls(), request.getName(), request.getScope(),
+             request.getDereferenceAliasesPolicy(), request.getSizeLimit(),
+             request.getTimeLimit(), request.isTypesOnly(), request.getFilter(),
+             request.getAttributes(), searchListener);
     searchOperation.run();
     return searchOperation;
   }
@@ -2808,4 +2454,3 @@
       return 256;
   }
 }
-
diff --git a/opendj3-server-dev/src/server/org/opends/server/protocols/internal/Requests.java b/opendj3-server-dev/src/server/org/opends/server/protocols/internal/Requests.java
new file mode 100644
index 0000000..f7e3c3e
--- /dev/null
+++ b/opendj3-server-dev/src/server/org/opends/server/protocols/internal/Requests.java
@@ -0,0 +1,169 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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.
+ *      Portions copyright 2011-2014 ForgeRock AS
+ */
+
+package org.opends.server.protocols.internal;
+
+import org.forgerock.i18n.LocalizedIllegalArgumentException;
+import org.forgerock.opendj.ldap.SearchScope;
+import org.forgerock.util.Reject;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.SearchFilter;
+
+/**
+ * This class contains various methods for creating and manipulating requests.
+ * <p>
+ * All copy constructors of the form {@code copyOfXXXRequest} perform deep
+ * copies of their request parameter. More specifically, any controls,
+ * modifications, and attributes contained within the response will be
+ * duplicated.
+ * <p>
+ * Similarly, all unmodifiable views of request returned by methods of the form
+ * {@code unmodifiableXXXRequest} return deep unmodifiable views of their
+ * request parameter. More specifically, any controls, modifications, and
+ * attributes contained within the returned request will be unmodifiable.
+ *
+ * @see org.forgerock.opendj.ldap.requests.Requests
+ */
+public final class Requests {
+
+    // TODO: search request from LDAP URL.
+
+    // TODO: update request from persistent search result.
+
+    // TODO: synchronized requests?
+
+    /**
+     * Creates a new search request using the provided distinguished name,
+     * scope, and filter.
+     *
+     * @param name
+     *            The distinguished name of the base entry relative to which the
+     *            search is to be performed.
+     * @param scope
+     *            The scope of the search.
+     * @param filter
+     *            The filter that defines the conditions that must be fulfilled
+     *            in order for an entry to be returned.
+     * @param attributeDescriptions
+     *            The names of the attributes to be included with each entry.
+     * @return The new search request.
+     * @throws NullPointerException
+     *             If the {@code name}, {@code scope}, or {@code filter} were
+     *             {@code null}.
+     */
+    public static SearchRequest newSearchRequest(final DN name, final SearchScope scope,
+            final SearchFilter filter, final String... attributeDescriptions)
+            throws NullPointerException {
+        Reject.ifNull(name, scope, filter);
+        final SearchRequest request = new SearchRequest(name, scope, filter);
+        for (final String attributeDescription : attributeDescriptions) {
+            request.addAttribute(attributeDescription);
+        }
+        return request;
+    }
+
+    /**
+     * Creates a new search request using the provided distinguished name,
+     * scope, and filter, decoded using the default schema.
+     *
+     * @param name
+     *            The distinguished name of the base entry relative to which the
+     *            search is to be performed.
+     * @param scope
+     *            The scope of the search.
+     * @param filter
+     *            The filter that defines the conditions that must be fulfilled
+     *            in order for an entry to be returned.
+     * @param attributeDescriptions
+     *            The names of the attributes to be included with each entry.
+     * @return The new search request.
+     * @throws  DirectoryException
+     *             If a problem occurs while decoding the provided string as a
+     *             search filter.
+     * @throws LocalizedIllegalArgumentException
+     *             If {@code name} could not be decoded using the default
+     *             schema, or if {@code filter} is not a valid LDAP string
+     *             representation of a filter.
+     * @throws NullPointerException
+     *             If the {@code name}, {@code scope}, or {@code filter} were
+     *             {@code null}.
+     */
+    public static SearchRequest newSearchRequest(final String name, final SearchScope scope,
+            final String filter, final String... attributeDescriptions)
+            throws NullPointerException, LocalizedIllegalArgumentException, DirectoryException {
+        Reject.ifNull(name, scope, filter);
+        SearchFilter f = SearchFilter.createFilterFromString(filter);
+        final SearchRequest request = new SearchRequest(DN.valueOf(name), scope, f);
+        for (final String attributeDescription : attributeDescriptions) {
+            request.addAttribute(attributeDescription);
+        }
+        return request;
+    }
+
+    /**
+     * Return a new search request object.
+     *
+     * @param name
+     *          the dn
+     * @param scope
+     *          the search scope
+     * @param filter
+     *          the search filter
+     * @return a new search request object
+     * @throws DirectoryException
+     *           if a problem occurs
+     * @see #newSearchRequest(DN, SearchScope, SearchFilter, String...)
+     */
+    public static SearchRequest newSearchRequest(final String name, final SearchScope scope, final String filter)
+            throws DirectoryException {
+        return newSearchRequest(DN.valueOf(name), scope, SearchFilter.createFilterFromString(filter));
+    }
+
+    /**
+     * Return a new search request object.
+     *
+     * @param name
+     *          the dn
+     * @param scope
+     *          the search scope
+     * @param filter
+     *          the search filter
+     * @return a new search request object
+     * @throws DirectoryException
+     *           if a problem occurs
+     * @see #newSearchRequest(DN, SearchScope, SearchFilter, String...)
+     */
+    public static SearchRequest newSearchRequest(final DN name, final SearchScope scope, final String filter)
+            throws DirectoryException {
+        return newSearchRequest(name, scope, SearchFilter.createFilterFromString(filter));
+    }
+
+    private Requests() {
+        // Prevent instantiation.
+    }
+}
diff --git a/opendj3-server-dev/src/server/org/opends/server/protocols/internal/SearchRequest.java b/opendj3-server-dev/src/server/org/opends/server/protocols/internal/SearchRequest.java
new file mode 100644
index 0000000..55128b2
--- /dev/null
+++ b/opendj3-server-dev/src/server/org/opends/server/protocols/internal/SearchRequest.java
@@ -0,0 +1,358 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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.
+ *      Portions copyright 2012-2014 ForgeRock AS.
+ */
+package org.opends.server.protocols.internal;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
+import org.forgerock.opendj.ldap.SearchScope;
+import org.forgerock.util.Reject;
+import org.opends.server.types.Control;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.SearchFilter;
+
+/**
+ * Search request implementation.
+ *
+ * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl
+ */
+public final class SearchRequest extends AbstractRequestImpl {
+    /**
+     * Use a LinkedHashSet to return the attributes in the same order as requested by the user
+     */
+    private final Set<String> attributes = new LinkedHashSet<String>();
+    private DereferenceAliasesPolicy dereferenceAliasesPolicy = DereferenceAliasesPolicy.NEVER;
+    private SearchFilter filter;
+    private DN name;
+    private SearchScope scope;
+    private int sizeLimit;
+    private int timeLimit;
+    private boolean typesOnly;
+
+    /**
+     * To be removed.
+     *
+     * @param name
+     *          the dn
+     * @param scope
+     *          the search scope
+     * @param filter
+     *          the search filter
+     */
+    SearchRequest(final DN name, final SearchScope scope, final SearchFilter filter) {
+        this.name = name;
+        this.scope = scope;
+        this.filter = filter;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @param attributeDescriptions
+     *          the attribute descriptions
+     * @return the current object
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#addAttribute(String...)
+     */
+    public SearchRequest addAttribute(final String... attributeDescriptions) {
+        for (final String attributeDescription : attributeDescriptions) {
+            attributes.add(Reject.checkNotNull(attributeDescription));
+        }
+        return this;
+    }
+
+    /**
+     * To be added to {@link org.forgerock.opendj.ldap.requests.SearchRequestImpl}?
+     *
+     * @param attributeDescriptions
+     *          the attribute descriptions
+     * @return the current object
+     */
+    public SearchRequest addAttribute(final Collection<String> attributeDescriptions) {
+        for (final String attributeDescription : attributeDescriptions) {
+            attributes.add(Reject.checkNotNull(attributeDescription));
+        }
+        return this;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @return the attributes
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#getAttributes()
+     */
+    public Set<String> getAttributes() {
+        return attributes;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @return the dereference aliases policy
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#getDereferenceAliasesPolicy()
+     */
+    public DereferenceAliasesPolicy getDereferenceAliasesPolicy() {
+        return dereferenceAliasesPolicy;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @return the search filter
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#getFilter()
+     */
+    public SearchFilter getFilter() {
+        return filter;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @return the DN
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#getName()
+     */
+    public DN getName() {
+        return name;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @return the search scope
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#getScope()
+     */
+    public SearchScope getScope() {
+        return scope;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @return the size limit
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#getSizeLimit()
+     */
+    public int getSizeLimit() {
+        return sizeLimit;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @return is single entry search
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#isSingleEntrySearch()
+     */
+    public boolean isSingleEntrySearch() {
+        return sizeLimit == 1 || SearchScope.BASE_OBJECT.equals(scope);
+    }
+
+    /**
+     * To be removed.
+     *
+     * @return the time limit
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#getTimeLimit()
+     */
+    public int getTimeLimit() {
+        return timeLimit;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @return the types only
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#isTypesOnly()
+     */
+    public boolean isTypesOnly() {
+        return typesOnly;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @param policy the dereference aliases policy
+     * @return the current request
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#setDereferenceAliasesPolicy(DereferenceAliasesPolicy)
+     */
+    public SearchRequest setDereferenceAliasesPolicy(final DereferenceAliasesPolicy policy) {
+        Reject.ifNull(policy);
+
+        this.dereferenceAliasesPolicy = policy;
+        return this;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @param filter the search filter
+     * @return the current request
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#setFilter(org.forgerock.opendj.ldap.Filter)
+     */
+    public SearchRequest setFilter(final SearchFilter filter) {
+        Reject.ifNull(filter);
+
+        this.filter = filter;
+        return this;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @param filter the search filter
+     * @return the current request
+     * @throws DirectoryException if problem occurs
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#setFilter(String)
+     */
+    public SearchRequest setFilter(final String filter) throws DirectoryException {
+        this.filter = SearchFilter.createFilterFromString(filter);
+        return this;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @param dn the dn
+     * @return the current request
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#setName(org.forgerock.opendj.ldap.DN)
+     */
+    public SearchRequest setName(final DN dn) {
+        Reject.ifNull(dn);
+
+        this.name = dn;
+        return this;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @param dn the dn
+     * @return the current request
+     * @throws DirectoryException if problem occurs
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#setName(String)
+     */
+    public SearchRequest setName(final String dn) throws DirectoryException {
+        Reject.ifNull(dn);
+
+        this.name = DN.valueOf(dn);
+        return this;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @param scope the search scope
+     * @return the current request
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#setScope(SearchScope)
+     */
+    public SearchRequest setScope(final SearchScope scope) {
+        Reject.ifNull(scope);
+
+        this.scope = scope;
+        return this;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @param limit the size limit
+     * @return the current request
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#setSizeLimit(int)
+     */
+    public SearchRequest setSizeLimit(final int limit) {
+        Reject.ifFalse(limit >= 0, "negative size limit");
+
+        this.sizeLimit = limit;
+        return this;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @param limit the time limit
+     * @return the current request
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#setTimeLimit(int)
+     */
+    public SearchRequest setTimeLimit(final int limit) {
+        Reject.ifFalse(limit >= 0, "negative time limit");
+
+        this.timeLimit = limit;
+        return this;
+    }
+
+    /**
+     * To be removed.
+     *
+     * @param typesOnly the types only
+     * @return the current request
+     * @see org.forgerock.opendj.ldap.requests.SearchRequestImpl#setTypesOnly(boolean)
+     */
+    public SearchRequest setTypesOnly(final boolean typesOnly) {
+        this.typesOnly = typesOnly;
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public SearchRequest addControl(Control control) {
+        super.addControl(control);
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public SearchRequest addControl(Collection<Control> controls) {
+        super.addControl(controls);
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("SearchRequest(name=");
+        builder.append(getName());
+        builder.append(", scope=");
+        builder.append(getScope());
+        builder.append(", dereferenceAliasesPolicy=");
+        builder.append(getDereferenceAliasesPolicy());
+        builder.append(", sizeLimit=");
+        builder.append(getSizeLimit());
+        builder.append(", timeLimit=");
+        builder.append(getTimeLimit());
+        builder.append(", typesOnly=");
+        builder.append(isTypesOnly());
+        builder.append(", filter=");
+        builder.append(getFilter());
+        builder.append(", attributes=");
+        builder.append(getAttributes());
+        builder.append(", controls=");
+        builder.append(getControls());
+        builder.append(")");
+        return builder.toString();
+    }
+
+}
diff --git a/opendj3-server-dev/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java b/opendj3-server-dev/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
index fe8a0ee..6e6fa72 100644
--- a/opendj3-server-dev/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
+++ b/opendj3-server-dev/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -61,6 +61,8 @@
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchListener;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.Requests;
+import org.opends.server.protocols.internal.SearchRequest;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.protocols.ldap.LDAPFilter;
@@ -91,6 +93,7 @@
 import static org.opends.messages.ReplicationMessages.*;
 import static org.opends.messages.ToolMessages.*;
 import static org.opends.server.protocols.internal.InternalClientConnection.*;
+import static org.opends.server.protocols.internal.Requests.*;
 import static org.opends.server.replication.plugin.EntryHistorical.*;
 import static org.opends.server.replication.protocol.OperationContext.*;
 import static org.opends.server.replication.service.ReplicationMonitor.*;
@@ -647,26 +650,20 @@
               + "entry " + getBaseDNString());
     }
 
-    LDAPFilter filter;
+    InternalSearchOperation search;
     try
     {
-      filter = LDAPFilter.decode("(objectclass=*)");
-    } catch (LDAPException e)
+      // Search the domain root entry that is used to save the generation id
+      SearchRequest request = newSearchRequest(getBaseDN(), SearchScope.BASE_OBJECT, "(objectclass=*)")
+          .addAttribute(REPLICATION_GENERATION_ID, REPLICATION_FRACTIONAL_EXCLUDE, REPLICATION_FRACTIONAL_INCLUDE);
+      search = conn.processSearch(request);
+    }
+    catch (DirectoryException e)
     {
       // Can not happen
       return false;
     }
 
-    // Search the domain root entry that is used to save the generation id
-    final ByteString asn1BaseDn = ByteString.valueOf(getBaseDNString());
-    final Set<String> attributes = newSet(
-        REPLICATION_GENERATION_ID,
-        REPLICATION_FRACTIONAL_EXCLUDE,
-        REPLICATION_FRACTIONAL_INCLUDE);
-    InternalSearchOperation search = conn.processSearch(asn1BaseDn,
-      SearchScope.BASE_OBJECT,
-      DereferenceAliasesPolicy.ALWAYS, 0, 0, false,
-      filter, attributes);
     if (search.getResultCode() != ResultCode.SUCCESS
         && search.getResultCode() != ResultCode.NO_SUCH_OBJECT)
     {
@@ -2164,7 +2161,7 @@
        SearchScope.WHOLE_SUBTREE,
        DereferenceAliasesPolicy.NEVER,
        0, 0, false, filter,
-       USER_AND_REPL_OPERATIONAL_ATTRS, null);
+       USER_AND_REPL_OPERATIONAL_ATTRS, null, null);
 
      Entry entryToRename = null;
      CSN entryToRenameCSN = null;
@@ -2554,13 +2551,9 @@
     }
     try
     {
-      final Set<String> attrs = newSet(ENTRYUUID_ATTRIBUTE_NAME);
-
-      final InternalSearchOperation search = getRootConnection().processSearch(
-          dn, SearchScope.BASE_OBJECT, DereferenceAliasesPolicy.NEVER,
-          0, 0, false,
-          SearchFilter.createFilterFromString("(objectclass=*)"),
-          attrs);
+      final SearchRequest request = newSearchRequest(dn, SearchScope.BASE_OBJECT, "(objectclass=*)")
+          .addAttribute(ENTRYUUID_ATTRIBUTE_NAME);
+      final InternalSearchOperation search = getRootConnection().processSearch(request);
       final SearchResultEntry resultEntry = getFirstResult(search);
       if (resultEntry != null)
       {
@@ -2598,9 +2591,8 @@
   {
     try
     {
-      InternalSearchOperation search = conn.processSearch(getBaseDN(),
-            SearchScope.WHOLE_SUBTREE,
-            SearchFilter.createFilterFromString("entryuuid="+uuid));
+      final SearchRequest request = newSearchRequest(getBaseDN(), SearchScope.WHOLE_SUBTREE, "entryuuid=" + uuid);
+      InternalSearchOperation search = conn.processSearch(request);
       final SearchResultEntry resultEntry = getFirstResult(search);
       if (resultEntry != null)
       {
@@ -3005,15 +2997,9 @@
     // Find an rename child entries.
     try
     {
-      final Set<String> attrs =
-          newSet(ENTRYUUID_ATTRIBUTE_NAME, HISTORICAL_ATTRIBUTE_NAME);
-
-      InternalSearchOperation op =
-          conn.processSearch(entryDN, SearchScope.SINGLE_LEVEL,
-              DereferenceAliasesPolicy.NEVER, 0, 0, false,
-              SearchFilter.createFilterFromString("(objectClass=*)"),
-              attrs);
-
+      final SearchRequest request = newSearchRequest(entryDN, SearchScope.SINGLE_LEVEL, "(objectClass=*)")
+          .addAttribute(ENTRYUUID_ATTRIBUTE_NAME, HISTORICAL_ATTRIBUTE_NAME);
+      InternalSearchOperation op = conn.processSearch(request);
       if (op.getResultCode() == ResultCode.SUCCESS)
       {
         for (SearchResultEntry entry : op.getSearchEntries())
@@ -3332,20 +3318,15 @@
      * Search the database entry that is used to periodically
      * save the generation id
      */
-    final Set<String> attributes = newSet(REPLICATION_GENERATION_ID);
-    final String filter = "(objectclass=*)";
-    InternalSearchOperation search = conn.processSearch(getBaseDNString(),
-        SearchScope.BASE_OBJECT,
-        DereferenceAliasesPolicy.ALWAYS, 0, 0, false,
-        filter,attributes);
+    final SearchRequest request = newSearchRequest(getBaseDN(), SearchScope.BASE_OBJECT, "(objectclass=*)")
+        .addAttribute(REPLICATION_GENERATION_ID);
+    InternalSearchOperation search = conn.processSearch(request);
     if (search.getResultCode() == ResultCode.NO_SUCH_OBJECT)
     {
       // if the base entry does not exist look for the generationID
       // in the config entry.
-      search = conn.processSearch(config.dn().toString(),
-          SearchScope.BASE_OBJECT,
-          DereferenceAliasesPolicy.ALWAYS, 0, 0, false,
-          filter,attributes);
+      request.setName(config.dn());
+      search = conn.processSearch(request);
     }
 
     boolean found = false;
@@ -4274,17 +4255,12 @@
       maxValueForId = lastCSN.toString();
     }
 
-    LDAPFilter filter = LDAPFilter.decode(
+    String filter =
         "(&(" + HISTORICAL_ATTRIBUTE_NAME + ">=dummy:" + fromCSN + ")" +
-          "(" + HISTORICAL_ATTRIBUTE_NAME + "<=dummy:" + maxValueForId + "))");
-
-    return getRootConnection().processSearch(
-      ByteString.valueOf(baseDN.toString()),
-      SearchScope.WHOLE_SUBTREE,
-      DereferenceAliasesPolicy.NEVER,
-      0, 0, false, filter,
-      USER_AND_REPL_OPERATIONAL_ATTRS,
-      resultListener);
+          "(" + HISTORICAL_ATTRIBUTE_NAME + "<=dummy:" + maxValueForId + "))";
+    SearchRequest request = Requests.newSearchRequest(baseDN, SearchScope.WHOLE_SUBTREE, filter)
+        .addAttribute(USER_AND_REPL_OPERATIONAL_ATTRS);
+    return getRootConnection().processSearch(request, resultListener);
   }
 
   /**
@@ -5053,24 +5029,10 @@
          + "lastCSNPurgedFromHist: "
          + lastCSNPurgedFromHist.toStringUI());
 
-     LDAPFilter filter = null;
-     try
-     {
-       filter = LDAPFilter.decode(
-         "(" + EntryHistorical.HISTORICAL_ATTRIBUTE_NAME + ">=dummy:"
-         + lastCSNPurgedFromHist + ")");
-
-     } catch (LDAPException e)
-     {
-       // Not possible. We know the filter just above is correct.
-     }
-
-     InternalSearchOperation searchOp = conn.processSearch(
-         ByteString.valueOf(getBaseDNString()),
-         SearchScope.WHOLE_SUBTREE,
-         DereferenceAliasesPolicy.NEVER,
-         0, 0, false, filter,
-         USER_AND_REPL_OPERATIONAL_ATTRS, null);
+    String filter = "(" + HISTORICAL_ATTRIBUTE_NAME + ">=dummy:" + lastCSNPurgedFromHist + ")";
+    SearchRequest request = Requests.newSearchRequest(getBaseDN(), SearchScope.WHOLE_SUBTREE, filter)
+        .addAttribute(USER_AND_REPL_OPERATIONAL_ATTRS);
+    InternalSearchOperation searchOp = conn.processSearch(request);
 
      int count = 0;
      if (task != null)
diff --git a/opendj3-server-dev/src/server/org/opends/server/replication/plugin/PersistentServerState.java b/opendj3-server-dev/src/server/org/opends/server/replication/plugin/PersistentServerState.java
index e7ed2a1..130f8f6 100644
--- a/opendj3-server-dev/src/server/org/opends/server/replication/plugin/PersistentServerState.java
+++ b/opendj3-server-dev/src/server/org/opends/server/replication/plugin/PersistentServerState.java
@@ -36,6 +36,8 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ModifyOperationBasis;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPModification;
 import org.opends.server.replication.common.CSN;
@@ -158,15 +160,13 @@
   {
     try
     {
-      SearchFilter filter =
-          SearchFilter.createFilterFromString("objectclass=*");
+      final SearchRequest request =
+          newSearchRequest(baseDN, SearchScope.BASE_OBJECT, "objectclass=*").addAttribute(REPLICATION_STATE);
       /*
        * Search the database entry that is used to periodically
        * save the ServerState
        */
-      final InternalSearchOperation search = getRootConnection().processSearch(
-          baseDN, SearchScope.BASE_OBJECT, DereferenceAliasesPolicy.NEVER,
-          0, 0, false, filter, Collections.singleton(REPLICATION_STATE));
+      final InternalSearchOperation search = getRootConnection().processSearch(request);
       final ResultCode resultCode = search.getResultCode();
       if (resultCode != ResultCode.SUCCESS
           && resultCode != ResultCode.NO_SUCH_OBJECT)
@@ -194,15 +194,11 @@
   {
     try
     {
-      SearchFilter filter = SearchFilter.createFilterFromString(
-          "(&(objectclass=ds-cfg-replication-domain)"
-          + "(ds-cfg-base-dn=" + baseDN + "))");
-
-      final InternalSearchOperation op = getRootConnection().processSearch(
-          DN.valueOf("cn=config"),
-          SearchScope.SUBORDINATES,
-          DereferenceAliasesPolicy.NEVER,
-          1, 0, false, filter, Collections.singleton(REPLICATION_STATE));
+      String filter = "(&(objectclass=ds-cfg-replication-domain)" + "(ds-cfg-base-dn=" + baseDN + "))";
+      final SearchRequest request = newSearchRequest("cn=config", SearchScope.SUBORDINATES, filter)
+          .setSizeLimit(1)
+          .addAttribute(REPLICATION_STATE);
+      final InternalSearchOperation op = getRootConnection().processSearch(request);
       return getFirstResult(op);
     }
     catch (DirectoryException e)
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/ChangelogBackendTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/ChangelogBackendTestCase.java
index ff60f3d..975e023 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/ChangelogBackendTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/ChangelogBackendTestCase.java
@@ -37,7 +37,6 @@
 import org.assertj.core.api.Assertions;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.ModificationType;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
@@ -52,8 +51,9 @@
 import org.opends.server.core.ModifyDNOperationBasis;
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.protocols.internal.InternalSearchListener;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.Requests;
+import org.opends.server.protocols.internal.SearchRequest;
 import org.opends.server.replication.ReplicationTestCase;
 import org.opends.server.replication.common.CSN;
 import org.opends.server.replication.common.CSNGenerator;
@@ -141,13 +141,6 @@
   /** The port of the replicationServer. */
   private int replicationServerPort;
 
-  /**
-   * When used in a search operation, it includes all attributes (user and
-   * operational)
-   */
-  private static final Set<String> ALL_ATTRIBUTES = newSet("*", "+");
-  private static final List<Control> NO_CONTROL = null;
-
   @BeforeClass
   @Override
   public void setUp() throws Exception
@@ -1093,53 +1086,48 @@
       throws Exception
   {
     debugInfo(testName, "Search with cookie=[" + cookie + "] filter=[" + filterString + "]");
-    return searchChangelog(filterString, ALL_ATTRIBUTES, createCookieControl(cookie),
-        expectedNbEntries, expectedResultCode, testName);
+    SearchRequest request = newSearchRequest(filterString).addControl(createCookieControl(cookie));
+    return searchChangelog(request, expectedNbEntries, expectedResultCode, testName);
   }
 
   private InternalSearchOperation searchChangelog(String filterString, int expectedNbEntries,
       ResultCode expectedResultCode, String testName) throws Exception
   {
-    return searchChangelog(filterString, ALL_ATTRIBUTES, NO_CONTROL, expectedNbEntries, expectedResultCode, testName);
+    SearchRequest request = newSearchRequest(filterString);
+    return searchChangelog(request, expectedNbEntries, expectedResultCode, testName);
   }
 
-  private InternalSearchOperation searchChangelog(String filterString, Set<String> attributes,
-      List<Control> controls, int expectedNbEntries, ResultCode expectedResultCode, String testName) throws Exception
+  private SearchRequest newSearchRequest(String filterString) throws DirectoryException
   {
-    InternalSearchOperation searchOperation = null;
-    int sizeLimitZero = 0;
-    int timeLimitZero = 0;
-    InternalSearchListener noSearchListener = null;
+    return Requests.newSearchRequest("cn=changelog", SearchScope.WHOLE_SUBTREE, filterString)
+        .addAttribute("*", "+"); // all user and operational attributes
+  }
+
+  private InternalSearchOperation searchChangelog(SearchRequest request, int expectedNbEntries,
+      ResultCode expectedResultCode, String testName) throws Exception
+  {
+    InternalSearchOperation searchOp = null;
     int count = 0;
     do
     {
       Thread.sleep(10);
-      boolean typesOnlyFalse = false;
-      searchOperation = connection.processSearch("cn=changelog", SearchScope.WHOLE_SUBTREE,
-          DereferenceAliasesPolicy.NEVER, sizeLimitZero, timeLimitZero, typesOnlyFalse, filterString,
-          attributes, controls, noSearchListener);
+      searchOp = connection.processSearch(request);
       count++;
     }
-    while (count < 300 && searchOperation.getSearchEntries().size() != expectedNbEntries);
+    while (count < 300 && searchOp.getSearchEntries().size() != expectedNbEntries);
 
-    final List<SearchResultEntry> entries = searchOperation.getSearchEntries();
+    final List<SearchResultEntry> entries = searchOp.getSearchEntries();
     assertThat(entries).hasSize(expectedNbEntries);
     debugAndWriteEntries(getLDIFWriter(), entries, testName);
-    waitForSearchOpResult(searchOperation, expectedResultCode);
-    return searchOperation;
+    waitForSearchOpResult(searchOp, expectedResultCode);
+    return searchOp;
   }
 
   private InternalSearchOperation searchDNWithBaseScope(String dn, Set<String> attributes) throws Exception
   {
-    final InternalSearchOperation searchOp = connection.processSearch(
-        dn,
-        SearchScope.BASE_OBJECT,
-        DereferenceAliasesPolicy.NEVER,
-        0,     // Size limit
-        0,     // Time limit
-        false, // Types only
-        "(objectclass=*)",
-        attributes);
+    SearchRequest request = Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT, "(objectclass=*)")
+        .addAttribute(attributes);
+    final InternalSearchOperation searchOp = connection.processSearch(request);
     waitForSearchOpResult(searchOp, ResultCode.SUCCESS);
     return searchOp;
   }
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java
index 00796ef..07954cc 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java
@@ -37,6 +37,8 @@
 import org.opends.server.core.*;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.tools.LDAPModify;
 import org.opends.server.types.*;
 import org.testng.annotations.BeforeClass;
@@ -252,8 +254,7 @@
   {
     DN schemaDN = DN.valueOf("cn=schema");
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     DeleteOperationBasis deleteOperation =
          new DeleteOperationBasis(conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(),
                              null, schemaDN);
@@ -274,8 +275,7 @@
     DN currentSchemaDN = DN.valueOf("cn=schema");
     DN newSchemaDN     = DN.valueOf("cn=newschema");
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     ModifyDNOperationBasis modifyDNOperation =
          new ModifyDNOperationBasis(conn, InternalClientConnection.nextOperationID(),
                                InternalClientConnection.nextMessageID(), null,
@@ -301,11 +301,8 @@
   {
     String filterString = "(|(objectClass=*)(objectClass=ldapSubentry))";
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(DN.valueOf("cn=schema"), SearchScope.BASE_OBJECT,
-              SearchFilter.createFilterFromString(filterString));
+    final SearchRequest request = newSearchRequest("cn=schema", SearchScope.BASE_OBJECT, filterString);
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertNotNull(searchOperation);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
@@ -319,16 +316,12 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test()
-  public void testSimpleOneLevelSearch()
-         throws Exception
+  public void testSimpleOneLevelSearch() throws Exception
   {
     String filterString = "(|(objectClass=*)(objectClass=ldapSubentry))";
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(DN.valueOf("cn=schema"), SearchScope.SINGLE_LEVEL,
-              SearchFilter.createFilterFromString(filterString));
+    final SearchRequest request = newSearchRequest("cn=schema", SearchScope.SINGLE_LEVEL, filterString);
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertNotNull(searchOperation);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertTrue(searchOperation.getSearchEntries().isEmpty());
@@ -348,11 +341,8 @@
   {
     String filterString = "(|(objectClass=*)(objectClass=ldapSubentry))";
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(DN.valueOf("cn=schema"), SearchScope.WHOLE_SUBTREE,
-              SearchFilter.createFilterFromString(filterString));
+    final SearchRequest request = newSearchRequest("cn=schema", SearchScope.WHOLE_SUBTREE, filterString);
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertNotNull(searchOperation);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
@@ -372,12 +362,8 @@
   {
     String filterString = "(|(objectClass=*)(objectClass=ldapSubentry))";
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(DN.valueOf("cn=schema"),
-              SearchScope.SUBORDINATES,
-              SearchFilter.createFilterFromString(filterString));
+    final SearchRequest request = newSearchRequest("cn=schema", SearchScope.SUBORDINATES, filterString);
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertNotNull(searchOperation);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertTrue(searchOperation.getSearchEntries().isEmpty());
@@ -392,19 +378,17 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test()
-  public void testSearchMatchedDN()
-         throws Exception
+  public void testSearchMatchedDN() throws Exception
   {
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     DN baseDN = DN.valueOf("o=bogus,cn=schema");
     SearchFilter filter =
          SearchFilter.createFilterFromString("(objectClass=*)");
 
     for (SearchScope scope : SearchScope.values())
     {
-      InternalSearchOperation searchOperation =
-           conn.processSearch(baseDN, scope, filter);
+      final SearchRequest request = newSearchRequest(baseDN, scope, filter);
+      InternalSearchOperation searchOperation = conn.processSearch(request);
       assertNotNull(searchOperation.getMatchedDN(),
                     "No matched DN for scope " + scope);
     }
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
index 5827c9d..2df659f 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
@@ -41,7 +41,8 @@
 import org.opends.server.core.ModifyOperationBasis;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.protocols.ldap.LDAPFilter;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.*;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.Attributes;
@@ -62,6 +63,7 @@
 import static org.forgerock.opendj.ldap.ConditionResult.*;
 import static org.forgerock.opendj.ldap.ModificationType.*;
 import static org.mockito.Mockito.*;
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.types.Attributes.*;
 import static org.testng.Assert.*;
 
@@ -574,35 +576,27 @@
 
   @Test(dependsOnMethods = "testAdd")
   public void testSearchScope() throws Exception {
-    InternalClientConnection conn =
-        InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
 
-    InternalSearchOperation search =
-        conn.processSearch(DN.valueOf("dc=test,dc=com"), SearchScope.BASE_OBJECT,
-            LDAPFilter.decode("(objectClass=*)").toSearchFilter());
+    InternalSearchOperation search = conn.processSearch("dc=test,dc=com", SearchScope.BASE_OBJECT, "(objectClass=*)");
     List<SearchResultEntry> result = search.getSearchEntries();
 
     assertEquals(result.size(), 1);
     assertEquals(result.get(0).getName().toString(), "dc=test,dc=com");
 
-    search = conn.processSearch(DN.valueOf("dc=test,dc=com"),
-        SearchScope.BASE_OBJECT, LDAPFilter.decode("(ou=People)").toSearchFilter());
+    search = conn.processSearch("dc=test,dc=com", SearchScope.BASE_OBJECT, "(ou=People)");
     result = search.getSearchEntries();
 
     assertEquals(result.size(), 0);
 
-    search = conn.processSearch(DN.valueOf("dc=test,dc=com"),
-        SearchScope.SINGLE_LEVEL,
-        LDAPFilter.decode("(objectClass=*)").toSearchFilter());
+    search = conn.processSearch("dc=test,dc=com", SearchScope.SINGLE_LEVEL, "(objectClass=*)");
     result = search.getSearchEntries();
 
     assertEquals(result.size(), 1);
     assertEquals(result.get(0).getName().toString(),
         "ou=People,dc=test,dc=com");
 
-    search = conn.processSearch(DN.valueOf("dc=test,dc=com"),
-        SearchScope.SUBORDINATES,
-        LDAPFilter.decode("(objectClass=*)").toSearchFilter());
+    search = conn.processSearch("dc=test,dc=com", SearchScope.SUBORDINATES, "(objectClass=*)");
     result = search.getSearchEntries();
 
     assertEquals(result.size(), 13);
@@ -610,9 +604,7 @@
       assertThat(entry.getName().toString()).isNotEqualTo("dc=test,dc=com");
     }
 
-    search = conn.processSearch(DN.valueOf("dc=test,dc=com"),
-        SearchScope.WHOLE_SUBTREE,
-        LDAPFilter.decode("(objectClass=*)").toSearchFilter());
+    search = conn.processSearch("dc=test,dc=com", SearchScope.WHOLE_SUBTREE, "(objectClass=*)");
     result = search.getSearchEntries();
 
     assertEquals(result.size(), 14);
@@ -712,15 +704,9 @@
   private List<SearchResultEntry> doSubtreeSearch(InternalClientConnection conn, String filter,
       Set<String> attribs) throws Exception
   {
-    InternalSearchOperation search =
-        conn.processSearch(DN.valueOf("dc=test,dc=com"),
-            SearchScope.WHOLE_SUBTREE,
-            DereferenceAliasesPolicy.NEVER,
-            0,
-            0,
-            false,
-            LDAPFilter.decode(filter).toSearchFilter(),
-            attribs);
+    final SearchRequest request =
+        newSearchRequest("dc=test,dc=com", SearchScope.WHOLE_SUBTREE, filter).addAttribute(attribs);
+    InternalSearchOperation search = conn.processSearch(request);
     return search.getSearchEntries();
   }
 
@@ -1255,20 +1241,9 @@
     assertFalse(orfound);
     assertTrue(apfound);
 
-    InternalClientConnection conn =
-        InternalClientConnection.getRootConnection();
-    Set<String> attribs = new LinkedHashSet<String>();
-    attribs.add(ATTR_DEBUG_SEARCH_INDEX);
-
-    InternalSearchOperation search =
-        conn.processSearch(DN.valueOf("dc=test,dc=com"),
-                           SearchScope.SUBORDINATES,
-                           DereferenceAliasesPolicy.NEVER,
-                           0,
-                           0,
-                           false,
-                           LDAPFilter.decode("(givenName~=Aaccf)").toSearchFilter(),
-                           attribs);
+    final SearchRequest request = newSearchRequest("dc=test,dc=com", SearchScope.SUBORDINATES, "(givenName~=Aaccf)")
+        .addAttribute(ATTR_DEBUG_SEARCH_INDEX);
+    InternalSearchOperation search = getRootConnection().processSearch(request);
 
     List<SearchResultEntry> result = search.getSearchEntries();
 
@@ -1422,8 +1397,6 @@
     assertEquals(resultCode, 0);
   }
 
-
-
   @Test(dependsOnMethods = {"testDeleteEntry", "testSearchScope",
       "testSearchIndex", "testMatchedDN"})
   public void testSearchNotIndexed() throws Exception {
@@ -1433,21 +1406,9 @@
       assertNotNull(backend.getEntry(entry.getName()));
     }
 
-    InternalClientConnection conn =
-        InternalClientConnection.getRootConnection();
-    Set<String> attribs = new LinkedHashSet<String>();
-    attribs.add(ATTR_DEBUG_SEARCH_INDEX);
-
-    InternalSearchOperation search =
-        conn.processSearch(DN.valueOf("dc=test,dc=com"),
-            SearchScope.SUBORDINATES,
-            DereferenceAliasesPolicy.NEVER,
-            0,
-            0,
-            false,
-            LDAPFilter.decode("(carLicense=377*)").toSearchFilter(),
-            attribs);
-
+    final SearchRequest request = newSearchRequest("dc=test,dc=com", SearchScope.SUBORDINATES, "(carLicense=377*)")
+        .addAttribute(ATTR_DEBUG_SEARCH_INDEX);
+    InternalSearchOperation search = getRootConnection().processSearch(request);
     List<SearchResultEntry> result = search.getSearchEntries();
 
     //No indexes should be used.
@@ -1524,17 +1485,14 @@
     ResultCode expectedResultCode
     ) throws Exception
   {
-    InternalClientConnection conn =
-      InternalClientConnection.getRootConnection();
-
-    // Filter for the search
-    SearchFilter filter = LDAPFilter.decode("(objectClass=*)").toSearchFilter();
+    InternalClientConnection conn = getRootConnection();
+    SearchFilter filter = SearchFilter.createFilterFromString("(objectClass=*)");
 
     // Test is performed with each and every scope
     for (SearchScope scope: SearchScope.values())
     {
-      InternalSearchOperation searchOperation =
-        conn.processSearch(searchBaseDN, scope, filter);
+      final SearchRequest request = newSearchRequest(searchBaseDN, scope, filter);
+      InternalSearchOperation searchOperation = conn.processSearch(request);
 
       assertEquals(searchOperation.getResultCode(), expectedResultCode);
       assertEquals(searchOperation.getMatchedDN(), expectedMatchedDN);
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/controls/PersistentSearchControlTest.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/controls/PersistentSearchControlTest.java
index ea2ffde..4400bc5 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/controls/PersistentSearchControlTest.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/controls/PersistentSearchControlTest.java
@@ -33,25 +33,26 @@
 import org.forgerock.opendj.io.ASN1Writer;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.ByteStringBuilder;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.ModificationType;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
 import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.protocols.ldap.LDAPModification;
 import org.opends.server.protocols.ldap.LDAPReader;
 import org.opends.server.tools.LDAPSearch;
 import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import static org.assertj.core.api.Assertions.*;
 import static org.opends.server.controls.PersistentSearchChangeType.*;
+import static org.opends.server.protocols.internal.Requests.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.testng.Assert.*;
 
@@ -546,21 +547,12 @@
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
 
     //Create a persistent search request.
-    Set<String> attributes = new LinkedHashSet<String>();
-    attributes.add("cn");
-    List<Control> controls = new LinkedList<Control>();
-          // Creates psearch control
-    Set<PersistentSearchChangeType> changeTypes =
-        EnumSet.of(ADD, DELETE, MODIFY, MODIFY_DN);
-    PersistentSearchControl persSearchControl = new PersistentSearchControl(
-          changeTypes, true, true);
-      controls.add(persSearchControl);
-    final InternalSearchOperation search =
-        conn.processSearch("o=test", SearchScope.BASE_OBJECT,
-            DereferenceAliasesPolicy.NEVER, 0, // Size limit
-            0, // Time limit
-            true, // Types only
-            "(objectClass=*)", attributes, controls, null);
+    Set<PersistentSearchChangeType> changeTypes = EnumSet.of(ADD, DELETE, MODIFY, MODIFY_DN);
+    SearchRequest request = newSearchRequest("o=test", SearchScope.BASE_OBJECT, "(objectClass=*)")
+        .setTypesOnly(true)
+        .addAttribute("cn")
+        .addControl(new PersistentSearchControl(changeTypes, true, true));
+    final InternalSearchOperation search = conn.processSearch(request);
 
     Thread t = new Thread(new Runnable() {
       @Override
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/BackendConfigManagerTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/BackendConfigManagerTestCase.java
index 7354fdc..f82756b 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/BackendConfigManagerTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/BackendConfigManagerTestCase.java
@@ -35,17 +35,18 @@
 import org.opends.server.api.Backend;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
 import org.opends.server.types.Attributes;
 import org.opends.server.types.DN;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.Entry;
 import org.opends.server.types.Modification;
-import org.opends.server.types.SearchFilter;
 import org.opends.server.util.StaticUtils;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import static org.opends.server.protocols.internal.InternalClientConnection.*;
+import static org.opends.server.protocols.internal.Requests.*;
 import static org.testng.Assert.*;
 
 /**
@@ -265,9 +266,8 @@
 
     InternalClientConnection conn = getRootConnection();
     // Make sure that both entries exist.
-    InternalSearchOperation internalSearch =
-         conn.processSearch(parentBaseDN, SearchScope.WHOLE_SUBTREE,
-              SearchFilter.createFilterFromString("(objectClass=*)"));
+    final SearchRequest request = newSearchRequest(parentBaseDN, SearchScope.WHOLE_SUBTREE, "(objectClass=*)");
+    InternalSearchOperation internalSearch = conn.processSearch(request);
     assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS);
     assertEquals(internalSearch.getSearchEntries().size(), 2);
 
@@ -275,8 +275,7 @@
 
     // Make sure that we can't remove the parent backend with the child still
     // in place.
-    DeleteOperation deleteOperation =
-         conn.processDelete(parentBackendEntry.getName());
+    DeleteOperation deleteOperation = conn.processDelete(parentBackendEntry.getName());
     assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
     assertNotNull(DirectoryServer.getBackend(parentBackendID));
 
@@ -337,23 +336,20 @@
     assertFalse(DirectoryServer.isNamingContext(childBaseDN));
 
 
-    InternalClientConnection conn = getRootConnection();
     // Verify that we can see both entries with a subtree search.
-    InternalSearchOperation internalSearch =
-         conn.processSearch(parentBaseDN, SearchScope.WHOLE_SUBTREE,
-              SearchFilter.createFilterFromString("(objectClass=*)"));
+    final SearchRequest request = newSearchRequest(parentBaseDN, SearchScope.WHOLE_SUBTREE, "(objectClass=*)");
+    InternalSearchOperation internalSearch = getRootConnection().processSearch(request);
     assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS);
     assertEquals(internalSearch.getSearchEntries().size(), 2);
 
 
     // Delete the backends from the server.
-    DeleteOperation deleteOperation =
-         conn.processDelete(childBackendEntry.getName());
+    DeleteOperation deleteOperation = getRootConnection().processDelete(childBackendEntry.getName());
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
     assertNull(DirectoryServer.getBackend(childBackendID));
     assertTrue(parentBackend.getSubordinateBackends().length == 0);
 
-    deleteOperation = conn.processDelete(parentBackendEntry.getName());
+    deleteOperation = getRootConnection().processDelete(parentBackendEntry.getName());
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
     assertNull(DirectoryServer.getBackend(parentBackendID));
   }
@@ -433,30 +429,19 @@
 
     InternalClientConnection conn = getRootConnection();
     // Verify that a subtree search can see all three entries.
-    InternalSearchOperation internalSearch =
-         conn.processSearch(parentBaseDN, SearchScope.WHOLE_SUBTREE,
-              SearchFilter.createFilterFromString("(objectClass=*)"));
-    assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS);
-    assertEquals(internalSearch.getSearchEntries().size(), 3);
+    final SearchRequest request = newSearchRequest(parentBaseDN, SearchScope.WHOLE_SUBTREE, "(objectClass=*)");
+    assertSearchResultsSize(request, 3);
 
 
     // Disable the intermediate (child) backend.  This should be allowed.
     ArrayList<Modification> mods = new ArrayList<Modification>();
-    mods.add(new Modification(ModificationType.REPLACE,
-        Attributes.create("ds-cfg-enabled",
-                                            "false")));
+    mods.add(new Modification(ModificationType.REPLACE, Attributes.create("ds-cfg-enabled", "false")));
     ModifyOperation modifyOperation =
          conn.processModify(childBackendEntry.getName(), mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
 
 
-    // Make sure that we now only see two entries with the subtree search
-    // (and those two entries should be the parent and grandchild base entries).
-    internalSearch =
-         conn.processSearch(parentBaseDN, SearchScope.WHOLE_SUBTREE,
-              SearchFilter.createFilterFromString("(objectClass=*)"));
-    assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS);
-    assertEquals(internalSearch.getSearchEntries().size(), 2);
+    assertSearchResultsSize(request, 2);
 
 
     // Re-enable the intermediate backend.
@@ -478,11 +463,7 @@
     // entries across stops and restarts, a subtree search below the parent
     // should still only return two entries, which means that it's going through
     // the entire chain of backends.
-    internalSearch =
-         conn.processSearch(parentBaseDN, SearchScope.WHOLE_SUBTREE,
-              SearchFilter.createFilterFromString("(objectClass=*)"));
-    assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS);
-    assertEquals(internalSearch.getSearchEntries().size(), 2);
+    assertSearchResultsSize(request, 2);
 
 
     // Add the child entry back into the server to get things back to the way
@@ -490,13 +471,8 @@
     createEntry(childBaseDN, childBackend);
 
 
-    // We should again be able to see all three entries when performing a
-    // search.
-    internalSearch =
-         conn.processSearch(parentBaseDN, SearchScope.WHOLE_SUBTREE,
-              SearchFilter.createFilterFromString("(objectClass=*)"));
-    assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS);
-    assertEquals(internalSearch.getSearchEntries().size(), 3);
+    // We should again be able to see all three entries when performing a search
+    assertSearchResultsSize(request, 3);
 
 
     // Get rid of the entries in the proper order.
@@ -517,6 +493,13 @@
     assertNull(DirectoryServer.getBackend(parentBackendID));
   }
 
+  private void assertSearchResultsSize(final SearchRequest request, int expected)
+  {
+    InternalSearchOperation internalSearch = getRootConnection().processSearch(request);
+    assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS);
+    assertEquals(internalSearch.getSearchEntries().size(), expected);
+  }
+
   private void createBackend(DN childBaseDN, Backend<?> childBackend, Backend<?> parentBackend,
       Backend<?> grandchildBackend) throws DirectoryException
   {
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java
index cc4ae53..e038963 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java
@@ -42,16 +42,18 @@
 import org.opends.server.plugins.InvocationCounterPlugin;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.Requests;
+import org.opends.server.protocols.internal.SearchRequest;
 import org.opends.server.protocols.ldap.*;
 import org.opends.server.tools.LDAPModify;
 import org.opends.server.tools.LDAPWriter;
 import org.opends.server.types.*;
-import org.opends.server.util.ServerConstants;
 import org.opends.server.util.StaticUtils;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import static org.assertj.core.api.Assertions.*;
 import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.testng.Assert.*;
@@ -1179,8 +1181,7 @@
 
     // Real attributes (these are all user attributes).
     List<String> realAttrTypes =
-        Arrays.asList("objectclass", "uid", "cn", "sn", "givenname",
-            "userpassword");
+        Arrays.asList("objectclass", "uid", "cn", "sn", "givenname", "userpassword");
 
     // Virtual attributes (these are all operational attributes).
     List<String> virtualAttrTypes =
@@ -1201,50 +1202,32 @@
         "cn: Test User",
         "userPassword: password");
 
-    Entry userEntry = DirectoryServer.getEntry(userDN);
-    assertNotNull(userEntry);
-
-    LinkedHashSet<String> attributes = new LinkedHashSet<String>();
+    final SearchRequest request = Requests.newSearchRequest(userDN, SearchScope.BASE_OBJECT, "(objectClass=*)");
+    request.setTypesOnly(typesOnly);
     switch (filterType)
     {
     case DEFAULT:
       // Only user attributes.
-      attributes = null;
       break;
     case WILDCARDS:
-      attributes.add("*");
-      attributes.add("+");
+      request.addAttribute("*", "+");
       break;
     case ENUMERATED:
-      attributes.addAll(realAttrTypes);
-      attributes.addAll(virtualAttrTypes);
+      request.addAttribute(realAttrTypes);
+      request.addAttribute(virtualAttrTypes);
       break;
     }
 
-    List<Control> controls = new LinkedList<Control>();
-
     if (stripRealAttributes)
     {
-      controls.add(new LDAPControl(ServerConstants.OID_VIRTUAL_ATTRS_ONLY,
-          false));
+      request.addControl(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, false));
     }
-
     if (stripVirtualAttributes)
     {
-      controls.add(new LDAPControl(ServerConstants.OID_REAL_ATTRS_ONLY,
-          false));
+      request.addControl(new LDAPControl(OID_REAL_ATTRS_ONLY, false));
     }
 
-    InternalClientConnection conn =
-        InternalClientConnection.getRootConnection();
-
-    InternalSearchOperation search =
-        conn.processSearch(userDNString, SearchScope.BASE_OBJECT,
-            DereferenceAliasesPolicy.NEVER, 0, // Size limit
-            0, // Time limit
-            typesOnly, // Types only
-            "(objectClass=*)", attributes, controls, null);
-
+    InternalSearchOperation search = getRootConnection().processSearch(request);
     assertEquals(search.getResultCode(), ResultCode.SUCCESS);
 
     LinkedList<SearchResultEntry> entries = search.getSearchEntries();
@@ -1279,16 +1262,14 @@
           {
             if (!attr.isEmpty())
             {
-              messages.add("Unexpected non-empty real attribute: "
-                  + attrType);
+              messages.add("Unexpected non-empty real attribute: " + attrType);
             }
           }
           else
           {
             if (attr.isEmpty())
             {
-              messages.add("Unexpected empty real attribute: "
-                  + attrType);
+              messages.add("Unexpected empty real attribute: " + attrType);
             }
           }
         }
@@ -1336,23 +1317,21 @@
           {
             if (!attr.isEmpty())
             {
-              messages.add("Unexpected non-empty virtual attribute: "
-                  + attrType);
+              messages.add("Unexpected non-empty virtual attribute: " + attrType);
             }
           }
           else
           {
             if (attr.isEmpty())
             {
-              messages.add("Unexpected empty virtual attribute: "
-                  + attrType);
+              messages.add("Unexpected empty virtual attribute: " + attrType);
             }
           }
         }
       }
     }
 
-    assertTrue(messages.isEmpty(), "Entry invalid: " + messages);
+    assertThat(messages).isEmpty();
   }
 
 
@@ -1373,25 +1352,18 @@
             Arrays.asList("objectClass", "cn", "cn;lang-fr") },
         {
             Arrays.asList("*", "+"),
-            Arrays.asList("objectClass", "cn", "cn;lang-fr", "entryDN",
-                "createTimestamp") },
+            Arrays.asList("objectClass", "cn", "cn;lang-fr", "entryDN", "createTimestamp") },
         {
-            Arrays.asList("objectClass", "cn", "cn;lang-fr", "entryDN",
-                "createTimestamp"),
-            Arrays.asList("objectClass", "cn", "cn;lang-fr", "entryDN",
-                "createTimestamp") },
+            Arrays.asList("objectClass", "cn", "cn;lang-fr", "entryDN", "createTimestamp"),
+            Arrays.asList("objectClass", "cn", "cn;lang-fr", "entryDN", "createTimestamp") },
         {
-            Arrays.asList("OBJECTCLASS", "commonName", "commonName;LANG-FR", "entrydn",
-                "CREATETIMESTAMP"),
-            Arrays.asList("OBJECTCLASS", "commonName",
-                "commonName;LANG-FR", "entrydn", "CREATETIMESTAMP") },
+            Arrays.asList("OBJECTCLASS", "commonName", "commonName;LANG-FR", "entrydn", "CREATETIMESTAMP"),
+            Arrays.asList("OBJECTCLASS", "commonName", "commonName;LANG-FR", "entrydn", "CREATETIMESTAMP") },
         {
             Arrays.asList("*", "+", "OBJECTCLASS", "commonName",
                 "commonName;LANG-FR", "entrydn", "CREATETIMESTAMP"),
-            Arrays.asList("OBJECTCLASS", "commonName",
-                "commonName;LANG-FR", "entrydn", "CREATETIMESTAMP") },
-        { Arrays.asList("name"),
-            Arrays.asList("givenName", "sn", "cn", "cn;lang-fr") },
+            Arrays.asList("OBJECTCLASS", "commonName", "commonName;LANG-FR", "entrydn", "CREATETIMESTAMP") },
+        { Arrays.asList("name"), Arrays.asList("givenName", "sn", "cn", "cn;lang-fr") },
         { Arrays.asList("name;lang-fr"), Arrays.asList("cn;lang-fr") },
         { Arrays.asList("name;LANG-FR"), Arrays.asList("cn;LANG-FR") }, };
   }
@@ -1431,22 +1403,9 @@
         "cn;lang-fr: Test Usager",
         "userPassword: password");
 
-    Entry userEntry = DirectoryServer.getEntry(userDN);
-    assertNotNull(userEntry);
-
-    LinkedHashSet<String> attributes =
-      new LinkedHashSet<String>(requestedAttributes);
-
-    InternalClientConnection conn =
-      InternalClientConnection.getRootConnection();
-
-    InternalSearchOperation search =
-      conn.processSearch(userDNString, SearchScope.BASE_OBJECT,
-          DereferenceAliasesPolicy.NEVER, 0, // Size limit
-          0, // Time limit
-          false, // Types only
-          "(objectClass=*)", attributes);
-
+    SearchRequest request = Requests.newSearchRequest(userDNString, SearchScope.BASE_OBJECT, "(objectClass=*)")
+        .addAttribute(requestedAttributes);
+    InternalSearchOperation search = getRootConnection().processSearch(request);
     assertEquals(search.getResultCode(), ResultCode.SUCCESS);
 
     LinkedList<SearchResultEntry> entries = search.getSearchEntries();
@@ -1464,8 +1423,7 @@
       actualNames.add(attribute.getNameWithOptions());
     }
 
-    assertTrue(actualNames.containsAll(expectedAttributes),
-        "Expected: " + expectedAttributes + " got " + actualNames);
+    assertThat(actualNames).containsAll(expectedAttributes);
   }
 
 
@@ -1503,9 +1461,6 @@
         "cn;lang-fr: Test Usager",
         "userPassword: password");
 
-    Entry userEntry = DirectoryServer.getEntry(userDN);
-    assertNotNull(userEntry);
-
     LinkedHashSet<String> attributes =
       new LinkedHashSet<String>(requestedAttributes);
 
@@ -1534,8 +1489,7 @@
       actualNames.add(attribute.getAttributeType());
     }
 
-    assertTrue(actualNames.containsAll(expectedAttributes),
-        "Expected: " + expectedAttributes + " got " + actualNames);
+    assertThat(actualNames).containsAll(expectedAttributes);
   }
 
 
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/ResourceLimitsPolicyTest.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/ResourceLimitsPolicyTest.java
index 7accc0b..200bba4 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/ResourceLimitsPolicyTest.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/networkgroups/ResourceLimitsPolicyTest.java
@@ -37,9 +37,9 @@
 import org.opends.server.api.ClientConnection;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.protocols.ldap.LDAPFilter;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.DN;
-import org.opends.server.types.SearchFilter;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -182,10 +182,8 @@
     InternalClientConnection conn1 = new InternalClientConnection(DN.NULL_DN);
     limits.addConnection(conn1);
 
-    InternalSearchOperation search = conn1.processSearch(
-        DN.valueOf("dc=example,dc=com"),
-        SearchScope.BASE_OBJECT,
-        LDAPFilter.decode(searchFilter).toSearchFilter());
+    final SearchRequest request = newSearchRequest("dc=example,dc=com", SearchScope.BASE_OBJECT, searchFilter);
+    InternalSearchOperation search = conn1.processSearch(request);
 
     assertOperationIsAllowed(limits, conn1, search, success);
     limits.removeConnection(conn1);
@@ -207,25 +205,19 @@
     InternalClientConnection conn = new InternalClientConnection(DN.NULL_DN);
     limits.addConnection(conn);
 
-    final DN dn = DN.valueOf("dc=example,dc=com");
-    final SearchFilter all = SearchFilter.createFilterFromString("(objectclass=*)");
-
-    final InternalSearchOperation search1 =
-        conn.processSearch(dn, SearchScope.BASE_OBJECT, all);
+    final SearchRequest request = newSearchRequest("dc=example,dc=com", SearchScope.BASE_OBJECT, "(objectclass=*)");
+    final InternalSearchOperation search1 = conn.processSearch(request);
     assertOperationIsAllowed(limits, conn, search1, true,
         "First operation should be allowed");
 
-    final InternalSearchOperation search2 =
-        conn.processSearch(dn, SearchScope.BASE_OBJECT, all);
-    assertOperationIsAllowed(limits, conn,
-        search2, false,
+    final InternalSearchOperation search2 = conn.processSearch(request);
+    assertOperationIsAllowed(limits, conn, search2, false,
         "Second operation in the same interval should be disallowed");
 
     // Wait for the end of the interval => counters are reset
     Thread.sleep(interval);
 
-    final InternalSearchOperation search3 =
-        conn.processSearch(dn, SearchScope.BASE_OBJECT, all);
+    final InternalSearchOperation search3 = conn.processSearch(request);
     assertOperationIsAllowed(limits, conn, search3, true,
         "Third operation should be allowed");
   }
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/crypto/CryptoManagerTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/crypto/CryptoManagerTestCase.java
index 8dfafee..754e8fd 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/crypto/CryptoManagerTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/crypto/CryptoManagerTestCase.java
@@ -33,7 +33,6 @@
 import java.io.OutputStream;
 import java.security.MessageDigest;
 import java.util.Arrays;
-import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -44,16 +43,19 @@
 import javax.naming.ldap.LdapName;
 
 import org.forgerock.i18n.LocalizableMessage;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.admin.ads.ADSContext;
 import org.opends.admin.ads.util.ConnectionUtils;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.config.ConfigConstants;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.types.*;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
+import org.opends.server.types.CryptoManager;
+import org.opends.server.types.CryptoManagerException;
+import org.opends.server.types.DN;
+import org.opends.server.types.Entry;
 import org.opends.server.util.EmbeddedUtils;
 import org.opends.server.util.StaticUtils;
 import org.opends.server.util.TimeThread;
@@ -64,6 +66,7 @@
 
 import com.forgerock.opendj.cli.CliConstants;
 
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.testng.Assert.*;
 
 /**
@@ -385,19 +388,8 @@
             .append(FILTER_CIPHER_TRANSFORMATION_NAME)
             .append(FILTER_CIPHER_KEY_LENGTH)
             .append(")").toString();
-    final LinkedHashSet<String> requestedAttributes
-            = new LinkedHashSet<String>();
-    requestedAttributes.add("dn");
-    final InternalClientConnection icc
-            = InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOp = icc.processSearch(
-            baseDN,
-            SearchScope.SINGLE_LEVEL,
-            DereferenceAliasesPolicy.NEVER,
-            /* size limit */ 0, /* time limit */ 0,
-            /* types only */ false,
-            SearchFilter.createFilterFromString(searchFilter),
-            requestedAttributes);
+    final SearchRequest request = newSearchRequest(baseDN, SearchScope.SINGLE_LEVEL, searchFilter).addAttribute("dn");
+    InternalSearchOperation searchOp = getRootConnection().processSearch(request);
     assertTrue(0 < searchOp.getSearchEntries().size());
 
     String compromisedTime = TimeThread.getGeneralizedTime();
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperationTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperationTestCase.java
index 4afef34..75f4e47 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperationTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperationTestCase.java
@@ -26,10 +26,7 @@
  */
 package org.opends.server.crypto;
 
-import java.util.LinkedHashSet;
-
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.admin.ads.ADSContext;
@@ -39,14 +36,16 @@
 import org.opends.server.core.ExtendedOperation;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.DN;
 import org.opends.server.types.Entry;
-import org.opends.server.types.SearchFilter;
 import org.opends.server.util.ServerConstants;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.testng.Assert.*;
 
 /**
@@ -108,19 +107,9 @@
             .append(FILTER_CIPHER_TRANSFORMATION_NAME)
             .append(FILTER_CIPHER_KEY_LENGTH)
             .append(")").toString();
-    final LinkedHashSet<String> requestedAttributes
-            = new LinkedHashSet<String>();
-    requestedAttributes.add(ConfigConstants.ATTR_CRYPTO_SYMMETRIC_KEY);
-    final InternalClientConnection icc
-            = InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOp = icc.processSearch(
-            baseDN,
-            SearchScope.SINGLE_LEVEL,
-            DereferenceAliasesPolicy.NEVER,
-            /* size limit */ 0, /* time limit */ 0,
-            /* types only */ false,
-            SearchFilter.createFilterFromString(searchFilter),
-            requestedAttributes);
+    final SearchRequest request = newSearchRequest(baseDN, SearchScope.SINGLE_LEVEL, searchFilter)
+        .addAttribute(ConfigConstants.ATTR_CRYPTO_SYMMETRIC_KEY);
+    InternalSearchOperation searchOp = getRootConnection().processSearch(request);
     assertTrue(0 < searchOp.getSearchEntries().size());
 
     final InternalClientConnection internalConnection =
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntityTagVirtualAttributeProviderTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntityTagVirtualAttributeProviderTestCase.java
index aec3cc3..bc848ea 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntityTagVirtualAttributeProviderTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntityTagVirtualAttributeProviderTestCase.java
@@ -27,7 +27,6 @@
 
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.SortedSet;
 import java.util.TreeSet;
@@ -36,7 +35,6 @@
 import org.forgerock.i18n.LocalizableMessageBuilder;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.ConditionResult;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.ModificationType;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
@@ -59,6 +57,8 @@
 import org.opends.server.core.SearchOperationWrapper;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.Requests;
+import org.opends.server.protocols.internal.SearchRequest;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.protocols.ldap.LDAPModification;
 import org.opends.server.types.Attribute;
@@ -849,12 +849,8 @@
   private Entry readEntry(InternalClientConnection conn, String userDN)
       throws DirectoryException
   {
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(2);
-    attrList.add("*");
-    attrList.add(ETAG);
-    InternalSearchOperation searchOperation = conn.processSearch(userDN,
-        SearchScope.BASE_OBJECT, DereferenceAliasesPolicy.NEVER, 0, 0,
-        false, "(objectClass=*)", attrList);
+    SearchRequest request = Requests.newSearchRequest(userDN, SearchScope.BASE_OBJECT, "(objectClass=*)", "*", ETAG);
+    InternalSearchOperation searchOperation = conn.processSearch(request);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
     Entry e = searchOperation.getSearchEntries().get(0);
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProviderTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProviderTestCase.java
index d64a29d..f61b2f0 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProviderTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProviderTestCase.java
@@ -27,7 +27,6 @@
 package org.opends.server.extensions;
 
 import java.util.Collections;
-import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -41,6 +40,8 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.types.*;
 import org.opends.server.workflowelement.localbackend.LocalBackendSearchOperation;
@@ -48,6 +49,7 @@
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.testng.Assert.*;
 
@@ -261,18 +263,9 @@
   public void testSearchEntryDNAttrInMatchingFilter(DN entryDN)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(entryDN=" + entryDN.toString() +
-                                             ")");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("entrydn");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(entryDN=" + entryDN + ")")
+        .addAttribute("entrydn");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -295,17 +288,9 @@
   public void testSearchEntryDNAttrInNonMatchingFilter(DN entryDN)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(entryDN=cn=Not A Match)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("entrydn");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(entryDN=cn=Not A Match)")
+        .addAttribute("entrydn");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 0);
   }
 
@@ -325,23 +310,10 @@
   public void testSearchEntryDNAttrRealAttrsOnly(DN entryDN)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(objectClass=*)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("entrydn");
-
-    LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         new InternalSearchOperation(conn, InternalClientConnection.nextOperationID(),
-                                     InternalClientConnection.nextMessageID(), requestControls,
-                                     entryDN, SearchScope.BASE_OBJECT,
-                                     DereferenceAliasesPolicy.NEVER, 0,
-                                     0, false, filter, attrList, null);
-    searchOperation.run();
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(objectClass=*)")
+        .addAttribute("entrydn")
+        .addControl(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -350,7 +322,6 @@
   }
 
 
-
   /**
    * Performs an internal search to retrieve the specified entry, ensuring that
    * the entryDN attribute is included when the entryDN attribute is
@@ -365,23 +336,11 @@
   public void testSearchEntryDNAttrVirtualAttrsOnly(DN entryDN)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(objectClass=*)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("entrydn");
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(objectClass=*)")
+        .addAttribute("entrydn")
+        .addControl(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, true));
 
-    LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, true));
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         new InternalSearchOperation(conn, InternalClientConnection.nextOperationID(),
-                                     InternalClientConnection.nextMessageID(), requestControls,
-                                     entryDN, SearchScope.BASE_OBJECT,
-                                     DereferenceAliasesPolicy.NEVER, 0,
-                                     0, false, filter, attrList, null);
-    searchOperation.run();
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProviderTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProviderTestCase.java
index 96d1fec..5f3426d 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProviderTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProviderTestCase.java
@@ -40,12 +40,15 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.types.*;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 import static org.testng.Assert.*;
@@ -298,17 +301,9 @@
     String uuidString = UUID.nameUUIDFromBytes(
                              getBytes(entryDN.toNormalizedString())).toString();
 
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(entryUUID=" + uuidString + ")");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("entryuuid");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(entryUUID=" + uuidString + ")")
+        .addAttribute("entryuuid");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -331,17 +326,9 @@
   public void testSearchEntryUUIDAttrInNonMatchingFilter(DN entryDN)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(entryUUID=wrong)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("entryuuid");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(entryUUID=wrong)")
+        .addAttribute("entryuuid");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 0);
   }
 
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExtensionTestUtils.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExtensionTestUtils.java
index 785c49a..9ca15c8 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExtensionTestUtils.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExtensionTestUtils.java
@@ -25,20 +25,18 @@
  */
 package org.opends.server.extensions;
 
-import org.opends.server.protocols.internal.InternalClientConnection;
+import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.schema.SchemaConstants;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.DN;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.opends.server.types.Entry;
-import org.opends.server.types.SearchFilter;
-import org.forgerock.opendj.ldap.SearchScope;
 
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.testng.Assert.*;
 
-import java.util.LinkedHashSet;
-
 /**
  * Utility class providing common code for extensions tests.
  */
@@ -49,13 +47,8 @@
   public static void testSearchEmptyAttrs(DN entryDN,
       AttributeType attributeType) throws Exception
   {
-    SearchFilter filter =
-        SearchFilter.createFilterFromString("(objectClass=*)");
-
-    InternalClientConnection conn =
-        InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-        conn.processSearch(entryDN, SearchScope.BASE_OBJECT, filter);
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(objectClass=*)");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -66,17 +59,10 @@
   public static void testSearchNoAttrs(DN entryDN, AttributeType attributeType)
       throws Exception
   {
-    SearchFilter filter =
-        SearchFilter.createFilterFromString("(objectClass=*)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add(SchemaConstants.NO_ATTRIBUTES);
-
-    InternalClientConnection conn =
-        InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-        conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-            DereferenceAliasesPolicy.NEVER, 0, 0, false, filter,
-            attrList);
+    final SearchRequest request =
+        newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(objectClass=*)")
+            .addAttribute(SchemaConstants.NO_ATTRIBUTES);
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -87,17 +73,9 @@
   public static void testSearchAllUserAttrs(DN entryDN,
       AttributeType attributeType) throws Exception
   {
-    SearchFilter filter =
-        SearchFilter.createFilterFromString("(objectClass=*)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("*");
-
-    InternalClientConnection conn =
-        InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-        conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-            DereferenceAliasesPolicy.NEVER, 0, 0, false, filter,
-            attrList);
+    final SearchRequest request =
+        newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(objectClass=*)").addAttribute("*");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -108,17 +86,9 @@
   public static void testSearchAllOperationalAttrs(DN entryDN,
       AttributeType attributeType) throws Exception
   {
-    SearchFilter filter =
-        SearchFilter.createFilterFromString("(objectClass=*)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("+");
-
-    InternalClientConnection conn =
-        InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-        conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-            DereferenceAliasesPolicy.NEVER, 0, 0, false, filter,
-            attrList);
+    final SearchRequest request =
+        newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(objectClass=*)").addAttribute("+");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -129,17 +99,9 @@
   public static void testSearchAttr(DN entryDN, String attrName,
       AttributeType attributeType) throws Exception
   {
-    SearchFilter filter =
-        SearchFilter.createFilterFromString("(objectClass=*)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add(attrName);
-
-    InternalClientConnection conn =
-        InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-        conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-            DereferenceAliasesPolicy.NEVER, 0, 0, false, filter,
-            attrList);
+    final SearchRequest request =
+        newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(objectClass=*)").addAttribute(attrName);
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -150,17 +112,9 @@
   public static void testSearchExcludeAttr(DN entryDN,
       AttributeType attributeType) throws Exception
   {
-    SearchFilter filter =
-        SearchFilter.createFilterFromString("(objectClass=*)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("objectClass");
-
-    InternalClientConnection conn =
-        InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-        conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-            DereferenceAliasesPolicy.NEVER, 0, 0, false, filter,
-            attrList);
+    final SearchRequest request =
+        newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(objectClass=*)").addAttribute("objectClass");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/GoverningStructureRuleVirtualAttributeProviderTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/GoverningStructureRuleVirtualAttributeProviderTestCase.java
index 63bd552..44e6c5a 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/GoverningStructureRuleVirtualAttributeProviderTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/GoverningStructureRuleVirtualAttributeProviderTestCase.java
@@ -26,36 +26,39 @@
  */
 package org.opends.server.extensions;
 
-import static org.opends.server.util.ServerConstants.*;
-import static org.testng.Assert.*;
-
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 
+import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
+import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.admin.std.meta.VirtualAttributeCfgDefn;
 import org.opends.server.api.VirtualAttributeProvider;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeType;
-import org.forgerock.opendj.ldap.ByteString;
 import org.opends.server.types.Control;
 import org.opends.server.types.DN;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.opends.server.types.Entry;
 import org.opends.server.types.SearchFilter;
-import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.types.VirtualAttributeRule;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.testng.Assert.*;
+
 /**
  * A set of test cases for the governing structure rule virtual attribute
  * provider.
@@ -320,17 +323,9 @@
   public void testSearchGovStructRuleInMatchingFilter(DN entryDN,String oc)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("governingstructurerule="+oc);
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("governingStructureRule");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "governingstructurerule=" + oc)
+        .addAttribute("governingStructureRule");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -353,22 +348,12 @@
   public void testSearchGovStructRuleAttrInNonMatchingFilter(DN entryDN)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(governingStructureRule=1)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("governingStructureRuleType");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(governingStructureRule=1)")
+        .addAttribute("governingStructureRuleType");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 0);
   }
 
-
-
   /**
    * Performs an internal search to retrieve the specified entry, ensuring that
    * the governingStructureRule attribute is not included when that attribute is
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProviderTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProviderTestCase.java
index dd43200..19146ab 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProviderTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProviderTestCase.java
@@ -38,12 +38,15 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.types.*;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 import static org.testng.Assert.*;
@@ -350,17 +353,9 @@
   public void testSearchhasSubordinatesAttrInMatchingFilter(DN entryDN, boolean hasSubs)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(hasSubordinates=" + hasSubs + ")");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("hasSubordinates");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(hasSubordinates=" + hasSubs + ")")
+        .addAttribute("hasSubordinates");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -368,8 +363,6 @@
     assertTrue(e.hasAttribute(hasSubordinatesType));
   }
 
-
-
   /**
    * Performs an internal search to retrieve the specified entry, ensuring that
    * no entries are returned when the hasSubordinates attribute is used in the search
@@ -383,17 +376,9 @@
   public void testSearchhasSubordinatesAttrInNonMatchingFilter(DN entryDN, boolean hasSubs)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(hasSubordinates=wrong)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("hasSubordinates");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request =
+        newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(hasSubordinates=wrong)").addAttribute("hasSubordinates");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 0);
   }
 
@@ -412,23 +397,10 @@
   public void testSearchhasSubordinatesAttrRealAttrsOnly(DN entryDN, boolean hasSubs)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(objectClass=*)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("hasSubordinates");
-
-    LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         new InternalSearchOperation(conn, InternalClientConnection.nextOperationID(),
-                                     InternalClientConnection.nextMessageID(), requestControls,
-                                     entryDN, SearchScope.BASE_OBJECT,
-                                     DereferenceAliasesPolicy.NEVER, 0,
-                                     0, false, filter, attrList, null);
-    searchOperation.run();
+    SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(objectClass=*)")
+        .addAttribute("hasSubordinates")
+        .addControl(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProviderTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProviderTestCase.java
index 720f805..d86ee28 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProviderTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProviderTestCase.java
@@ -26,24 +26,23 @@
  */
 package org.opends.server.extensions;
 
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
 import java.util.List;
 
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.DirectoryServerTestCase;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.types.*;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.testng.Assert.*;
 
@@ -351,18 +350,10 @@
   public void testSearchnumSubordinatesAttrInMatchingFilter(DN entryDN, int count)
          throws Exception
   {
-
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(numSubordinates=" + count + ")");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("numSubordinates");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request =
+        newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(numSubordinates=" + count + ")")
+            .addAttribute("numSubordinates");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -370,8 +361,6 @@
     assertTrue(e.hasAttribute(numSubordinatesType));
   }
 
-
-
   /**
    * Performs an internal search to retrieve the specified entry, ensuring that
    * no entries are returned when the numSubordinates attribute is used in the search
@@ -385,17 +374,9 @@
   public void testSearchnumSubordinatesAttrInNonMatchingFilter(DN entryDN, int count)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(numSubordinates=wrong)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("numSubordinates");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request =
+        newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(numSubordinates=wrong)").addAttribute("numSubordinates");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 0);
   }
 
@@ -414,23 +395,10 @@
   public void testSearchnumSubordinatesAttrRealAttrsOnly(DN entryDN, int count)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(objectClass=*)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("numSubordinates");
-
-    LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         new InternalSearchOperation(conn, InternalClientConnection.nextOperationID(),
-                                     InternalClientConnection.nextMessageID(), requestControls,
-                                     entryDN, SearchScope.BASE_OBJECT,
-                                     DereferenceAliasesPolicy.NEVER, 0,
-                                     0, false, filter, attrList, null);
-    searchOperation.run();
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(objectClass=*)")
+        .addAttribute("numSubordinates")
+        .addControl(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -454,23 +422,10 @@
   public void testSearchnumSubordinatesAttrVirtualAttrsOnly(DN entryDN, int count)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(objectClass=*)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("numSubordinates");
-
-    LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, true));
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         new InternalSearchOperation(conn, InternalClientConnection.nextOperationID(),
-                                     InternalClientConnection.nextMessageID(), requestControls,
-                                     entryDN, SearchScope.BASE_OBJECT,
-                                     DereferenceAliasesPolicy.NEVER, 0,
-                                     0, false, filter, attrList, null);
-    searchOperation.run();
+    final SearchRequest request =
+        newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(objectClass=*)").addAttribute("numSubordinates")
+            .addControl(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, true));
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -492,17 +447,10 @@
   public void testSearchnumSubordinatesAttrInGTEFilter(DN entryDN, int count)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(numSubordinates>=" + count + ")");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("numSubordinates");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request =
+        newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(numSubordinates>=" + count + ")")
+            .addAttribute("numSubordinates");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -524,17 +472,10 @@
   public void testSearchnumSubordinatesAttrInLTEFilter(DN entryDN, int count)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(numSubordinates<=" + count + ")");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("numSubordinates");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request =
+        newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(numSubordinates<=" + count + ")")
+            .addAttribute("numSubordinates");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -549,8 +490,6 @@
   @Test()
   public void testIsMultiValued()
   {
-    NumSubordinatesVirtualAttributeProvider provider =
-        new NumSubordinatesVirtualAttributeProvider();
-    assertFalse(provider.isMultiValued());
+    assertFalse(new NumSubordinatesVirtualAttributeProvider().isMultiValued());
   }
 }
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordExpirationTimeVirtualAttributeProviderTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordExpirationTimeVirtualAttributeProviderTestCase.java
index 31e0fcf..0c37c94 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordExpirationTimeVirtualAttributeProviderTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PasswordExpirationTimeVirtualAttributeProviderTestCase.java
@@ -27,25 +27,28 @@
 package org.opends.server.extensions;
 
 import java.util.Iterator;
-import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.TestCaseUtils;
-import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
 import org.opends.server.schema.GeneralizedTimeSyntax;
-import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.DisconnectReason;
+import org.opends.server.types.Entry;
+import org.opends.server.types.SearchResultEntry;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
+import static org.opends.server.protocols.internal.Requests.*;
 import static org.testng.Assert.*;
 
 @SuppressWarnings("javadoc")
@@ -198,30 +201,10 @@
   private long getTimeValueFromAttribute(String attributeName)
     throws Exception
   {
-    // Establish the internal connection as root
-
-    InternalClientConnection conn =
-      InternalClientConnection.getRootConnection();
-
-    assertNotNull(conn);
-
-    // Define the attribute to be returned
-
-    LinkedHashSet<String> retAttr = new  LinkedHashSet<String>();
-    retAttr.add(attributeName);
-    retAttr.add("pwdpolicysubentry");
-
     // Process the search request
-
-    InternalSearchOperation search =
-      conn.processSearch(notExpired.getName().toString(),
-                         SearchScope.BASE_OBJECT,
-                         DereferenceAliasesPolicy.ALWAYS,
-                         0,
-                         0,
-                         false,
-                         "(objectclass=*)",
-                         retAttr);
+    SearchRequest request = newSearchRequest(notExpired.getName(), SearchScope.BASE_OBJECT, "(objectclass=*)")
+        .addAttribute(attributeName, "pwdpolicysubentry");
+    InternalSearchOperation search = getRootConnection().processSearch(request);
     assertEquals(search.getResultCode(), ResultCode.SUCCESS);
 
     LinkedList<SearchResultEntry> entries = search.getSearchEntries();
@@ -243,7 +226,7 @@
 
     ByteString val = it.next();
 
-    conn.disconnect(DisconnectReason.UNBIND, true, LocalizableMessage.EMPTY);
+    getRootConnection().disconnect(DisconnectReason.UNBIND, true, LocalizableMessage.EMPTY);
 
     return GeneralizedTimeSyntax.decodeGeneralizedTimeValue(val);
   }
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java
index fe2c688..5fd15b7 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java
@@ -36,10 +36,12 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.protocols.ldap.LDAPFilter;
+import org.opends.server.protocols.internal.Requests;
+import org.opends.server.protocols.internal.SearchRequest;
 import org.opends.server.schema.SchemaConstants;
 import org.opends.server.tools.LDAPSearch;
 import org.opends.server.types.AuthenticationInfo;
+import org.opends.server.types.DN;
 import org.opends.server.types.Entry;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
@@ -92,10 +94,9 @@
   @Test()
   public void testSASLPlainAdvertised() throws Exception
   {
-    InternalClientConnection conn = getRootConnection();
-    InternalSearchOperation op =
-         conn.processSearch(ByteString.empty(), SearchScope.BASE_OBJECT,
-              LDAPFilter.decode("(supportedSASLMechanisms=PLAIN)"));
+    SearchRequest request =
+        Requests.newSearchRequest(DN.rootDN(), SearchScope.BASE_OBJECT, "(supportedSASLMechanisms=PLAIN)");
+    InternalSearchOperation op = getRootConnection().processSearch(request);
     assertFalse(op.getSearchEntries().isEmpty());
   }
 
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/StructuralObjectClassVirtualAttributeProviderTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/StructuralObjectClassVirtualAttributeProviderTestCase.java
index c79abd0..e55924d 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/StructuralObjectClassVirtualAttributeProviderTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/StructuralObjectClassVirtualAttributeProviderTestCase.java
@@ -26,34 +26,37 @@
  */
 package org.opends.server.extensions;
 
-import static org.opends.server.util.ServerConstants.*;
-import static org.testng.Assert.*;
-
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 
+import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
+import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.admin.std.meta.VirtualAttributeCfgDefn;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeType;
-import org.forgerock.opendj.ldap.ByteString;
 import org.opends.server.types.Control;
 import org.opends.server.types.DN;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.opends.server.types.Entry;
 import org.opends.server.types.SearchFilter;
-import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.types.VirtualAttributeRule;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.testng.Assert.*;
+
 /**
  * A set of test cases for the structural object class virtual attribute
  * provider.
@@ -287,17 +290,9 @@
   public void testSearchStructuralOCAttrInMatchingFilter(DN entryDN,String oc)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString(oc);
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("structuralObjectClass");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, oc)
+        .addAttribute("structuralObjectClass");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -320,17 +315,9 @@
   public void testSearchStructuralOCAttrInNonMatchingFilter(DN entryDN)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(structuralObjectClass=abc)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("structuralObjectClass");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(structuralObjectClass=abc)")
+        .addAttribute("structuralObjectClass");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 0);
   }
 
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProviderTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProviderTestCase.java
index b109de0..b6ef65e 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProviderTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProviderTestCase.java
@@ -26,34 +26,32 @@
  */
 package org.opends.server.extensions;
 
-import static org.opends.server.util.ServerConstants.*;
-import static org.testng.Assert.*;
-
 import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
 import java.util.List;
 
+import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.admin.std.meta.VirtualAttributeCfgDefn;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.protocols.ldap.LDAPControl;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeType;
-import org.forgerock.opendj.ldap.ByteString;
-import org.opends.server.types.Control;
 import org.opends.server.types.DN;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.opends.server.types.Entry;
 import org.opends.server.types.SearchFilter;
-import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.types.VirtualAttributeRule;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.testng.Assert.*;
+
 /**
  * A set of test cases for the subschemaSubentry virtual attribute provider.
  */
@@ -265,17 +263,9 @@
   public void testSearchSubschemaSubentryAttrInMatchingFilter(DN entryDN)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(subschemaSubentry=cn=schema)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("subschemaSubentry");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(subschemaSubentry=cn=schema)")
+        .addAttribute("subschemaSubentry");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -298,17 +288,9 @@
   public void testSearchSubschemaSubentryAttrInNonMatchingFilter(DN entryDN)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(subschemaSubentry=cn=foo)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("subschemaSubentry");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            filter, attrList);
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(subschemaSubentry=cn=foo)")
+        .addAttribute("subschemaSubentry");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 0);
   }
 
@@ -328,24 +310,10 @@
   public void testSearchSubschemaSubentryAttrRealAttrsOnly(DN entryDN)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(objectClass=*)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("subschemaSubentry");
-
-    LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-        new InternalSearchOperation(conn, InternalClientConnection
-            .nextOperationID(), InternalClientConnection
-            .nextMessageID(), requestControls, entryDN,
-            SearchScope.BASE_OBJECT,
-            DereferenceAliasesPolicy.NEVER, 0, 0, false, filter,
-            attrList, null);
-    searchOperation.run();
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(objectClass=*)")
+        .addAttribute("subschemaSubentry")
+        .addControl(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -369,24 +337,10 @@
   public void testSearchSubschemaSubentryAttrVirtualAttrsOnly(DN entryDN)
          throws Exception
   {
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(objectClass=*)");
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
-    attrList.add("subschemaSubentry");
-
-    LinkedList<Control> requestControls = new LinkedList<Control>();
-    requestControls.add(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, true));
-
-    InternalClientConnection conn =
-        InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-        new InternalSearchOperation(conn, InternalClientConnection
-            .nextOperationID(), InternalClientConnection
-            .nextMessageID(), requestControls, entryDN,
-            SearchScope.BASE_OBJECT,
-            DereferenceAliasesPolicy.NEVER, 0, 0, false, filter,
-            attrList, null);
-    searchOperation.run();
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(objectClass=*)")
+        .addAttribute("subschemaSubentry")
+        .addControl(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, true));
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getSearchEntries().size(), 1);
 
     Entry e = searchOperation.getSearchEntries().get(0);
@@ -402,9 +356,7 @@
   @Test()
   public void testIsMultiValued()
   {
-    SubschemaSubentryVirtualAttributeProvider provider =
-         new SubschemaSubentryVirtualAttributeProvider();
-    assertFalse(provider.isMultiValued());
+    assertFalse(new SubschemaSubentryVirtualAttributeProvider().isMultiValued());
   }
 
 
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProviderTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProviderTestCase.java
index 92da0de..72bdf88 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProviderTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProviderTestCase.java
@@ -26,7 +26,6 @@
  */
 package org.opends.server.extensions;
 
-import java.util.LinkedHashSet;
 import java.util.List;
 
 import org.forgerock.opendj.ldap.ByteString;
@@ -38,11 +37,14 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.tools.LDAPModify;
 import org.opends.server.types.*;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.testng.Assert.*;
 
 /**
@@ -110,9 +112,7 @@
       "ds-cfg-conflict-behavior: real-overrides-virtual",
       "ds-cfg-value: single value");
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-
+    InternalClientConnection conn = getRootConnection();
     try
     {
       InternalSearchOperation searchOperation =
@@ -178,9 +178,7 @@
       "ds-cfg-value: first value",
       "ds-cfg-value: second value");
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-
+    InternalClientConnection conn = getRootConnection();
     try
     {
       InternalSearchOperation searchOperation =
@@ -260,15 +258,11 @@
       "cn: Test User",
       "userPassword: test");
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-
+    InternalClientConnection conn = getRootConnection();
     try
     {
-      InternalSearchOperation searchOperation =
-          conn.processSearch(DN.valueOf(userDN),
-              SearchScope.BASE_OBJECT, SearchFilter
-                  .createFilterFromString("(objectClass=*)"));
+      final SearchRequest request = newSearchRequest(userDN, SearchScope.BASE_OBJECT, "(objectClass=*)");
+      InternalSearchOperation searchOperation = conn.processSearch(request);
 
       List<Attribute> attrList =
           searchOperation.getSearchEntries().get(0).getAttribute(
@@ -332,15 +326,11 @@
       "cn: Test User",
       "userPassword: test");
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-
+    InternalClientConnection conn = getRootConnection();
     try
     {
-      InternalSearchOperation searchOperation =
-          conn.processSearch(DN.valueOf(userDN),
-              SearchScope.BASE_OBJECT, SearchFilter
-                  .createFilterFromString("(objectClass=*)"));
+      final SearchRequest request = newSearchRequest(userDN, SearchScope.BASE_OBJECT, "(objectClass=*)");
+      InternalSearchOperation searchOperation = conn.processSearch(request);
 
       List<Attribute> attrList =
           searchOperation.getSearchEntries().get(0).getAttribute(
@@ -405,15 +395,11 @@
       "userPassword: test",
       "description: " + realValue);
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-
+    InternalClientConnection conn = getRootConnection();
     try
     {
-      InternalSearchOperation searchOperation =
-          conn.processSearch(DN.valueOf(userDN),
-              SearchScope.BASE_OBJECT, SearchFilter
-                  .createFilterFromString("(objectClass=*)"));
+      final SearchRequest request = newSearchRequest(userDN, SearchScope.BASE_OBJECT, "(objectClass=*)");
+      InternalSearchOperation searchOperation = conn.processSearch(request);
 
       List<Attribute> attrList =
           searchOperation.getSearchEntries().get(0).getAttribute(
@@ -477,15 +463,11 @@
       "userPassword: test",
       "description: " + realValue);
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-
+    InternalClientConnection conn = getRootConnection();
     try
     {
-      InternalSearchOperation searchOperation =
-          conn.processSearch(DN.valueOf(userDN),
-              SearchScope.BASE_OBJECT, SearchFilter
-                  .createFilterFromString("(objectClass=*)"));
+      final SearchRequest request = newSearchRequest(userDN, SearchScope.BASE_OBJECT, "(objectClass=*)");
+      InternalSearchOperation searchOperation = conn.processSearch(request);
 
       List<Attribute> attrList =
           searchOperation.getSearchEntries().get(0).getAttribute(
@@ -506,7 +488,6 @@
   }
 
 
-
   /**
    * Tests the creation of a description virtual attribute when real and virtual
    * values should be merged and the entry has a real value.
@@ -549,15 +530,11 @@
       "userPassword: test",
       "description: " + realValue);
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-
+    InternalClientConnection conn = getRootConnection();
     try
     {
-      InternalSearchOperation searchOperation =
-          conn.processSearch(DN.valueOf(userDN),
-              SearchScope.BASE_OBJECT, SearchFilter
-                  .createFilterFromString("(objectClass=*)"));
+      final SearchRequest request = newSearchRequest(userDN, SearchScope.BASE_OBJECT, "(objectClass=*)");
+      InternalSearchOperation searchOperation = conn.processSearch(request);
 
       List<Attribute> attrList =
           searchOperation.getSearchEntries().get(0).getAttribute(
@@ -633,19 +610,11 @@
 
     try
     {
-      LinkedHashSet<String> attributes = new LinkedHashSet<String>(1);
-      attributes.add("description");
+      final SearchRequest request =
+          newSearchRequest(userDN, SearchScope.BASE_OBJECT, "(objectClass=*)").addAttribute("description");
+      InternalSearchOperation searchOperation = conn.processSearch(request);
 
-      InternalSearchOperation searchOperation =
-          conn.processSearch(DN.valueOf(userDN),
-              SearchScope.BASE_OBJECT,
-              DereferenceAliasesPolicy.NEVER, 0, 0, false,
-              SearchFilter.createFilterFromString("(objectClass=*)"),
-              attributes);
-
-      List<Attribute> attrList =
-          searchOperation.getSearchEntries().get(0).getAttribute(
-              descriptionType);
+      List<Attribute> attrList = searchOperation.getSearchEntries().get(0).getAttribute(descriptionType);
       assertNotNull(attrList);
       assertEquals(attrList.size(), 1);
 
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java
index 3131531..bb63422 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java
@@ -41,11 +41,14 @@
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.*;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.testng.Assert.*;
 
 /**
@@ -874,18 +877,14 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  private void cleanUp()
-          throws Exception
+  private void cleanUp() throws Exception
   {
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(DN.valueOf("ou=Groups,dc=example,dc=com"),
-              SearchScope.SINGLE_LEVEL,
-              SearchFilter.createFilterFromString("(objectClass=*)"));
+    final SearchRequest request =
+        newSearchRequest("ou=Groups,dc=example,dc=com", SearchScope.SINGLE_LEVEL, "(objectClass=*)");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     for (Entry e : searchOperation.getSearchEntries())
     {
-      conn.processDelete(e.getName());
+      getRootConnection().processDelete(e.getName());
     }
   }
 }
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java
index 8b2b11b..6957f18 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/monitors/InternalSearchMonitorTestCase.java
@@ -34,6 +34,8 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.SearchResultEntry;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -42,7 +44,6 @@
 
 import static org.forgerock.opendj.ldap.SearchScope.*;
 import static org.opends.server.protocols.internal.InternalClientConnection.*;
-import static org.opends.server.types.SearchFilter.*;
 import static org.testng.Assert.*;
 
 /**
@@ -138,8 +139,8 @@
 
     for (SearchResultEntry sre : op.getSearchEntries())
     {
-      final InternalSearchOperation readOp = conn.processSearch(
-          sre.getName(), BASE_OBJECT, createFilterFromString("(objectClass=*)"));
+      final SearchRequest request = newSearchRequest(sre.getName(), BASE_OBJECT, "(objectClass=*)");
+      final InternalSearchOperation readOp = conn.processSearch(request);
       assertEquals(readOp.getResultCode(), ResultCode.SUCCESS,
           "Failed to read " + sre.getName() + " entry. Got error message: " + readOp.getErrorMessage());
     }
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java
index 56af977..e839c0d 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java
@@ -28,29 +28,25 @@
 
 import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.LinkedHashSet;
 import java.util.List;
 
+import org.forgerock.opendj.config.server.ConfigException;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.SearchScope;
+import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.LDAPAttributeDescriptionListPluginCfgDefn;
+import org.opends.server.admin.std.server.LDAPAttributeDescriptionListPluginCfg;
+import org.opends.server.api.plugin.PluginType;
+import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import org.opends.server.types.Entry;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
-import org.opends.server.TestCaseUtils;
-import org.opends.server.admin.server.AdminTestCaseUtils;
-import org.opends.server.admin.std.meta.
-            LDAPAttributeDescriptionListPluginCfgDefn;
-import org.opends.server.admin.std.server.LDAPAttributeDescriptionListPluginCfg;
-import org.opends.server.api.plugin.PluginType;
-import org.forgerock.opendj.config.server.ConfigException;
-import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.forgerock.opendj.ldap.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.forgerock.opendj.ldap.SearchScope;
-
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
+import static org.opends.server.protocols.internal.Requests.*;
 import static org.testng.Assert.*;
 
 /**
@@ -210,20 +206,14 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
+  @Test
   public void testDoPreParseSearchWithEmptyAttrList()
          throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>();
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(DN.valueOf("o=test"), SearchScope.BASE_OBJECT,
-              DereferenceAliasesPolicy.NEVER, 0, 0, false,
-              SearchFilter.createFilterFromString("(objectClass=*)"), attrList);
+    final SearchRequest request = newSearchRequest("o=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
 
@@ -239,21 +229,15 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
+  @Test
   public void testDoPreParseSearchWithRequestedAttribute()
          throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>();
-    attrList.add("o");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(DN.valueOf("o=test"), SearchScope.BASE_OBJECT,
-              DereferenceAliasesPolicy.NEVER, 0, 0, false,
-              SearchFilter.createFilterFromString("(objectClass=*)"), attrList);
+    SearchRequest request = newSearchRequest("o=test", SearchScope.BASE_OBJECT, "(objectClass=*)")
+        .addAttribute("o");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
 
@@ -269,21 +253,15 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
+  @Test
   public void testDoPreParseSearchWithRequestedObjectClass()
          throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>();
-    attrList.add("@organization");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(DN.valueOf("o=test"), SearchScope.BASE_OBJECT,
-              DereferenceAliasesPolicy.NEVER, 0, 0, false,
-              SearchFilter.createFilterFromString("(objectClass=*)"), attrList);
+    final SearchRequest request = newSearchRequest("o=test", SearchScope.BASE_OBJECT, "(objectClass=*)")
+        .addAttribute("@organization");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
 
@@ -299,21 +277,15 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
+  @Test
   public void testDoPreParseSearchWithRequestedUndefinedObjectClass()
          throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    LinkedHashSet<String> attrList = new LinkedHashSet<String>();
-    attrList.add("@undefined");
-
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(DN.valueOf("o=test"), SearchScope.BASE_OBJECT,
-              DereferenceAliasesPolicy.NEVER, 0, 0, false,
-              SearchFilter.createFilterFromString("(objectClass=*)"), attrList);
+    final SearchRequest request =
+        newSearchRequest("o=test", SearchScope.BASE_OBJECT, "(objectClass=*)").addAttribute("@undefined");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
 
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java
index 2fca41e..148dca6 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java
@@ -34,7 +34,6 @@
 
 import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.ModificationType;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
@@ -48,6 +47,8 @@
 import org.opends.server.core.*;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.*;
 import org.opends.server.types.Attributes;
 import org.opends.server.types.DN;
@@ -1165,13 +1166,8 @@
                                      String... dns)
           throws Exception {
     AttributeType type= getAttrType(attr);
-    String filterStr="(" + attr + "=*)";
-    InternalClientConnection conn = getRootConnection();
-    InternalSearchOperation operation = conn.processSearch(DN.valueOf(entryDN),
-            SearchScope.BASE_OBJECT,
-            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-            SearchFilter.createFilterFromString(filterStr),
-            null);
+    final SearchRequest request = newSearchRequest(entryDN, SearchScope.BASE_OBJECT, "(" + attr + "=*)");
+    InternalSearchOperation operation = getRootConnection().processSearch(request);
     for (SearchResultEntry entry : operation.getSearchEntries()) {
       for(String dn : dns) {
         ByteString value = ByteString.valueOf(dn);
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java
index 04a7578..bcd9fc8 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java
@@ -27,11 +27,9 @@
 package org.opends.server.protocols.internal;
 
 import java.util.ArrayList;
-import java.util.LinkedHashSet;
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.ModificationType;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
@@ -45,14 +43,25 @@
 import org.opends.server.core.ModifyDNOperation;
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.protocols.ldap.LDAPAttribute;
-import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.protocols.ldap.LDAPModification;
-import org.opends.server.types.*;
+import org.opends.server.types.Attributes;
+import org.opends.server.types.AuthenticationInfo;
+import org.opends.server.types.CancelRequest;
+import org.opends.server.types.CancelResult;
+import org.opends.server.types.DN;
+import org.opends.server.types.DisconnectReason;
+import org.opends.server.types.Entry;
+import org.opends.server.types.Modification;
+import org.opends.server.types.RDN;
+import org.opends.server.types.RawAttribute;
+import org.opends.server.types.RawModification;
+import org.opends.server.types.SearchResultReference;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import static org.opends.server.protocols.internal.InternalClientConnection.*;
+import static org.opends.server.protocols.internal.Requests.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.testng.Assert.*;
 
@@ -704,13 +713,10 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test
-  public void testProcessSearch1()
-         throws Exception
+  public void testProcessSearch1() throws Exception
   {
-    InternalClientConnection conn = getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(ByteString.valueOf(""), SearchScope.BASE_OBJECT,
-                            LDAPFilter.decode("(objectClass=*)"));
+    SearchRequest request = newSearchRequest(DN.rootDN(), SearchScope.BASE_OBJECT, "(objectClass=*)");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
     assertTrue(searchOperation.getSearchReferences().isEmpty());
@@ -725,15 +731,10 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test
-  public void testProcessSearch2()
-         throws Exception
+  public void testProcessSearch2() throws Exception
   {
-    InternalClientConnection conn = getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(ByteString.valueOf(""), SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            LDAPFilter.decode("(objectClass=*)"),
-                            new LinkedHashSet<String>());
+    SearchRequest request = newSearchRequest(DN.rootDN(), SearchScope.BASE_OBJECT, "(objectClass=*)");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
     assertTrue(searchOperation.getSearchReferences().isEmpty());
@@ -749,18 +750,12 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test
-  public void testProcessSearch3()
-         throws Exception
+  public void testProcessSearch3() throws Exception
   {
-    TestInternalSearchListener searchListener =
-         new TestInternalSearchListener();
+    TestInternalSearchListener searchListener = new TestInternalSearchListener();
 
-    InternalClientConnection conn = getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(ByteString.valueOf(""), SearchScope.BASE_OBJECT,
-                            DereferenceAliasesPolicy.NEVER, 0, 0, false,
-                            LDAPFilter.decode("(objectClass=*)"),
-                            new LinkedHashSet<String>(), searchListener);
+    SearchRequest request = newSearchRequest(DN.rootDN(), SearchScope.BASE_OBJECT, "(objectClass=*)");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request, searchListener);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchListener.getSearchEntries().isEmpty());
     assertTrue(searchListener.getSearchReferences().isEmpty());
@@ -775,13 +770,10 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test
-  public void testProcessSearch4()
-         throws Exception
+  public void testProcessSearch4() throws Exception
   {
-    InternalClientConnection conn = getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(DN.rootDN(), SearchScope.BASE_OBJECT,
-              SearchFilter.createFilterFromString("(objectClass=*)"));
+    final SearchRequest request = newSearchRequest(DN.rootDN(), SearchScope.BASE_OBJECT, "(objectClass=*)");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
     assertTrue(searchOperation.getSearchReferences().isEmpty());
@@ -796,15 +788,10 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test
-  public void testProcessSearch5()
-         throws Exception
+  public void testProcessSearch5() throws Exception
   {
-    InternalClientConnection conn = getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(DN.rootDN(), SearchScope.BASE_OBJECT,
-              DereferenceAliasesPolicy.NEVER, 0, 0, false,
-              SearchFilter.createFilterFromString("(objectClass=*)"),
-              new LinkedHashSet<String>());
+    final SearchRequest request = newSearchRequest(DN.rootDN(), SearchScope.BASE_OBJECT, "(objectClass=*)");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
     assertTrue(searchOperation.getSearchReferences().isEmpty());
@@ -820,18 +807,13 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test
-  public void testProcessSearch6()
-         throws Exception
+  public void testProcessSearch6() throws Exception
   {
     TestInternalSearchListener searchListener =
          new TestInternalSearchListener();
 
-    InternalClientConnection conn = getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(DN.rootDN(), SearchScope.BASE_OBJECT,
-              DereferenceAliasesPolicy.NEVER, 0, 0, false,
-              SearchFilter.createFilterFromString("(objectClass=*)"),
-              new LinkedHashSet<String>(), searchListener);
+    final SearchRequest request = newSearchRequest(DN.rootDN(), SearchScope.BASE_OBJECT, "(objectClass=*)");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request, searchListener);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchListener.getSearchEntries().isEmpty());
     assertTrue(searchListener.getSearchReferences().isEmpty());
@@ -849,9 +831,7 @@
          throws Exception
   {
     InternalClientConnection conn = getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(ByteString.valueOf(""), SearchScope.BASE_OBJECT,
-                            LDAPFilter.decode("(objectClass=*)"));
+    InternalSearchOperation searchOperation = conn.processSearch("", SearchScope.BASE_OBJECT, "(objectClass=*)");
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
     assertTrue(searchOperation.getSearchReferences().isEmpty());
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalSearchOperationTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalSearchOperationTestCase.java
index 9be5674..cd0378a 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalSearchOperationTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalSearchOperationTestCase.java
@@ -31,14 +31,15 @@
 
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.protocols.ldap.LDAPFilter;
 import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.testng.Assert.*;
 
 /**
@@ -72,10 +73,9 @@
   public void testConstructor1WithoutListener()
          throws Exception
   {
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    new InternalSearchOperation(conn, InternalClientConnection.nextOperationID(),
-                                InternalClientConnection.nextMessageID(), new ArrayList<Control>(),
+    InternalClientConnection conn = getRootConnection();
+    new InternalSearchOperation(conn, nextOperationID(),
+                                nextMessageID(), new ArrayList<Control>(),
                                 ByteString.empty(), SearchScope.BASE_OBJECT,
                                 DereferenceAliasesPolicy.NEVER, 0, 0,
                                 false, LDAPFilter.decode("(objectClass=*)"),
@@ -94,10 +94,9 @@
   public void testConstructor1WithListener()
          throws Exception
   {
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    new InternalSearchOperation(conn, InternalClientConnection.nextOperationID(),
-                                InternalClientConnection.nextMessageID(), new ArrayList<Control>(),
+    InternalClientConnection conn = getRootConnection();
+    new InternalSearchOperation(conn, nextOperationID(),
+                                nextMessageID(), new ArrayList<Control>(),
                                 ByteString.empty(), SearchScope.BASE_OBJECT,
                                 DereferenceAliasesPolicy.NEVER, 0, 0,
                                 false, LDAPFilter.decode("(objectClass=*)"),
@@ -120,10 +119,9 @@
     SearchFilter searchFilter =
          SearchFilter.createFilterFromString("(objectClass=*)");
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    new InternalSearchOperation(conn, InternalClientConnection.nextOperationID(),
-                                InternalClientConnection.nextMessageID(), new ArrayList<Control>(),
+    InternalClientConnection conn = getRootConnection();
+    new InternalSearchOperation(conn, nextOperationID(),
+                                nextMessageID(), new ArrayList<Control>(),
                                 DN.rootDN(), SearchScope.BASE_OBJECT,
                                 DereferenceAliasesPolicy.NEVER, 0, 0,
                                 false, searchFilter,
@@ -145,10 +143,9 @@
     SearchFilter searchFilter =
          SearchFilter.createFilterFromString("(objectClass=*)");
 
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    new InternalSearchOperation(conn, InternalClientConnection.nextOperationID(),
-                                InternalClientConnection.nextMessageID(), new ArrayList<Control>(),
+    InternalClientConnection conn = getRootConnection();
+    new InternalSearchOperation(conn, nextOperationID(),
+                                nextMessageID(), new ArrayList<Control>(),
                                 DN.rootDN(), SearchScope.BASE_OBJECT,
                                 DereferenceAliasesPolicy.NEVER, 0, 0,
                                 false, searchFilter,
@@ -165,14 +162,10 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test()
-  public void testGetSearchEntriesAndReferences()
-         throws Exception
+  public void testGetSearchEntriesAndReferences() throws Exception
   {
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
-    InternalSearchOperation searchOperation =
-         conn.processSearch(ByteString.valueOf(""), SearchScope.BASE_OBJECT,
-                            LDAPFilter.decode("(objectClass=*)"));
+    SearchRequest request = Requests.newSearchRequest(DN.rootDN(), SearchScope.BASE_OBJECT, "(objectClass=*)");
+    InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
     assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
     assertFalse(searchOperation.getSearchEntries().isEmpty());
     assertTrue(searchOperation.getSearchReferences().isEmpty());
@@ -186,14 +179,12 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test()
-  public void testAddSearchEntryWithoutListener()
-         throws Exception
+  public void testAddSearchEntryWithoutListener() throws Exception
   {
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     InternalSearchOperation searchOperation =
-         new InternalSearchOperation(conn, InternalClientConnection.nextOperationID(),
-                                     InternalClientConnection.nextMessageID(),
+         new InternalSearchOperation(conn, nextOperationID(),
+                                     nextMessageID(),
                                      new ArrayList<Control>(),
                                      ByteString.empty(),
                                      SearchScope.BASE_OBJECT,
@@ -219,11 +210,10 @@
   public void testAddSearchEntryWithListener()
          throws Exception
   {
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     InternalSearchOperation searchOperation =
-         new InternalSearchOperation(conn, InternalClientConnection.nextOperationID(),
-                                     InternalClientConnection.nextMessageID(),
+         new InternalSearchOperation(conn, nextOperationID(),
+                                     nextMessageID(),
                                      new ArrayList<Control>(),
                                      ByteString.empty(),
                                      SearchScope.BASE_OBJECT,
@@ -250,11 +240,10 @@
   public void testAddSearchReferenceWithoutListener()
          throws Exception
   {
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     InternalSearchOperation searchOperation =
-         new InternalSearchOperation(conn, InternalClientConnection.nextOperationID(),
-                                     InternalClientConnection.nextMessageID(),
+         new InternalSearchOperation(conn, nextOperationID(),
+                                     nextMessageID(),
                                      new ArrayList<Control>(),
                                      ByteString.empty(),
                                      SearchScope.BASE_OBJECT,
@@ -279,11 +268,10 @@
   public void testAddSearchReferenceWithListener()
          throws Exception
   {
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     InternalSearchOperation searchOperation =
-         new InternalSearchOperation(conn, InternalClientConnection.nextOperationID(),
-                                     InternalClientConnection.nextMessageID(),
+         new InternalSearchOperation(conn, nextOperationID(),
+                                     nextMessageID(),
                                      new ArrayList<Control>(),
                                      ByteString.empty(),
                                      SearchScope.BASE_OBJECT,
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/InitOnLineTest.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/InitOnLineTest.java
index 9250149..fc36654 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/InitOnLineTest.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/InitOnLineTest.java
@@ -38,6 +38,7 @@
 import org.opends.server.core.AddOperation;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
 import org.opends.server.replication.common.ServerStatus;
 import org.opends.server.replication.plugin.LDAPReplicationDomain;
 import org.opends.server.replication.protocol.*;
@@ -48,7 +49,6 @@
 import org.opends.server.types.DN;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.Entry;
-import org.opends.server.types.SearchFilter;
 import org.opends.server.util.Base64;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -58,6 +58,7 @@
 import static org.opends.messages.TaskMessages.*;
 import static org.opends.server.backends.task.TaskState.*;
 import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.protocols.internal.Requests.*;
 import static org.opends.server.util.StaticUtils.*;
 import static org.testng.Assert.*;
 
@@ -262,14 +263,11 @@
     // Wait until the task completes.
     int timeout = 2000;
 
-    SearchFilter filter =
-        SearchFilter.createFilterFromString("(objectclass=*)");
-
     long startMillisecs = System.currentTimeMillis();
     do
     {
-      InternalSearchOperation searchOperation = connection.processSearch(
-          taskEntry.getName(), SearchScope.BASE_OBJECT, filter);
+      final SearchRequest request = newSearchRequest(taskEntry.getName(), SearchScope.BASE_OBJECT, "(objectclass=*)");
+      InternalSearchOperation searchOperation = connection.processSearch(request);
       Entry resultEntry = searchOperation.getSearchEntries().getFirst();
 
       String completionTime = resultEntry.parseAttribute(
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
index d4148c0..89dc52a 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
@@ -26,7 +26,12 @@
  */
 package org.opends.server.replication;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 import java.util.concurrent.locks.Lock;
 
 import org.assertj.core.api.Assertions;
@@ -34,7 +39,6 @@
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.ModificationType;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
@@ -47,10 +51,14 @@
 import org.opends.server.core.DeleteOperation;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.protocols.internal.InternalSearchListener;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
 import org.opends.server.replication.common.ServerState;
-import org.opends.server.replication.plugin.*;
+import org.opends.server.replication.plugin.DomainFakeCfg;
+import org.opends.server.replication.plugin.DummyReplicationDomain;
+import org.opends.server.replication.plugin.GenerationIdChecksum;
+import org.opends.server.replication.plugin.LDAPReplicationDomain;
+import org.opends.server.replication.plugin.MultimasterReplication;
 import org.opends.server.replication.protocol.ReplSessionSecurity;
 import org.opends.server.replication.protocol.ReplicationMsg;
 import org.opends.server.replication.protocol.Session;
@@ -58,7 +66,13 @@
 import org.opends.server.replication.server.changelog.file.FileChangelogDB;
 import org.opends.server.replication.server.changelog.je.JEChangelogDB;
 import org.opends.server.replication.service.ReplicationBroker;
-import org.opends.server.types.*;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.Attributes;
+import org.opends.server.types.DN;
+import org.opends.server.types.Entry;
+import org.opends.server.types.LockManager;
+import org.opends.server.types.Modification;
+import org.opends.server.types.SearchResultEntry;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -67,6 +81,7 @@
 import static org.forgerock.opendj.ldap.SearchScope.*;
 import static org.opends.server.TestCaseUtils.*;
 import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.protocols.internal.Requests.*;
 import static org.testng.Assert.*;
 
 /**
@@ -80,9 +95,6 @@
   /** The tracer object for the debug logger */
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
-  private static final Set<String> ALL_ATTRIBUTES = newSet("*", "+");
-  private static final List<Control> NO_CONTROL = null;
-
   /**
    * This is the generation id matching the memory test backend with its initial
    * root entry o=test created. This matches the backend obtained calling:
@@ -635,16 +647,13 @@
     Entry taskEntry = TestCaseUtils.addEntry(task);
 
     // Wait until the task completes.
-    SearchFilter filter = SearchFilter.createFilterFromString("(objectclass=*)");
     Entry resultEntry = null;
     String completionTime = null;
     long startMillisecs = System.currentTimeMillis();
     do
     {
-      InternalSearchOperation searchOperation =
-           connection.processSearch(taskEntry.getName(),
-                                    SearchScope.BASE_OBJECT,
-                                    filter);
+      final SearchRequest request = newSearchRequest(taskEntry.getName(), SearchScope.BASE_OBJECT, "(objectclass=*)");
+      InternalSearchOperation searchOperation = connection.processSearch(request);
       if (searchOperation.getSearchEntries().isEmpty())
       {
         continue;
@@ -735,13 +744,12 @@
   {
     long startTime = System.currentTimeMillis();
 
-    SearchFilter filter = SearchFilter.createFilterFromString("(objectclass=*)");
     Entry resultEntry = null;
     TaskState taskState = null;
     do
     {
-      InternalSearchOperation searchOperation =
-          connection.processSearch(taskEntry.getName(), SearchScope.BASE_OBJECT, filter);
+      final SearchRequest request = newSearchRequest(taskEntry.getName(), SearchScope.BASE_OBJECT, "(objectclass=*)");
+      InternalSearchOperation searchOperation = connection.processSearch(request);
       resultEntry = searchOperation.getSearchEntries().getFirst();
 
       // Check that the task state is as expected.
@@ -939,21 +947,17 @@
       ResultCode expectedResultCode, int expectedNbEntries) throws Exception
   {
     InternalSearchOperation searchOp = null;
-    int sizeLimitZero = 0;
-    int timeLimitZero = 0;
-    boolean typesOnlyFalse = false;
-    InternalSearchListener noSearchListener = null;
     int count = 0;
     do
     {
       Thread.sleep(10);
-      searchOp = connection.processSearch(dn, scope, DereferenceAliasesPolicy.NEVER, sizeLimitZero,
-          timeLimitZero, typesOnlyFalse, filter, ALL_ATTRIBUTES, NO_CONTROL, noSearchListener);
+      final SearchRequest request = newSearchRequest(dn, scope, filter).addAttribute("*", "+");
+      searchOp = connection.processSearch(request);
       count++;
-      System.out.println(searchOp.getResultCode() + " " + searchOp.getSearchEntries().size());
     }
-    while (count < 300 && searchOp.getResultCode() != expectedResultCode &&
-        searchOp.getSearchEntries().size() != expectedNbEntries);
+    while (count < 300
+        && searchOp.getResultCode() != expectedResultCode
+        && searchOp.getSearchEntries().size() != expectedNbEntries);
 
     final List<SearchResultEntry> entries = searchOp.getSearchEntries();
     Assertions.assertThat(entries).hasSize(expectedNbEntries);
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java
index 58d9e67..1aa7fa5 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java
@@ -44,6 +44,8 @@
 import org.opends.server.core.DeleteOperation;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.replication.ReplicationTestCase;
 import org.opends.server.replication.common.*;
 import org.opends.server.replication.protocol.*;
@@ -1467,7 +1469,8 @@
     {
       if (count++>0)
         Thread.sleep(100);
-      op = connection.processSearch(dn, SearchScope.WHOLE_SUBTREE, monitorFilter);
+      final SearchRequest request = newSearchRequest(dn, SearchScope.WHOLE_SUBTREE, monitorFilter);
+      op = connection.processSearch(request);
     }
     while (op.getSearchEntries().isEmpty() && count < 100);
 
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/tasks/TasksTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/tasks/TasksTestCase.java
index 3860811..bfad9b2 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/tasks/TasksTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/tasks/TasksTestCase.java
@@ -38,10 +38,11 @@
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.SearchRequest;
+import static org.opends.server.protocols.internal.Requests.*;
 import org.opends.server.types.AttributeParser;
 import org.opends.server.types.DN;
 import org.opends.server.types.Entry;
-import org.opends.server.types.SearchFilter;
 import org.testng.annotations.Test;
 
 import static org.opends.server.config.ConfigConstants.*;
@@ -72,8 +73,7 @@
                  "Add of the task definition was not successful");
 
     // Wait until the task completes.
-    SearchFilter filter =
-         SearchFilter.createFilterFromString("(objectclass=*)");
+    final SearchRequest request = newSearchRequest(taskEntry.getName(), SearchScope.BASE_OBJECT, "(objectclass=*)");
     Entry resultEntry = null;
     String completionTime = null;
     long startMillisecs = System.currentTimeMillis();
@@ -81,10 +81,7 @@
     do
     {
       Thread.sleep(100);
-      InternalSearchOperation searchOperation =
-           connection.processSearch(taskEntry.getName(),
-                                    SearchScope.BASE_OBJECT,
-                                    filter);
+      InternalSearchOperation searchOperation = connection.processSearch(request);
       resultEntry = searchOperation.getSearchEntries().getFirst();
       completionTime = parseAttribute(resultEntry, ATTR_TASK_COMPLETION_TIME).asString();
       timedOut = System.currentTimeMillis() - startMillisecs > 1000 * timeout;

--
Gitblit v1.10.0