From f2090c0d863b07e3bad8d16a3efddfad6ff77960 Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Tue, 08 Oct 2013 14:16:54 +0000
Subject: [PATCH] Fix OPENDJ-346 Consider using java.util.ServiceLoader for loading extensions and requesting transport implementations This a a part of OPENDJ-175 - Decouple OpenDJ LDAP SDK from Grizzly  CR-2440

---
 opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/TimeoutChecker.java                          |   10 
 opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPServerFilter.java                        |    4 
 opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnectionTestCase.java           |   13 
 opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConnectionFactoryProvider.java     |   20 
 opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/TestCaseUtils.java                 |   47 ++
 opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/TestCaseUtils.java                           |   22 +
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java                   |   41 +
 opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnection.java                   |    8 
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/LDAPConnectionFactoryImpl.java           |   52 ++
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/TransportProvider.java                   |   79 +++
 opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/ConnectionFactoryProviderTest.java |    4 
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListener.java                            |   34 +
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/package-info.java                        |   31 +
 opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPListener.java                     |   45 +
 opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/StaticUtils.java                             |   46 ++
 opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java               |   41 +
 opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java                              |    6 
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/Provider.java                            |   45 ++
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListenerOptions.java                     |  114 +++-
 opendj3/opendj-server2x-adapter/src/test/java/org/forgerock/opendj/adapter/server2x/TestCaseUtils.java       |   47 ++
 opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyTransportProvider.java                |   81 +++
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/LDAPListenerImpl.java                    |   58 ++
 opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnectionFactory.java            |   50 +
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPOptions.java                             |  133 ++++--
 opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPConnectionFactoryTestCase.java           |   22 
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ProviderNotFoundException.java               |   76 +++
 opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPClientFilter.java                        |   36 
 opendj3/opendj-server2x-adapter/src/test/java/org/forgerock/opendj/adapter/server2x/AdaptersTestCase.java    |   21 
 opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPListenerTestCase.java                    |   94 +++-
 opendj3/opendj-ldap-sdk/src/main/resources/META-INF/services/org.forgerock.opendj.ldap.spi.TransportProvider |   26 +
 30 files changed, 1,092 insertions(+), 214 deletions(-)

diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnection.java b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnection.java
similarity index 99%
rename from opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnection.java
rename to opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnection.java
index 77dbd01..d9c7968 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnection.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnection.java
@@ -87,7 +87,7 @@
 /**
  * LDAP connection implementation.
  */
-final class LDAPConnection extends AbstractAsynchronousConnection implements Connection {
+final class GrizzlyLDAPConnection extends AbstractAsynchronousConnection implements Connection {
     /**
      * A dummy SSL client engine configurator as SSLFilter only needs client
      * config. This prevents Grizzly from needlessly using JVM defaults which
@@ -109,7 +109,7 @@
     private final org.glassfish.grizzly.Connection<?> connection;
     private final LDAPWriter ldapWriter = new LDAPWriter();
     private final AtomicInteger nextMsgID = new AtomicInteger(1);
-    private final LDAPConnectionFactoryImpl factory;
+    private final GrizzlyLDAPConnectionFactory factory;
     private final ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>> pendingRequests =
             new ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>>();
     private final Object stateLock = new Object();
@@ -120,8 +120,8 @@
     private boolean isFailed = false;
     private List<ConnectionEventListener> listeners = null;
 
-    LDAPConnection(final org.glassfish.grizzly.Connection<?> connection,
-            final LDAPConnectionFactoryImpl factory) {
+    GrizzlyLDAPConnection(final org.glassfish.grizzly.Connection<?> connection,
+            final GrizzlyLDAPConnectionFactory factory) {
         this.connection = connection;
         this.factory = factory;
     }
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnectionFactory.java
similarity index 84%
rename from opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java
rename to opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnectionFactory.java
index 91b4c93..00d09a7 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnectionFactory.java
@@ -29,6 +29,7 @@
 
 import static com.forgerock.opendj.ldap.DefaultTCPNIOTransport.DEFAULT_TRANSPORT;
 import static com.forgerock.opendj.ldap.TimeoutChecker.TIMEOUT_CHECKER;
+
 import static org.forgerock.opendj.ldap.ErrorResultException.*;
 
 import java.io.IOException;
@@ -40,7 +41,6 @@
 import javax.net.ssl.SSLEngine;
 
 import org.forgerock.opendj.ldap.Connection;
-import org.forgerock.opendj.ldap.ConnectionFactory;
 import org.forgerock.opendj.ldap.ErrorResultException;
 import org.forgerock.opendj.ldap.FutureResult;
 import org.forgerock.opendj.ldap.LDAPOptions;
@@ -49,6 +49,7 @@
 import org.forgerock.opendj.ldap.requests.Requests;
 import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest;
 import org.forgerock.opendj.ldap.responses.ExtendedResult;
+import org.forgerock.opendj.ldap.spi.LDAPConnectionFactoryImpl;
 import org.glassfish.grizzly.CompletionHandler;
 import org.glassfish.grizzly.EmptyCompletionHandler;
 import org.glassfish.grizzly.SocketConnectorHandler;
@@ -62,9 +63,9 @@
 import com.forgerock.opendj.util.ReferenceCountedObject;
 
 /**
- * LDAP connection factory implementation.
+ * LDAP connection factory implementation using Grizzly for transport.
  */
-public final class LDAPConnectionFactoryImpl implements ConnectionFactory {
+public final class GrizzlyLDAPConnectionFactory implements LDAPConnectionFactoryImpl {
     /**
      * Adapts a Grizzly connection completion handler to an LDAP connection
      * asynchronous future result.
@@ -88,7 +89,7 @@
         @Override
         public void completed(final org.glassfish.grizzly.Connection result) {
             // Adapt the connection.
-            final LDAPConnection connection = adaptConnection(result);
+            final GrizzlyLDAPConnection connection = adaptConnection(result);
 
             // Plain connection.
             if (options.getSSLContext() == null) {
@@ -159,14 +160,14 @@
             // Ignore this.
         }
 
-        private LDAPConnection adaptConnection(final org.glassfish.grizzly.Connection<?> connection) {
+        private GrizzlyLDAPConnection adaptConnection(final org.glassfish.grizzly.Connection<?> connection) {
             /*
              * Test shows that its much faster with non block writes but risk
              * running out of memory if the server is slow.
              */
             connection.configureBlocking(true);
-            final LDAPConnection ldapConnection =
-                    new LDAPConnection(connection, LDAPConnectionFactoryImpl.this);
+            final GrizzlyLDAPConnection ldapConnection =
+                    new GrizzlyLDAPConnection(connection, GrizzlyLDAPConnectionFactory.this);
             timeoutChecker.get().addConnection(ldapConnection);
             clientFilter.registerConnection(connection, ldapConnection);
             return ldapConnection;
@@ -184,14 +185,14 @@
             }
         }
 
-        private void onFailure(final LDAPConnection connection, final Throwable t) {
+        private void onFailure(final GrizzlyLDAPConnection connection, final Throwable t) {
             // Abort connection attempt due to error.
             connection.close();
             future.handleErrorResult(adaptConnectionException(t));
             releaseTransportAndTimeoutChecker();
         }
 
-        private void onSuccess(final LDAPConnection connection) {
+        private void onSuccess(final GrizzlyLDAPConnection connection) {
             future.handleResult(connection);
 
             // Close the connection if the future was cancelled.
@@ -224,7 +225,7 @@
             .acquire();
 
     /**
-     * Creates a new LDAP connection factory implementation which can be used to
+     * Creates a new LDAP connection factory based on Grizzly which can be used to
      * create connections to the Directory Server at the provided host and port
      * address using provided connection options.
      *
@@ -233,14 +234,31 @@
      * @param options
      *            The LDAP connection options to use when creating connections.
      */
-    public LDAPConnectionFactoryImpl(final SocketAddress address, final LDAPOptions options) {
-        this.transport = DEFAULT_TRANSPORT.acquireIfNull(options.getTCPNIOTransport());
+    public GrizzlyLDAPConnectionFactory(final SocketAddress address, final LDAPOptions options) {
+        this(address, options, null);
+    }
+
+    /**
+     * Creates a new LDAP connection factory based on Grizzly which can be used
+     * to create connections to the Directory Server at the provided host and
+     * port address using provided connection options and provided TCP
+     * transport.
+     *
+     * @param address
+     *            The address of the Directory Server to connect to.
+     * @param options
+     *            The LDAP connection options to use when creating connections.
+     * @param transport
+     *            Grizzly TCP Transport NIO implementation to use for
+     *            connections. If {@code null}, default transport will be used.
+     */
+    public GrizzlyLDAPConnectionFactory(final SocketAddress address, final LDAPOptions options,
+            TCPNIOTransport transport) {
+        this.transport = DEFAULT_TRANSPORT.acquireIfNull(transport);
         this.socketAddress = address;
         this.options = new LDAPOptions(options);
-        this.clientFilter =
-                new LDAPClientFilter(new LDAPReader(this.options.getDecodeOptions()), 0);
-        this.defaultFilterChain =
-                FilterChainBuilder.stateless().add(new TransportFilter()).add(clientFilter).build();
+        this.clientFilter = new LDAPClientFilter(new LDAPReader(this.options.getDecodeOptions()), 0);
+        this.defaultFilterChain = FilterChainBuilder.stateless().add(new TransportFilter()).add(clientFilter).build();
     }
 
     @Override
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPListenerImpl.java b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPListener.java
similarity index 75%
rename from opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPListenerImpl.java
rename to opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPListener.java
index cf540ec..d60d583 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPListenerImpl.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPListener.java
@@ -30,14 +30,15 @@
 import static com.forgerock.opendj.ldap.DefaultTCPNIOTransport.DEFAULT_TRANSPORT;
 import static com.forgerock.opendj.util.StaticUtils.DEFAULT_LOG;
 
-import java.io.Closeable;
 import java.io.IOException;
 import java.net.SocketAddress;
 import java.util.concurrent.atomic.AtomicBoolean;
+
 import org.forgerock.opendj.ldap.DecodeOptions;
 import org.forgerock.opendj.ldap.LDAPClientContext;
 import org.forgerock.opendj.ldap.LDAPListenerOptions;
 import org.forgerock.opendj.ldap.ServerConnectionFactory;
+import org.forgerock.opendj.ldap.spi.LDAPListenerImpl;
 import org.glassfish.grizzly.filterchain.FilterChain;
 import org.glassfish.grizzly.filterchain.FilterChainBuilder;
 import org.glassfish.grizzly.filterchain.TransportFilter;
@@ -48,9 +49,9 @@
 import com.forgerock.opendj.util.ReferenceCountedObject;
 
 /**
- * LDAP listener implementation.
+ * LDAP listener implementation using Grizzly for transport.
  */
-public final class LDAPListenerImpl implements Closeable {
+public final class GrizzlyLDAPListener implements LDAPListenerImpl {
     private final ReferenceCountedObject<TCPNIOTransport>.Reference transport;
     private final FilterChain defaultFilterChain;
     private final ServerConnectionFactory<LDAPClientContext, Integer> connectionFactory;
@@ -72,10 +73,35 @@
      *             If an error occurred while trying to listen on the provided
      *             address.
      */
-    public LDAPListenerImpl(final SocketAddress address,
+    public GrizzlyLDAPListener(final SocketAddress address,
             final ServerConnectionFactory<LDAPClientContext, Integer> factory,
             final LDAPListenerOptions options) throws IOException {
-        this.transport = DEFAULT_TRANSPORT.acquireIfNull(options.getTCPNIOTransport());
+        this(address, factory, options, null);
+    }
+
+    /**
+     * Creates a new LDAP listener implementation which will listen for LDAP
+     * client connections using the provided address, connection options and
+     * provided TCP transport.
+     *
+     * @param address
+     *            The address to listen on.
+     * @param factory
+     *            The server connection factory which will be used to create
+     *            server connections.
+     * @param options
+     *            The LDAP listener options.
+     * @param transport
+     *            Grizzly TCP Transport NIO implementation to use for
+     *            connections. If {@code null}, default transport will be used.
+     * @throws IOException
+     *             If an error occurred while trying to listen on the provided
+     *             address.
+     */
+    public GrizzlyLDAPListener(final SocketAddress address,
+            final ServerConnectionFactory<LDAPClientContext, Integer> factory,
+            final LDAPListenerOptions options, TCPNIOTransport transport) throws IOException {
+        this.transport = DEFAULT_TRANSPORT.acquireIfNull(transport);
         this.connectionFactory = factory;
 
         final DecodeOptions decodeOptions = new DecodeOptions(options.getDecodeOptions());
@@ -84,7 +110,7 @@
                         new LDAPServerFilter(this, new LDAPReader(decodeOptions), options
                                 .getMaxRequestSize())).build();
         final TCPNIOBindingHandler bindingHandler =
-                TCPNIOBindingHandler.builder(transport.get()).processor(defaultFilterChain).build();
+                TCPNIOBindingHandler.builder(this.transport.get()).processor(defaultFilterChain).build();
         this.serverConnection = bindingHandler.bind(address, options.getBacklog());
     }
 
@@ -104,11 +130,8 @@
         }
     }
 
-    /**
-     * Returns the address that this LDAP listener is listening on.
-     *
-     * @return The address that this LDAP listener is listening on.
-     */
+    /** {@inheritDoc} */
+    @Override
     public SocketAddress getSocketAddress() {
         return serverConnection.getLocalAddress();
     }
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyTransportProvider.java b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyTransportProvider.java
new file mode 100644
index 0000000..680dc9d
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyTransportProvider.java
@@ -0,0 +1,81 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at 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 2013 ForgeRock AS.
+ */
+package com.forgerock.opendj.ldap;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+
+import org.forgerock.opendj.ldap.LDAPClientContext;
+import org.forgerock.opendj.ldap.LDAPListenerOptions;
+import org.forgerock.opendj.ldap.LDAPOptions;
+import org.forgerock.opendj.ldap.ServerConnectionFactory;
+import org.forgerock.opendj.ldap.spi.LDAPConnectionFactoryImpl;
+import org.forgerock.opendj.ldap.spi.LDAPListenerImpl;
+import org.forgerock.opendj.ldap.spi.TransportProvider;
+
+/**
+ * Provides an implementation of {@code LDAPListener} using Grizzly as
+ * transport.
+ * <p>
+ * To be used, this implementation must be declared in the
+ * provider-configuration file
+ * {@code META-INF/services/org.forgerock.opendj.ldap.spi.LDAPListenerProvider}
+ * with this single line:
+ *
+ * <pre>
+ * com.forgerock.opendj.ldap.GrizzlyLDAPListenerProvider
+ * </pre>.
+ * <p>
+ * To require that this implementation is used, you must set the transport
+ * provider to {@code Grizzly} using
+ * {@code LDAPListenerOptions#setTransportProvider(String)} method. Otherwise
+ * there is no guarantee that this implementation will be used.
+ */
+public class GrizzlyTransportProvider implements TransportProvider {
+
+    /** {@inheritDoc} */
+    @Override
+    public LDAPConnectionFactoryImpl getLDAPConnectionFactory(SocketAddress address, LDAPOptions options) {
+        return new GrizzlyLDAPConnectionFactory(address, options);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public LDAPListenerImpl getLDAPListener(
+            SocketAddress address,
+            ServerConnectionFactory<LDAPClientContext, Integer> factory,
+            LDAPListenerOptions options)
+            throws IOException {
+        return new GrizzlyLDAPListener(address, factory, options);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getName() {
+        return "Grizzly";
+    }
+
+}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPClientFilter.java b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPClientFilter.java
index f540a8d..eddd89c 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPClientFilter.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPClientFilter.java
@@ -22,7 +22,7 @@
  *
  *
  *      Copyright 2010 Sun Microsystems, Inc.
- *      Portions copyright 2012 ForgeRock AS.
+ *      Portions copyright 2012-2013 ForgeRock AS.
  */
 
 package com.forgerock.opendj.ldap;
@@ -67,7 +67,7 @@
  * side logic for SSL and SASL operations over LDAP.
  */
 final class LDAPClientFilter extends BaseFilter {
-    private static final Attribute<LDAPConnection> LDAP_CONNECTION_ATTR =
+    private static final Attribute<GrizzlyLDAPConnection> LDAP_CONNECTION_ATTR =
             Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPClientConnection");
     private static final Attribute<ASN1BufferReader> LDAP_ASN1_READER_ATTR =
             Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPASN1Reader");
@@ -80,7 +80,7 @@
                 @Override
                 public void addResult(final FilterChainContext ctx, final int messageID,
                         final Result result) throws UnexpectedResponseException, IOException {
-                    final LDAPConnection ldapConnection =
+                    final GrizzlyLDAPConnection ldapConnection =
                             LDAP_CONNECTION_ATTR.get(ctx.getConnection());
                     if (ldapConnection != null) {
                         final AbstractLDAPFutureResultImpl<?> pendingRequest =
@@ -103,7 +103,7 @@
                 @Override
                 public void bindResult(final FilterChainContext ctx, final int messageID,
                         final BindResult result) throws UnexpectedResponseException, IOException {
-                    final LDAPConnection ldapConnection =
+                    final GrizzlyLDAPConnection ldapConnection =
                             LDAP_CONNECTION_ATTR.get(ctx.getConnection());
                     if (ldapConnection != null) {
                         final AbstractLDAPFutureResultImpl<?> pendingRequest =
@@ -179,7 +179,7 @@
                 @Override
                 public void compareResult(final FilterChainContext ctx, final int messageID,
                         final CompareResult result) throws UnexpectedResponseException, IOException {
-                    final LDAPConnection ldapConnection =
+                    final GrizzlyLDAPConnection ldapConnection =
                             LDAP_CONNECTION_ATTR.get(ctx.getConnection());
                     if (ldapConnection != null) {
                         final AbstractLDAPFutureResultImpl<?> pendingRequest =
@@ -200,7 +200,7 @@
                 @Override
                 public void deleteResult(final FilterChainContext ctx, final int messageID,
                         final Result result) throws UnexpectedResponseException, IOException {
-                    final LDAPConnection ldapConnection =
+                    final GrizzlyLDAPConnection ldapConnection =
                             LDAP_CONNECTION_ATTR.get(ctx.getConnection());
                     if (ldapConnection != null) {
                         final AbstractLDAPFutureResultImpl<?> pendingRequest =
@@ -224,7 +224,7 @@
                 public void extendedResult(final FilterChainContext ctx, final int messageID,
                         final ExtendedResult result) throws UnexpectedResponseException,
                         IOException {
-                    final LDAPConnection ldapConnection =
+                    final GrizzlyLDAPConnection ldapConnection =
                             LDAP_CONNECTION_ATTR.get(ctx.getConnection());
                     if (ldapConnection != null) {
                         if (messageID == 0) {
@@ -274,7 +274,7 @@
                 public void intermediateResponse(final FilterChainContext ctx, final int messageID,
                         final IntermediateResponse response) throws UnexpectedResponseException,
                         IOException {
-                    final LDAPConnection ldapConnection =
+                    final GrizzlyLDAPConnection ldapConnection =
                             LDAP_CONNECTION_ATTR.get(ctx.getConnection());
                     if (ldapConnection != null) {
                         final AbstractLDAPFutureResultImpl<?> pendingRequest =
@@ -289,7 +289,7 @@
                 @Override
                 public void modifyDNResult(final FilterChainContext ctx, final int messageID,
                         final Result result) throws UnexpectedResponseException, IOException {
-                    final LDAPConnection ldapConnection =
+                    final GrizzlyLDAPConnection ldapConnection =
                             LDAP_CONNECTION_ATTR.get(ctx.getConnection());
                     if (ldapConnection != null) {
                         final AbstractLDAPFutureResultImpl<?> pendingRequest =
@@ -312,7 +312,7 @@
                 @Override
                 public void modifyResult(final FilterChainContext ctx, final int messageID,
                         final Result result) throws UnexpectedResponseException, IOException {
-                    final LDAPConnection ldapConnection =
+                    final GrizzlyLDAPConnection ldapConnection =
                             LDAP_CONNECTION_ATTR.get(ctx.getConnection());
                     if (ldapConnection != null) {
                         final AbstractLDAPFutureResultImpl<?> pendingRequest =
@@ -335,7 +335,7 @@
                 @Override
                 public void searchResult(final FilterChainContext ctx, final int messageID,
                         final Result result) throws UnexpectedResponseException, IOException {
-                    final LDAPConnection ldapConnection =
+                    final GrizzlyLDAPConnection ldapConnection =
                             LDAP_CONNECTION_ATTR.get(ctx.getConnection());
                     if (ldapConnection != null) {
                         final AbstractLDAPFutureResultImpl<?> pendingRequest =
@@ -356,7 +356,7 @@
                 public void searchResultEntry(final FilterChainContext ctx, final int messageID,
                         final SearchResultEntry entry) throws UnexpectedResponseException,
                         IOException {
-                    final LDAPConnection ldapConnection =
+                    final GrizzlyLDAPConnection ldapConnection =
                             LDAP_CONNECTION_ATTR.get(ctx.getConnection());
                     if (ldapConnection != null) {
                         final AbstractLDAPFutureResultImpl<?> pendingRequest =
@@ -376,7 +376,7 @@
                 public void searchResultReference(final FilterChainContext ctx,
                         final int messageID, final SearchResultReference reference)
                         throws UnexpectedResponseException, IOException {
-                    final LDAPConnection ldapConnection =
+                    final GrizzlyLDAPConnection ldapConnection =
                             LDAP_CONNECTION_ATTR.get(ctx.getConnection());
                     if (ldapConnection != null) {
                         final AbstractLDAPFutureResultImpl<?> pendingRequest =
@@ -395,7 +395,7 @@
 
                 // Needed in order to expose type information.
                 private <R extends ExtendedResult> void handleExtendedResult0(
-                        final LDAPConnection conn, final LDAPExtendedFutureResultImpl<R> future,
+                        final GrizzlyLDAPConnection conn, final LDAPExtendedFutureResultImpl<R> future,
                         final ExtendedResult result) throws DecodeException {
                     final R decodedResponse =
                             future.decodeResult(result, conn.getLDAPOptions().getDecodeOptions());
@@ -457,7 +457,7 @@
             // Just ignore errors on closed connections.
             return;
         }
-        final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(connection);
+        final GrizzlyLDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(connection);
 
         Result errorResult;
         if (error instanceof EOFException) {
@@ -474,7 +474,7 @@
     @Override
     public NextAction handleClose(final FilterChainContext ctx) throws IOException {
         final Connection<?> connection = ctx.getConnection();
-        final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.remove(connection);
+        final GrizzlyLDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.remove(connection);
         if (ldapConnection != null) {
             final Result errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_SERVER_DOWN);
             ldapConnection.close(null, false, errorResult);
@@ -499,7 +499,7 @@
                 ldapReader.decode(asn1Reader, CLIENT_RESPONSE_HANDLER, ctx);
             }
         } catch (IOException ioe) {
-            final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx.getConnection());
+            final GrizzlyLDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx.getConnection());
             final Result errorResult =
                     Responses.newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR).setCause(ioe)
                             .setDiagnosticMessage(ioe.getMessage());
@@ -512,7 +512,7 @@
         return ctx.getStopAction();
     }
 
-    void registerConnection(final Connection<?> connection, final LDAPConnection ldapConnection) {
+    void registerConnection(final Connection<?> connection, final GrizzlyLDAPConnection ldapConnection) {
         LDAP_CONNECTION_ATTR.set(connection, ldapConnection);
     }
 }
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPServerFilter.java b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPServerFilter.java
index abd829a..4bbee8c 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPServerFilter.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPServerFilter.java
@@ -658,7 +658,7 @@
     }
 
     private final LDAPReader ldapReader;
-    private final LDAPListenerImpl listener;
+    private final GrizzlyLDAPListener listener;
     private final int maxASN1ElementSize;
 
     private final AbstractLDAPMessageHandler<FilterChainContext> serverRequestHandler =
@@ -794,7 +794,7 @@
                 }
             };
 
-    LDAPServerFilter(final LDAPListenerImpl listener, final LDAPReader ldapReader,
+    LDAPServerFilter(final GrizzlyLDAPListener listener, final LDAPReader ldapReader,
             final int maxASN1ElementSize) {
         this.listener = listener;
         this.ldapReader = ldapReader;
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/TimeoutChecker.java b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/TimeoutChecker.java
index 2ef5df9..2ecdd37 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/TimeoutChecker.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/TimeoutChecker.java
@@ -63,8 +63,8 @@
      * The connection set must be safe from CMEs because expiring requests can
      * cause the connection to be closed.
      */
-    private final Set<LDAPConnection> connections =
-            newSetFromMap(new ConcurrentHashMap<LDAPConnection, Boolean>());
+    private final Set<GrizzlyLDAPConnection> connections =
+            newSetFromMap(new ConcurrentHashMap<GrizzlyLDAPConnection, Boolean>());
 
     /**
      * Used to signal thread shutdown.
@@ -80,7 +80,7 @@
                     final long currentTime = System.currentTimeMillis();
                     long delay = 0;
 
-                    for (final LDAPConnection connection : connections) {
+                    for (final GrizzlyLDAPConnection connection : connections) {
                         DEFAULT_LOG.trace("Checking connection {} delay = {}", connection, delay);
 
                         // May update the connections set.
@@ -113,12 +113,12 @@
         checkerThread.start();
     }
 
-    void addConnection(final LDAPConnection connection) {
+    void addConnection(final GrizzlyLDAPConnection connection) {
         connections.add(connection);
         signal();
     }
 
-    void removeConnection(final LDAPConnection connection) {
+    void removeConnection(final GrizzlyLDAPConnection connection) {
         connections.remove(connection);
         // No need to signal.
     }
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/StaticUtils.java b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/StaticUtils.java
index f14ad93..1c5f81e 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/StaticUtils.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/StaticUtils.java
@@ -45,6 +45,7 @@
 import java.util.GregorianCalendar;
 import java.util.Iterator;
 import java.util.Locale;
+import java.util.ServiceLoader;
 import java.util.TimeZone;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
@@ -60,6 +61,8 @@
 import org.forgerock.i18n.LocalizableMessageBuilder;
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteStringBuilder;
+import org.forgerock.opendj.ldap.ProviderNotFoundException;
+import org.forgerock.opendj.ldap.spi.Provider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -2256,4 +2259,47 @@
         // No implementation required.
     }
 
+    /**
+     * Find and returns a provider of one or more implementations.
+     * <p>
+     * The provider is loaded using the {@code ServiceLoader} facility.
+     *
+     * @param <P> type of provider
+     * @param providerClass
+     *          class of provider
+     * @param requestedProvider
+     *            name of provider to use, or {@code null} if no specific
+     *            provider is requested.
+     * @param classLoader
+     *            class loader to use to load the provider, or {@code null} to
+     *            use the default class loader.
+     * @return a provider
+     * @throws ProviderNotFoundException
+     *             if no provider is available or if the provider requested
+     *             using options is not found.
+     */
+    public static <P extends Provider> P getProvider(final Class<P> providerClass, final String requestedProvider,
+            final ClassLoader classLoader) {
+
+        ServiceLoader<P> loader = ServiceLoader.load(providerClass, classLoader);
+        StringBuilder providersFound = new StringBuilder();
+        for (P provider : loader) {
+            if (providersFound.length() > 0) {
+                providersFound.append(" ");
+            }
+            providersFound.append(provider.getName());
+            if (requestedProvider == null || provider.getName().equals(requestedProvider)) {
+                return provider;
+            }
+        }
+        if (providersFound.length() > 0) {
+            throw new ProviderNotFoundException(providerClass, requestedProvider, String.format(
+                    "The requested provider '%s' of type '%s' was not found. Available providers: %s",
+                    requestedProvider, providerClass.getName(), providersFound));
+        } else {
+            throw new ProviderNotFoundException(providerClass, requestedProvider, String.format(
+                    "There was no provider of type '%s' available.", providerClass.getName()));
+        }
+    }
+
 }
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java
index 043e489..112b32e 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java
@@ -27,11 +27,15 @@
 
 package org.forgerock.opendj.ldap;
 
+import static com.forgerock.opendj.util.StaticUtils.getProvider;
+
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
 
-import com.forgerock.opendj.ldap.LDAPConnectionFactoryImpl;
+import org.forgerock.opendj.ldap.spi.LDAPConnectionFactoryImpl;
+import org.forgerock.opendj.ldap.spi.TransportProvider;
+
 import com.forgerock.opendj.util.Validator;
 
 /**
@@ -45,6 +49,11 @@
      */
     private final LDAPConnectionFactoryImpl impl;
 
+    /*
+     * Transport provider that provides the implementation of this factory.
+     */
+    private TransportProvider provider;
+
     /**
      * Creates a new LDAP connection factory which can be used to create LDAP
      * connections to the Directory Server at the provided address.
@@ -53,6 +62,8 @@
      *            The address of the Directory Server.
      * @throws NullPointerException
      *             If {@code address} was {@code null}.
+     * @throws ProviderNotFoundException if no provider is available or if the
+     *             provider requested using options is not found.
      */
     public LDAPConnectionFactory(final SocketAddress address) {
         this(address, new LDAPOptions());
@@ -68,10 +79,14 @@
      *            The LDAP options to use when creating connections.
      * @throws NullPointerException
      *             If {@code address} or {@code options} was {@code null}.
+     * @throws ProviderNotFoundException if no provider is available or if the
+     *             provider requested using options is not found.
      */
     public LDAPConnectionFactory(final SocketAddress address, final LDAPOptions options) {
         Validator.ensureNotNull(address, options);
-        this.impl = new LDAPConnectionFactoryImpl(address, options);
+        this.provider = getProvider(TransportProvider.class, options.getTransportProvider(),
+                options.getProviderClassLoader());
+        this.impl = provider.getLDAPConnectionFactory(address, options);
     }
 
     /**
@@ -85,6 +100,8 @@
      *            The port number.
      * @throws NullPointerException
      *             If {@code host} was {@code null}.
+     * @throws ProviderNotFoundException if no provider is available or if the
+     *             provider requested using options is not found.
      */
     public LDAPConnectionFactory(final String host, final int port) {
         this(host, port, new LDAPOptions());
@@ -103,11 +120,15 @@
      *            The LDAP options to use when creating connections.
      * @throws NullPointerException
      *             If {@code host} or {@code options} was {@code null}.
+     * @throws ProviderNotFoundException if no provider is available or if the
+     *             provider requested using options is not found.
      */
     public LDAPConnectionFactory(final String host, final int port, final LDAPOptions options) {
         Validator.ensureNotNull(host, options);
         final SocketAddress address = new InetSocketAddress(host, port);
-        this.impl = new LDAPConnectionFactoryImpl(address, options);
+        this.provider = getProvider(TransportProvider.class, options.getTransportProvider(),
+                options.getProviderClassLoader());
+        this.impl = provider.getLDAPConnectionFactory(address, options);
     }
 
     /**
@@ -175,14 +196,24 @@
     }
 
     /**
-     * Returns the address that this LDAP listener is listening on.
+     * Returns the address used by the connections created by this factory.
      *
-     * @return The address that this LDAP listener is listening on.
+     * @return The address used by the connections.
      */
     public SocketAddress getSocketAddress() {
         return impl.getSocketAddress();
     }
 
+    /**
+     * Returns the name of the transport provider, which provides the implementation
+     * of this factory.
+     *
+     * @return The name of actual transport provider.
+     */
+    public String getProviderName() {
+        return provider.getName();
+    }
+
     @Override
     public String toString() {
         return impl.toString();
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListener.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListener.java
index 4aa7445..bcbb5e4 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListener.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListener.java
@@ -27,13 +27,16 @@
 
 package org.forgerock.opendj.ldap;
 
+import static com.forgerock.opendj.util.StaticUtils.*;
+
 import java.io.Closeable;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
+import org.forgerock.opendj.ldap.spi.LDAPListenerImpl;
+import org.forgerock.opendj.ldap.spi.TransportProvider;
 
-import com.forgerock.opendj.ldap.LDAPListenerImpl;
 import com.forgerock.opendj.util.Validator;
 
 /**
@@ -91,11 +94,16 @@
  * </pre>
  */
 public final class LDAPListener implements Closeable {
+
     // We implement the factory using the pimpl idiom in order have
     // cleaner Javadoc which does not expose implementation methods.
-
     private final LDAPListenerImpl impl;
 
+    /*
+     * Transport provider that provides the implementation of this listener.
+     */
+    private TransportProvider provider;
+
     /**
      * Creates a new LDAP listener implementation which will listen for LDAP
      * client connections at the provided address.
@@ -138,7 +146,9 @@
             final LDAPListenerOptions options) throws IOException {
         Validator.ensureNotNull(factory, options);
         final SocketAddress address = new InetSocketAddress(port);
-        this.impl = new LDAPListenerImpl(address, factory, options);
+        this.provider = getProvider(TransportProvider.class, options.getTransportProvider(),
+                options.getProviderClassLoader());
+        this.impl = provider.getLDAPListener(address, factory, options);
     }
 
     /**
@@ -183,7 +193,9 @@
             final ServerConnectionFactory<LDAPClientContext, Integer> factory,
             final LDAPListenerOptions options) throws IOException {
         Validator.ensureNotNull(address, factory, options);
-        this.impl = new LDAPListenerImpl(address, factory, options);
+        this.provider = getProvider(TransportProvider.class, options.getTransportProvider(),
+                options.getProviderClassLoader());
+        this.impl = provider.getLDAPListener(address, factory, options);
     }
 
     /**
@@ -233,7 +245,9 @@
             final LDAPListenerOptions options) throws IOException {
         Validator.ensureNotNull(host, factory, options);
         final SocketAddress address = new InetSocketAddress(host, port);
-        this.impl = new LDAPListenerImpl(address, factory, options);
+        this.provider = getProvider(TransportProvider.class, options.getTransportProvider(),
+                options.getProviderClassLoader());
+        this.impl = provider.getLDAPListener(address, factory, options);
     }
 
     /**
@@ -302,6 +316,16 @@
     }
 
     /**
+     * Returns the name of the transport provider, which provides the implementation
+     * of this factory.
+     *
+     * @return The name of actual transport provider.
+     */
+    public String getProviderName() {
+        return provider.getName();
+    }
+
+    /**
      * {@inheritDoc}
      */
     public String toString() {
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListenerOptions.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListenerOptions.java
index 3290349..696e4f4 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListenerOptions.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListenerOptions.java
@@ -22,13 +22,11 @@
  *
  *
  *      Copyright 2010 Sun Microsystems, Inc.
- *      Portions copyright 2012 ForgeRock AS.
+ *      Portions copyright 2012-2013 ForgeRock AS.
  */
 
 package org.forgerock.opendj.ldap;
 
-import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
-
 import com.forgerock.opendj.util.Validator;
 
 /**
@@ -39,17 +37,15 @@
     private int backlog;
     private DecodeOptions decodeOptions;
     private int maxRequestSize;
-    private TCPNIOTransport transport;
+    private ClassLoader providerClassLoader;
+    private String transportProvider;
 
     /**
      * Creates a new set of listener options with default settings. SSL will not
      * be enabled, and a default set of decode options will be used.
      */
     public LDAPListenerOptions() {
-        this.backlog = 0;
-        this.maxRequestSize = 0;
         this.decodeOptions = new DecodeOptions();
-        this.transport = null;
     }
 
     /**
@@ -63,7 +59,8 @@
         this.backlog = options.backlog;
         this.maxRequestSize = options.maxRequestSize;
         this.decodeOptions = new DecodeOptions(options.decodeOptions);
-        this.transport = options.transport;
+        this.providerClassLoader = options.providerClassLoader;
+        this.transportProvider = options.transportProvider;
     }
 
     /**
@@ -102,22 +99,6 @@
     }
 
     /**
-     * Returns the Grizzly TCP transport which will be used when initiating
-     * connections with the Directory Server.
-     * <p>
-     * By default this method will return {@code null} indicating that the
-     * default transport factory should be used to obtain a TCP transport.
-     *
-     * @return The Grizzly TCP transport which will be used when initiating
-     *         connections with the Directory Server, or {@code null} if the
-     *         default transport factory should be used to obtain a TCP
-     *         transport.
-     */
-    public TCPNIOTransport getTCPNIOTransport() {
-        return transport;
-    }
-
-    /**
      * Sets the maximum queue length for incoming connections requests. If a
      * connection request arrives when the queue is full, the connection is
      * refused. If the backlog is less than {@code 1} then a default value of
@@ -165,21 +146,84 @@
     }
 
     /**
-     * Sets the Grizzly TCP transport which will be used when initiating
-     * connections with the Directory Server.
+     * Gets the class loader which will be used to load the
+     * {@code TransportProvider}.
      * <p>
      * By default this method will return {@code null} indicating that the
-     * default transport factory should be used to obtain a TCP transport.
+     * default class loader will be used.
+     * <p>
+     * The transport provider is loaded using {@code java.util.ServiceLoader},
+     * the JDK service-provider loading facility. The provider must be
+     * accessible from the same class loader that was initially queried to
+     * locate the configuration file; note that this is not necessarily the
+     * class loader from which the file was actually loaded. This method allows
+     * to provide a class loader to be used for loading the provider.
      *
-     * @param transport
-     *            The Grizzly TCP transport which will be used when initiating
-     *            connections with the Directory Server, or {@code null} if the
-     *            default transport factory should be used to obtain a TCP
-     *            transport.
-     * @return A reference to this connection options.
+     * @return The class loader which will be used to load the transport
+     *         provider, or {@code null} if the default class loader should be
+     *         used.
      */
-    public LDAPListenerOptions setTCPNIOTransport(final TCPNIOTransport transport) {
-        this.transport = transport;
+    public final ClassLoader getProviderClassLoader() {
+        return providerClassLoader;
+    }
+
+    /**
+     * Sets the class loader which will be used to load the
+     * {@code TransportProvider}.
+     * <p>
+     * The default class loader will be used if no class loader is set using
+     * this method.
+     * <p>
+     * The transport provider is loaded using {@code java.util.ServiceLoader},
+     * the JDK service-provider loading facility. The provider must be
+     * accessible from the same class loader that was initially queried to
+     * locate the configuration file; note that this is not necessarily the
+     * class loader from which the file was actually loaded. This method allows
+     * to provide a class loader to be used for loading the provider.
+     *
+     * @param classLoader
+     *            The class loader which will be used load the transport
+     *            provider, or {@code null} if the default class loader should
+     *            be used.
+     * @return A reference to this LDAP listener options.
+     */
+    public final LDAPListenerOptions setProviderClassLoader(ClassLoader classLoader) {
+        this.providerClassLoader = classLoader;
+        return this;
+    }
+
+    /**
+     * Returns the name of the provider used for transport.
+     * <p>
+     * Transport providers implement {@code TransportProvider} interface.
+     * <p>
+     * The name should correspond to the name of an existing provider, as
+     * returned by {@code TransportProvider#getName()} method.
+     *
+     * @return The name of transport provider. The name is {@code null} if no
+     *         specific provider has been selected. In that case, the first
+     *         provider found will be used.
+     */
+    public String getTransportProvider() {
+        return transportProvider;
+    }
+
+    /**
+     * Sets the name of the provider to use for transport.
+     * <p>
+     * Transport providers implement {@code TransportProvider} interface.
+     * <p>
+     * The name should correspond to the name of an existing provider, as
+     * returned by {@code TransportProvider#getName()} method.
+     *
+     * @param providerName
+     *            The name of transport provider, or {@code null} if no specific
+     *            provider is preferred. In that case, the first provider found
+     *            will be used.
+     * @return A reference to this LDAP listener options.
+     */
+    public LDAPListenerOptions setTransportProvider(String providerName) {
+        this.transportProvider = providerName;
         return this;
     }
 
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPOptions.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPOptions.java
index 4a8e8fc..9bcee09 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPOptions.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPOptions.java
@@ -22,7 +22,7 @@
  *
  *
  *      Copyright 2010 Sun Microsystems, Inc.
- *      Portions copyright 2012 ForgeRock AS.
+ *      Portions copyright 2012-2013 ForgeRock AS.
  */
 
 package org.forgerock.opendj.ldap;
@@ -33,8 +33,6 @@
 
 import javax.net.ssl.SSLContext;
 
-import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
-
 import com.forgerock.opendj.util.Validator;
 
 /**
@@ -63,18 +61,15 @@
     private DecodeOptions decodeOptions;
     private List<String> enabledCipherSuites = new LinkedList<String>();
     private List<String> enabledProtocols = new LinkedList<String>();
-    private TCPNIOTransport transport;
+    private ClassLoader providerClassLoader;
+    private String transportProvider;
 
     /**
      * Creates a new set of connection options with default settings. SSL will
      * not be enabled, and a default set of decode options will be used.
      */
     public LDAPOptions() {
-        this.sslContext = null;
-        this.timeoutInMillis = 0;
-        this.useStartTLS = false;
         this.decodeOptions = new DecodeOptions();
-        this.transport = null;
     }
 
     /**
@@ -91,7 +86,8 @@
         this.decodeOptions = new DecodeOptions(options.decodeOptions);
         this.enabledCipherSuites.addAll(options.getEnabledCipherSuites());
         this.enabledProtocols.addAll(options.getEnabledProtocols());
-        this.transport = options.transport;
+        this.providerClassLoader = options.providerClassLoader;
+        this.transportProvider = options.transportProvider;
     }
 
     /**
@@ -123,22 +119,6 @@
     }
 
     /**
-     * Returns the Grizzly TCP transport which will be used when initiating
-     * connections with the Directory Server.
-     * <p>
-     * By default this method will return {@code null} indicating that the
-     * default transport factory should be used to obtain a TCP transport.
-     *
-     * @return The Grizzly TCP transport which will be used when initiating
-     *         connections with the Directory Server, or {@code null} if the
-     *         default transport factory should be used to obtain a TCP
-     *         transport.
-     */
-    public final TCPNIOTransport getTCPNIOTransport() {
-        return transport;
-    }
-
-    /**
      * Returns the operation timeout in the specified unit.
      *
      * @param unit
@@ -187,25 +167,6 @@
     }
 
     /**
-     * Sets the Grizzly TCP transport which will be used when initiating
-     * connections with the Directory Server.
-     * <p>
-     * By default this method will return {@code null} indicating that the
-     * default transport factory will be used to obtain a TCP transport.
-     *
-     * @param transport
-     *            The Grizzly TCP transport which will be used when initiating
-     *            connections with the Directory Server, or {@code null} if the
-     *            default transport factory should be used to obtain a TCP
-     *            transport.
-     * @return A reference to this LDAP connection options.
-     */
-    public final LDAPOptions setTCPNIOTransport(final TCPNIOTransport transport) {
-        this.transport = transport;
-        return this;
-    }
-
-    /**
      * Sets the operation timeout. If the response is not received from the
      * Directory Server in the timeout period, the operation will be abandoned
      * and an error result returned. A timeout setting of 0 disables timeout
@@ -315,4 +276,88 @@
         return enabledCipherSuites;
     }
 
+    /**
+     * Gets the class loader which will be used to load the
+     * {@code TransportProvider}.
+     * <p>
+     * By default this method will return {@code null} indicating that the
+     * default class loader will be used.
+     * <p>
+     * The transport provider is loaded using {@code java.util.ServiceLoader},
+     * the JDK service-provider loading facility. The provider must be
+     * accessible from the same class loader that was initially queried to
+     * locate the configuration file; note that this is not necessarily the
+     * class loader from which the file was actually loaded. This method allows
+     * to provide a class loader to be used for loading the provider.
+     *
+     * @return The class loader which will be used when loading the transport
+     *         provider, or {@code null} if the default class loader should be
+     *         used.
+     */
+    public final ClassLoader getProviderClassLoader() {
+        return providerClassLoader;
+    }
+
+    /**
+     * Sets the class loader which will be used to load the
+     * {@code TransportProvider}.
+     * <p>
+     * The default class loader will be used if no class loader is set using
+     * this method.
+     * <p>
+     * The transport provider is loaded using {@code java.util.ServiceLoader},
+     * the JDK service-provider loading facility. The provider must be
+     * accessible from the same class loader that was initially queried to
+     * locate the configuration file; note that this is not necessarily the
+     * class loader from which the file was actually loaded. This method allows
+     * to provide a class loader to be used for loading the provider.
+     *
+     * @param classLoader
+     *            The class loader which will be used when loading the transport
+     *            provider, or {@code null} if the default class loader should
+     *            be used.
+     * @return A reference to this LDAP connection options.
+     */
+    public final LDAPOptions setProviderClassLoader(ClassLoader classLoader) {
+        this.providerClassLoader = classLoader;
+        return this;
+    }
+
+    /**
+     * Returns the name of the provider used for transport.
+     * <p>
+     * Transport providers implement {@code TransportProvider}
+     * interface.
+     * <p>
+     * The name should correspond to the name of an existing provider, as
+     * returned by {@code TransportProvider#getName()} method.
+     *
+     * @return The name of transport provider. The name is {@code null} if no
+     *         specific provider has been selected. In that case, the first
+     *         provider found will be used.
+     */
+    public String getTransportProvider() {
+        return transportProvider;
+    }
+
+    /**
+     * Sets the name of the provider to use for transport.
+     * <p>
+     * Transport providers implement {@code TransportProvider}
+     * interface.
+     * <p>
+     * The name should correspond to the name of an existing provider, as
+     * returned by {@code TransportProvider#getName()} method.
+     *
+     * @param providerName
+     *            The name of transport provider, or {@code null} if no specific
+     *            provider is preferred. In that case, the first provider found
+     *            will be used.
+     * @return A reference to this LDAP connection options.
+     */
+    public LDAPOptions setTransportProvider(String providerName) {
+        this.transportProvider = providerName;
+        return this;
+    }
+
 }
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ProviderNotFoundException.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ProviderNotFoundException.java
new file mode 100644
index 0000000..d11e447
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ProviderNotFoundException.java
@@ -0,0 +1,76 @@
+/*
+ * 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 2013 ForgeRock AS.
+ */
+
+package org.forgerock.opendj.ldap;
+
+import org.forgerock.opendj.ldap.spi.Provider;
+
+/**
+ * Exception thrown when a provider of a service can't be found.
+ */
+@SuppressWarnings("serial")
+public class ProviderNotFoundException extends RuntimeException {
+
+    private final Class<? extends Provider> providerType;
+    private final String providerName;
+
+    /**
+     * Creates the exception with a provider type, provider name and a message.
+     *
+     * @param providerClass
+     *            the provider class
+     * @param providerName
+     *            the name of the provider implementation that was requested
+     * @param message
+     *            the detail message
+     */
+    public ProviderNotFoundException(final Class<? extends Provider> providerClass, final String providerName,
+            final String message) {
+        super(message);
+        this.providerType = providerClass;
+        this.providerName = providerName;
+    }
+
+    /**
+     * Returns the type of provider.
+     *
+     * @return the provider class
+     */
+    public Class<?> getProviderType() {
+        return providerType;
+    }
+
+    /**
+     * Returns the name of provider.
+     *
+     * @return the name of the provider implementation that was requested, or
+     *         null if the default provider was requested.
+     */
+    public String getProviderName() {
+        return providerName;
+    }
+
+}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/LDAPConnectionFactoryImpl.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/LDAPConnectionFactoryImpl.java
new file mode 100644
index 0000000..ed5d466
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/LDAPConnectionFactoryImpl.java
@@ -0,0 +1,52 @@
+/*
+ * 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 2013 ForgeRock AS.
+ */
+package org.forgerock.opendj.ldap.spi;
+
+import java.net.SocketAddress;
+
+import org.forgerock.opendj.ldap.ConnectionFactory;
+
+/**
+ * Interface for all classes that actually implement
+ * {@code LDAPConnectionFactory}.
+ * <p>
+ * An implementation class is provided by a {@code TransportProvider}.
+ * <p>
+ * The implementation can be automatically loaded using the
+ * {@code java.util.ServiceLoader} facility if its provider extending
+ * {@code TransportProvider} is declared in the provider-configuration file
+ * {@code META-INF/services/org.forgerock.opendj.ldap.spi.TransportProvider}.
+ */
+public interface LDAPConnectionFactoryImpl extends ConnectionFactory {
+
+    /**
+     * Returns the address used by the connections created by this factory.
+     *
+     * @return The address used by the connections.
+     */
+    public SocketAddress getSocketAddress();
+
+}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/LDAPListenerImpl.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/LDAPListenerImpl.java
new file mode 100644
index 0000000..d8952f9
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/LDAPListenerImpl.java
@@ -0,0 +1,58 @@
+/*
+ * 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 2013 ForgeRock AS.
+ */
+package org.forgerock.opendj.ldap.spi;
+
+import java.io.Closeable;
+import java.net.SocketAddress;
+
+/**
+ * Interface for all classes that actually implement {@code LDAPListener}.
+ * <p>
+ * An implementation class is provided by a {@code TransportProvider}.
+ * <p>
+ * The implementation can be automatically loaded using the
+ * {@code java.util.ServiceLoader} facility if its provider extending
+ * {@code TransportProvider} is declared in the provider-configuration file
+ * {@code META-INF/services/org.forgerock.opendj.ldap.spi.TransportProvider}.
+ */
+public interface LDAPListenerImpl extends Closeable {
+
+    /**
+     * Returns the address that this LDAP listener is listening on.
+     *
+     * @return The address that this LDAP listener is listening on.
+     */
+    public SocketAddress getSocketAddress();
+
+    /**
+     * Closes this stream and releases any system resources associated
+     * with it. If the stream is already closed then invoking this
+     * method has no effect.
+     */
+    @Override
+    public void close();
+
+}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/Provider.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/Provider.java
new file mode 100644
index 0000000..2c0487e
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/Provider.java
@@ -0,0 +1,45 @@
+/*
+ * 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 2013 ForgeRock AS.
+ */
+package org.forgerock.opendj.ldap.spi;
+
+/**
+ * Interface for providers, which provide an implementation of one or more interfaces.
+ * <p>
+ * A provider must be declared in the provider-configuration file
+ * {@code META-INF/services/org.forgerock.opendj.ldap.spi.<ProviderClass>}
+ * in order to allow automatic loading of the implementation classes using the
+ * {@code java.util.ServiceLoader} facility.
+ */
+public interface Provider {
+
+    /**
+     * Returns the name of this provider.
+     *
+     * @return name of provider
+     */
+    String getName();
+
+}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/TransportProvider.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/TransportProvider.java
new file mode 100644
index 0000000..4b5bdc7
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/TransportProvider.java
@@ -0,0 +1,79 @@
+/*
+ * 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 2013 ForgeRock AS.
+ */
+package org.forgerock.opendj.ldap.spi;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+
+import org.forgerock.opendj.ldap.LDAPClientContext;
+import org.forgerock.opendj.ldap.LDAPListenerOptions;
+import org.forgerock.opendj.ldap.LDAPOptions;
+import org.forgerock.opendj.ldap.ServerConnectionFactory;
+
+/**
+ * Interface for transport providers, which provide implementation
+ * for {@code LDAPConnectionFactory} and {@code LDAPListener} classes,
+ * using a specific transport.
+ * <p>
+ * A transport provider must be declared in the provider-configuration file
+ * {@code META-INF/services/org.forgerock.opendj.ldap.spi.TransportProvider}
+ * in order to allow automatic loading of the implementation classes using the
+ * {@code java.util.ServiceLoader} facility.
+ */
+public interface TransportProvider extends Provider {
+
+    /**
+     * Returns an implementation of {@code LDAPConnectionFactory}.
+     *
+     * @param address
+     *          The address of the Directory Server to connect to.
+     * @param options
+     *            The LDAP options to use when creating connections.
+     * @return an implementation of {@code LDAPConnectionFactory}
+     */
+    LDAPConnectionFactoryImpl getLDAPConnectionFactory(SocketAddress address, LDAPOptions options);
+
+    /**
+     * Returns an implementation of {@code LDAPListener}.
+     *
+     * @param address
+     *            The address to listen on.
+     * @param factory
+     *            The server connection factory which will be used to create
+     *            server connections.
+     * @param options
+     *            The LDAP listener options.
+     * @return an implementation of {@code LDAPListener}
+     * @throws IOException
+     *             If an error occurred while trying to listen on the provided
+     *             address.
+     */
+    LDAPListenerImpl getLDAPListener(
+            SocketAddress address,
+            ServerConnectionFactory<LDAPClientContext, Integer> factory,
+            LDAPListenerOptions options) throws IOException;
+
+}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/package-info.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/package-info.java
new file mode 100644
index 0000000..b59caf0
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/package-info.java
@@ -0,0 +1,31 @@
+/*
+ * 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 2013 ForgeRock AS.
+ */
+
+/**
+ * Interfaces and classes for service providers.
+ */
+package org.forgerock.opendj.ldap.spi;
+
diff --git a/opendj3/opendj-ldap-sdk/src/main/resources/META-INF/services/org.forgerock.opendj.ldap.spi.TransportProvider b/opendj3/opendj-ldap-sdk/src/main/resources/META-INF/services/org.forgerock.opendj.ldap.spi.TransportProvider
new file mode 100644
index 0000000..fa780e5
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk/src/main/resources/META-INF/services/org.forgerock.opendj.ldap.spi.TransportProvider
@@ -0,0 +1,26 @@
+#
+# 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 2013 ForgeRock AS.
+#
+com.forgerock.opendj.ldap.GrizzlyTransportProvider
\ No newline at end of file
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/LDAPConnectionTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnectionTestCase.java
similarity index 91%
rename from opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/LDAPConnectionTestCase.java
rename to opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnectionTestCase.java
index 5924e23..c1b271d 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/LDAPConnectionTestCase.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnectionTestCase.java
@@ -38,7 +38,6 @@
 import org.forgerock.opendj.ldap.ErrorResultException;
 import org.forgerock.opendj.ldap.LDAPConnectionFactory;
 import org.forgerock.opendj.ldap.LDAPListener;
-import org.forgerock.opendj.ldap.LDAPOptions;
 import org.forgerock.opendj.ldap.RequestHandler;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchResultHandler;
@@ -55,7 +54,7 @@
  * Tests LDAP connection implementation class.
  */
 @SuppressWarnings("javadoc")
-public class LDAPConnectionTestCase extends LDAPTestCase {
+public class GrizzlyLDAPConnectionTestCase extends LDAPTestCase {
 
     /**
      * Tests that a normal request is subject to client side timeout checking.
@@ -84,16 +83,16 @@
         @SuppressWarnings("unchecked")
         LDAPListener listener =
                 new LDAPListener(address, Connections
-                        .newServerConnectionFactory(mock(RequestHandler.class)));
+                        .newServerConnectionFactory(mock(RequestHandler.class)),
+                        TestCaseUtils.getLDAPListenerTestOptions());
 
         /*
          * Use a very long time out in order to prevent the timeout thread from
          * triggering the timeout.
          */
-        LDAPConnectionFactory factory =
-                new LDAPConnectionFactory(address, new LDAPOptions().setTimeout(100,
-                        TimeUnit.SECONDS));
-        LDAPConnection connection = (LDAPConnection) factory.getConnection();
+        LDAPConnectionFactory factory = new LDAPConnectionFactory(address,
+                TestCaseUtils.getLDAPTestOptions().setTimeout(100, TimeUnit.SECONDS));
+        GrizzlyLDAPConnection connection = (GrizzlyLDAPConnection) factory.getConnection();
         try {
             SearchRequest request =
                     Requests.newSearchRequest("dc=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
index 590268a..2319b8c 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
@@ -28,13 +28,14 @@
 package org.forgerock.opendj.ldap;
 
 import static java.util.Arrays.asList;
+
+import static org.forgerock.opendj.ldap.TestCaseUtils.getLDAPTestOptions;
 import static org.fest.assertions.Assertions.assertThat;
 import static org.forgerock.opendj.ldap.Connections.newFixedConnectionPool;
 import static org.forgerock.opendj.ldap.Connections.newHeartBeatConnectionFactory;
 import static org.forgerock.opendj.ldap.Connections.newLoadBalancer;
 import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-import static org.forgerock.opendj.ldap.TestCaseUtils.findFreeSocketAddress;
-import static org.forgerock.opendj.ldap.TestCaseUtils.getServerSocketAddress;
+import static org.forgerock.opendj.ldap.TestCaseUtils.*;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.doAnswer;
@@ -142,7 +143,8 @@
 
         factories[0][0] =
                 Connections.newHeartBeatConnectionFactory(new LDAPConnectionFactory(
-                        getServerSocketAddress()), 1000, 500, TimeUnit.MILLISECONDS, request);
+                        getServerSocketAddress(), getLDAPTestOptions()),
+                        1000, 500, TimeUnit.MILLISECONDS, request);
 
         // InternalConnectionFactory
         factories[1][0] = Connections.newInternalConnectionFactory(LDAPServer.getInstance(), null);
@@ -150,22 +152,25 @@
         // AuthenticatedConnectionFactory
         factories[2][0] =
                 new AuthenticatedConnectionFactory(new LDAPConnectionFactory(
-                        getServerSocketAddress()), Requests.newSimpleBindRequest("", new char[0]));
+                        getServerSocketAddress(), getLDAPTestOptions()),
+                        Requests.newSimpleBindRequest("", new char[0]));
 
         // AuthenticatedConnectionFactory with multi-stage SASL
         factories[3][0] =
                 new AuthenticatedConnectionFactory(new LDAPConnectionFactory(
-                        getServerSocketAddress()), Requests.newCRAMMD5SASLBindRequest("id:user",
+                        getServerSocketAddress(), getLDAPTestOptions()),
+                        Requests.newCRAMMD5SASLBindRequest("id:user",
                             "password".toCharArray()));
 
         // LDAPConnectionFactory with default options
-        factories[4][0] = new LDAPConnectionFactory(getServerSocketAddress());
+        factories[4][0] = new LDAPConnectionFactory(getServerSocketAddress(),
+                getLDAPTestOptions());
 
         // LDAPConnectionFactory with startTLS
         SSLContext sslContext =
                 new SSLContextBuilder().setTrustManager(TrustManagers.trustAll()).getSSLContext();
         LDAPOptions options =
-                new LDAPOptions().setSSLContext(sslContext).setUseStartTLS(true)
+                getLDAPTestOptions().setSSLContext(sslContext).setUseStartTLS(true)
                         .addEnabledCipherSuite(
                                 new String[] { "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
                                     "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
@@ -188,12 +193,14 @@
 
         // Connection pool and load balancing tests.
         ConnectionFactory offlineServer1 =
-                Connections.newNamedConnectionFactory(new LDAPConnectionFactory(findFreeSocketAddress()), "offline1");
+                Connections.newNamedConnectionFactory(new LDAPConnectionFactory(findFreeSocketAddress(),
+                        getLDAPTestOptions()), "offline1");
         ConnectionFactory offlineServer2 =
-                Connections.newNamedConnectionFactory(new LDAPConnectionFactory(findFreeSocketAddress()), "offline2");
+                Connections.newNamedConnectionFactory(new LDAPConnectionFactory(findFreeSocketAddress(),
+                        getLDAPTestOptions()), "offline2");
         ConnectionFactory onlineServer =
                 Connections.newNamedConnectionFactory(new LDAPConnectionFactory(
-                        getServerSocketAddress()), "online");
+                        getServerSocketAddress(), getLDAPTestOptions()), "online");
 
         // Connection pools.
         factories[7][0] = Connections.newFixedConnectionPool(onlineServer, 10);
@@ -539,9 +546,11 @@
                     }
                 });
 
-        LDAPListener listener = new LDAPListener(findFreeSocketAddress(), mockServer);
+        LDAPListener listener = new LDAPListener(findFreeSocketAddress(), mockServer,
+                TestCaseUtils.getLDAPListenerTestOptions());
         try {
-            LDAPConnectionFactory clientFactory = new LDAPConnectionFactory(listener.getSocketAddress());
+            LDAPConnectionFactory clientFactory =
+                    new LDAPConnectionFactory(listener.getSocketAddress(), getLDAPTestOptions());
             final Connection client = clientFactory.getConnection();
             connectLatch.await(TEST_TIMEOUT, TimeUnit.SECONDS);
             MockConnectionEventListener mockListener = null;
@@ -620,9 +629,11 @@
                     }
                 });
 
-        LDAPListener listener = new LDAPListener(findFreeSocketAddress(), mockServer);
+        LDAPListener listener = new LDAPListener(findFreeSocketAddress(), mockServer,
+                getLDAPListenerTestOptions());
         try {
-            LDAPConnectionFactory clientFactory = new LDAPConnectionFactory(listener.getSocketAddress());
+            LDAPConnectionFactory clientFactory =
+                    new LDAPConnectionFactory(listener.getSocketAddress(), getLDAPTestOptions());
             final Connection client = clientFactory.getConnection();
             connectLatch.await(TEST_TIMEOUT, TimeUnit.SECONDS);
             try {
@@ -659,7 +670,7 @@
         final ConnectionFactory factory =
                 newLoadBalancer(new FailoverLoadBalancingAlgorithm(asList(newFixedConnectionPool(
                         newHeartBeatConnectionFactory(new LDAPConnectionFactory(
-                                getServerSocketAddress())), 2))));
+                                getServerSocketAddress(), getLDAPTestOptions())), 2))));
         Connection conn = null;
         try {
             conn = factory.getConnection();
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPConnectionFactoryTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPConnectionFactoryTestCase.java
index 01c2914..171df62 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPConnectionFactoryTestCase.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPConnectionFactoryTestCase.java
@@ -27,6 +27,7 @@
 
 import static org.fest.assertions.Assertions.assertThat;
 import static org.forgerock.opendj.ldap.TestCaseUtils.findFreeSocketAddress;
+import static org.forgerock.opendj.ldap.TestCaseUtils.getLDAPTestOptions;
 import static org.mockito.Mockito.mock;
 
 import java.io.IOException;
@@ -44,6 +45,21 @@
     // Test timeout for tests which need to wait for network events.
     private static final long TEST_TIMEOUT = 30L;
 
+    @Test
+    public void testCreateLDAPConnectionFactory() throws Exception {
+        // test no exception is thrown, which means transport provider is correctly loaded
+        LDAPConnectionFactory factory = new LDAPConnectionFactory(findFreeSocketAddress(), getLDAPTestOptions());
+        factory.close();
+    }
+
+    @Test(expectedExceptions = { ProviderNotFoundException.class },
+            expectedExceptionsMessageRegExp = "^The requested provider 'unknown' .*")
+    public void testCreateLDAPConnectionFactoryFailureProviderNotFound() throws Exception {
+        LDAPOptions options = getLDAPTestOptions().setTransportProvider("unknown");
+        LDAPConnectionFactory factory = new LDAPConnectionFactory(findFreeSocketAddress(), options);
+        factory.close();
+    }
+
     /**
      * This unit test exposes the bug raised in issue OPENDJ-1156: NPE in
      * ReferenceCountedObject after shutting down directory.
@@ -53,7 +69,8 @@
         final AtomicReference<LDAPClientContext> context = new AtomicReference<LDAPClientContext>();
         final Semaphore latch = new Semaphore(0);
         final LDAPListener server = createServer(latch, context);
-        final ConnectionFactory factory = new LDAPConnectionFactory(server.getSocketAddress());
+        final ConnectionFactory factory = new LDAPConnectionFactory(server.getSocketAddress(),
+                getLDAPTestOptions());
         try {
             for (int i = 0; i < 100; i++) {
                 // Connect to the server.
@@ -92,6 +109,7 @@
                         latch.release();
                         return mock(ServerConnection.class);
                     }
-                });
+                },
+                TestCaseUtils.getLDAPListenerTestOptions());
     }
 }
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPListenerTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPListenerTestCase.java
index 711ef98..dda8d5d 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPListenerTestCase.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPListenerTestCase.java
@@ -29,6 +29,7 @@
 import static org.fest.assertions.Assertions.*;
 import static org.fest.assertions.Fail.*;
 import static org.forgerock.opendj.ldap.TestCaseUtils.*;
+import static org.mockito.Mockito.*;
 
 import java.net.InetSocketAddress;
 import java.util.Arrays;
@@ -231,6 +232,31 @@
     }
 
     /**
+     * Test creation of LDAP listener with default transport provider.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testCreateLDAPListener() throws Exception {
+        // test no exception is thrown, which means transport provider is
+        // correctly loaded
+        LDAPListener listener = new LDAPListener(findFreeSocketAddress(), mock(ServerConnectionFactory.class),
+                getLDAPListenerTestOptions());
+        listener.close();
+    }
+
+    /**
+     * Test creation of LDAP listener with unknown transport provider.
+     */
+    @SuppressWarnings({ "unused", "resource", "unchecked" })
+    @Test(expectedExceptions = { ProviderNotFoundException.class },
+        expectedExceptionsMessageRegExp = "^The requested provider 'unknown' .*")
+    public void testCreateLDAPListenerFailureProviderNotFound() throws Exception {
+        LDAPListenerOptions options = getLDAPListenerTestOptions().setTransportProvider("unknown");
+        LDAPListener listener = new LDAPListener(findFreeSocketAddress(), mock(ServerConnectionFactory.class), options);
+        listener.close();
+    }
+
+    /**
      * Tests basic LDAP listener functionality.
      *
      * @throws Exception
@@ -242,11 +268,13 @@
         final MockServerConnectionFactory serverConnectionFactory =
                 new MockServerConnectionFactory(serverConnection);
         final LDAPListener listener =
-                new LDAPListener(new InetSocketAddress(0), serverConnectionFactory);
+                new LDAPListener(new InetSocketAddress(0), serverConnectionFactory,
+                        TestCaseUtils.getLDAPListenerTestOptions());
         try {
             // Connect and close.
             final Connection connection =
-                    new LDAPConnectionFactory(listener.getSocketAddress()).getConnection();
+                    new LDAPConnectionFactory(listener.getSocketAddress(), getLDAPTestOptions()).
+                    getConnection();
             assertThat(serverConnection.context.get(10, TimeUnit.SECONDS)).isNotNull();
             assertThat(serverConnection.isClosed.getCount()).isEqualTo(1);
             connection.close();
@@ -277,13 +305,14 @@
             // Connection pool and load balancing tests.
             final ConnectionFactory offlineServer1 =
                     Connections.newNamedConnectionFactory(new LDAPConnectionFactory(
-                            findFreeSocketAddress()), "offline1");
+                            findFreeSocketAddress(), getLDAPTestOptions()), "offline1");
             final ConnectionFactory offlineServer2 =
                     Connections.newNamedConnectionFactory(new LDAPConnectionFactory(
-                            findFreeSocketAddress()), "offline2");
+                            findFreeSocketAddress(), getLDAPTestOptions()), "offline2");
             final ConnectionFactory onlineServer =
                     Connections.newNamedConnectionFactory(new LDAPConnectionFactory(
-                            onlineServerListener.getSocketAddress()), "online");
+                            onlineServerListener.getSocketAddress(), getLDAPTestOptions()),
+                            "online");
 
             // Round robin.
             final ConnectionFactory loadBalancer =
@@ -345,19 +374,21 @@
         final MockServerConnectionFactory onlineServerConnectionFactory =
                 new MockServerConnectionFactory(onlineServerConnection);
         final LDAPListener onlineServerListener =
-                new LDAPListener(new InetSocketAddress(0), onlineServerConnectionFactory);
+                new LDAPListener(new InetSocketAddress(0), onlineServerConnectionFactory,
+                        getLDAPListenerTestOptions());
 
         try {
             // Connection pool and load balancing tests.
             final ConnectionFactory offlineServer1 =
                     Connections.newNamedConnectionFactory(new LDAPConnectionFactory(
-                            findFreeSocketAddress()), "offline1");
+                            findFreeSocketAddress(), getLDAPTestOptions()), "offline1");
             final ConnectionFactory offlineServer2 =
                     Connections.newNamedConnectionFactory(new LDAPConnectionFactory(
-                            findFreeSocketAddress()), "offline2");
+                            findFreeSocketAddress(), getLDAPTestOptions()), "offline2");
             final ConnectionFactory onlineServer =
                     Connections.newNamedConnectionFactory(new LDAPConnectionFactory(
-                            onlineServerListener.getSocketAddress()), "online");
+                            onlineServerListener.getSocketAddress(), getLDAPTestOptions()),
+                            "online");
 
             // Round robin.
             final ConnectionFactory loadBalancer =
@@ -396,11 +427,13 @@
                     new MockServerConnectionFactory(proxyServerConnection);
 
             final LDAPListener proxyListener =
-                    new LDAPListener(new InetSocketAddress(0), proxyServerConnectionFactory);
+                    new LDAPListener(new InetSocketAddress(0), proxyServerConnectionFactory,
+                            getLDAPListenerTestOptions());
             try {
                 // Connect, bind, and close.
                 final Connection connection =
-                        new LDAPConnectionFactory(proxyListener.getSocketAddress()).getConnection();
+                        new LDAPConnectionFactory(proxyListener.getSocketAddress(),
+                                getLDAPTestOptions()).getConnection();
                 try {
                     connection.bind("cn=test", "password".toCharArray());
 
@@ -447,7 +480,8 @@
                                 final LDAPClientContext clientContext) throws ErrorResultException {
                             // First attempt offline server.
                             LDAPConnectionFactory lcf =
-                                    new LDAPConnectionFactory(findFreeSocketAddress());
+                                    new LDAPConnectionFactory(findFreeSocketAddress(),
+                                            getLDAPTestOptions());
                             try {
                                 // This is expected to fail.
                                 lcf.getConnection().close();
@@ -486,7 +520,8 @@
             try {
                 // Connect and close.
                 final Connection connection =
-                        new LDAPConnectionFactory(proxyListener.getSocketAddress()).getConnection();
+                        new LDAPConnectionFactory(proxyListener.getSocketAddress(), getLDAPTestOptions()).
+                        getConnection();
 
                 assertThat(proxyServerConnection.context.get(10, TimeUnit.SECONDS)).isNotNull();
                 assertThat(onlineServerConnection.context.get(10, TimeUnit.SECONDS)).isNotNull();
@@ -516,7 +551,8 @@
         final MockServerConnectionFactory onlineServerConnectionFactory =
                 new MockServerConnectionFactory(onlineServerConnection);
         final LDAPListener onlineServerListener =
-                new LDAPListener(findFreeSocketAddress(), onlineServerConnectionFactory);
+                new LDAPListener(findFreeSocketAddress(), onlineServerConnectionFactory,
+                        getLDAPListenerTestOptions());
 
         try {
             final MockServerConnection proxyServerConnection = new MockServerConnection() {
@@ -531,7 +567,8 @@
                         final ResultHandler<BindResult> resultHandler)
                         throws UnsupportedOperationException {
                     // First attempt offline server.
-                    LDAPConnectionFactory lcf = new LDAPConnectionFactory(findFreeSocketAddress());
+                    LDAPConnectionFactory lcf = new LDAPConnectionFactory(findFreeSocketAddress(),
+                            getLDAPTestOptions());
                     try {
                         // This is expected to fail.
                         lcf.getConnection().close();
@@ -541,9 +578,8 @@
                     } catch (final ConnectionException ce) {
                         // This is expected - so go to online server.
                         try {
-                            lcf =
-                                    new LDAPConnectionFactory(onlineServerListener
-                                            .getSocketAddress());
+                            lcf = new LDAPConnectionFactory(onlineServerListener.getSocketAddress(),
+                                    getLDAPTestOptions());
                             lcf.getConnection().close();
                             resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS));
                         } catch (final Exception e) {
@@ -564,11 +600,14 @@
             final MockServerConnectionFactory proxyServerConnectionFactory =
                     new MockServerConnectionFactory(proxyServerConnection);
             final LDAPListener proxyListener =
-                    new LDAPListener(findFreeSocketAddress(), proxyServerConnectionFactory);
+                    new LDAPListener(findFreeSocketAddress(), proxyServerConnectionFactory,
+                            TestCaseUtils.getLDAPListenerTestOptions());
             try {
                 // Connect, bind, and close.
                 final Connection connection =
-                        new LDAPConnectionFactory(proxyListener.getSocketAddress()).getConnection();
+                        new LDAPConnectionFactory(proxyListener.getSocketAddress(),
+                                getLDAPTestOptions()).
+                        getConnection();
                 try {
                     connection.bind("cn=test", "password".toCharArray());
 
@@ -601,12 +640,14 @@
         final MockServerConnection serverConnection = new MockServerConnection();
         final MockServerConnectionFactory factory =
                 new MockServerConnectionFactory(serverConnection);
-        final LDAPListenerOptions options = new LDAPListenerOptions().setMaxRequestSize(2048);
+        final LDAPListenerOptions options =
+                TestCaseUtils.getLDAPListenerTestOptions().setMaxRequestSize(2048);
         final LDAPListener listener = new LDAPListener(findFreeSocketAddress(), factory, options);
 
         Connection connection = null;
         try {
-            connection = new LDAPConnectionFactory(listener.getSocketAddress()).getConnection();
+            connection = new LDAPConnectionFactory(listener.getSocketAddress(), getLDAPTestOptions()).
+                    getConnection();
 
             // Small request
             connection.bind("cn=test", "password".toCharArray());
@@ -658,12 +699,14 @@
         final MockServerConnection serverConnection = new MockServerConnection();
         final MockServerConnectionFactory factory =
                 new MockServerConnectionFactory(serverConnection);
-        final LDAPListener listener = new LDAPListener(findFreeSocketAddress(), factory);
+        final LDAPListener listener = new LDAPListener(findFreeSocketAddress(), factory,
+                TestCaseUtils.getLDAPListenerTestOptions());
 
         final Connection connection;
         try {
             // Connect and bind.
-            connection = new LDAPConnectionFactory(listener.getSocketAddress()).getConnection();
+            connection = new LDAPConnectionFactory(listener.getSocketAddress(), getLDAPTestOptions()).
+                    getConnection();
             try {
                 connection.bind("cn=test", "password".toCharArray());
             } catch (final ErrorResultException e) {
@@ -678,7 +721,8 @@
         try {
             // Connect and bind.
             final Connection failedConnection =
-                    new LDAPConnectionFactory(listener.getSocketAddress()).getConnection();
+                    new LDAPConnectionFactory(listener.getSocketAddress(), getLDAPTestOptions()).
+                    getConnection();
             failedConnection.close();
             connection.close();
             fail("Connection attempt to closed listener succeeded unexpectedly");
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
index 8ec3cdb..051bb6f 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
@@ -27,6 +27,8 @@
 
 package org.forgerock.opendj.ldap;
 
+import static org.forgerock.opendj.ldap.TestCaseUtils.*;
+
 import static com.forgerock.opendj.ldap.LDAPConstants.TYPE_AUTHENTICATION_SASL;
 
 import java.io.IOException;
@@ -542,8 +544,8 @@
         }
         sslContext = new SSLContextBuilder().getSSLContext();
         listener =
-                new LDAPListener(TestCaseUtils.findFreeSocketAddress(), getInstance(),
-                        new LDAPListenerOptions().setBacklog(4096));
+                new LDAPListener(findFreeSocketAddress(), getInstance(),
+                        getLDAPListenerTestOptions().setBacklog(4096));
         isRunning = true;
     }
 
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/TestCaseUtils.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/TestCaseUtils.java
index 2a8c3bd..17bd937 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/TestCaseUtils.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/TestCaseUtils.java
@@ -222,4 +222,26 @@
         }
         return mock;
     }
+
+    /**
+     * Returns LDAP options with the parameter {@code LDAPOptions#getClassLoader()} already
+     * set to the test class loader.
+     *
+     * @return LDAPOptions already set with the class loader used by the test.
+     *         This is required if the test need to use a transport provider.
+     */
+    public static LDAPOptions getLDAPTestOptions() {
+        return new LDAPOptions().setProviderClassLoader(Thread.currentThread().getContextClassLoader());
+    }
+
+    /**
+     * Returns LDAPListener options with the parameter {@code LDAPListenerOptions#getClassLoader()} already
+     * set to the test class loader.
+     *
+     * @return LDAPListenerOptions already set with the class loader used by the test.
+     *         This is required if the test need to use a transport provider.
+     */
+    public static LDAPListenerOptions getLDAPListenerTestOptions() {
+        return new LDAPListenerOptions().setProviderClassLoader(Thread.currentThread().getContextClassLoader());
+    }
 }
diff --git a/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConnectionFactoryProvider.java b/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConnectionFactoryProvider.java
index 00051cc..45ea5b3 100644
--- a/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConnectionFactoryProvider.java
+++ b/opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConnectionFactoryProvider.java
@@ -180,15 +180,23 @@
 
     private final ConsoleApplication app;
 
+    private LDAPOptions options;
+
     public ConnectionFactoryProvider(final ArgumentParser argumentParser,
             final ConsoleApplication app) throws ArgumentException {
-        this(argumentParser, app, "cn=Directory Manager", 389, false);
+        this(argumentParser, app, "cn=Directory Manager", 389, false, null);
+    }
+
+    public ConnectionFactoryProvider(final ArgumentParser argumentParser,
+            final ConsoleApplication app, final LDAPOptions options) throws ArgumentException {
+        this(argumentParser, app, "cn=Directory Manager", 389, false, options);
     }
 
     public ConnectionFactoryProvider(final ArgumentParser argumentParser,
             final ConsoleApplication app, final String defaultBindDN, final int defaultPort,
-            final boolean alwaysSSL) throws ArgumentException {
+            final boolean alwaysSSL, final LDAPOptions options) throws ArgumentException {
         this.app = app;
+        this.options = options == null ? new LDAPOptions() : options;
         useSSLArg =
                 new BooleanArgument("useSSL", OPTION_SHORT_USE_SSL, OPTION_LONG_USE_SSL,
                         INFO_DESCRIPTION_USE_SSL.get());
@@ -432,13 +440,9 @@
             }
 
             if (sslContext != null) {
-                final LDAPOptions options =
-                        new LDAPOptions().setSSLContext(sslContext).setUseStartTLS(
-                                useStartTLSArg.isPresent());
-                connFactory = new LDAPConnectionFactory(hostNameArg.getValue(), port, options);
-            } else {
-                connFactory = new LDAPConnectionFactory(hostNameArg.getValue(), port);
+                options.setSSLContext(sslContext).setUseStartTLS(useStartTLSArg.isPresent());
             }
+            connFactory = new LDAPConnectionFactory(hostNameArg.getValue(), port, options);
         }
         return connFactory;
     }
diff --git a/opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/ConnectionFactoryProviderTest.java b/opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/ConnectionFactoryProviderTest.java
index afcc9df..fc206a9 100644
--- a/opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/ConnectionFactoryProviderTest.java
+++ b/opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/ConnectionFactoryProviderTest.java
@@ -25,6 +25,8 @@
  */
 package com.forgerock.opendj.ldap.tools;
 
+import static com.forgerock.opendj.ldap.tools.TestCaseUtils.getLDAPTestOptions;
+
 import static org.fest.assertions.Assertions.*;
 
 import java.io.File;
@@ -50,7 +52,7 @@
     public void init() throws Exception {
         MockitoAnnotations.initMocks(this);
         argParser = new ArgumentParser("unused", new LocalizableMessageBuilder().toMessage(), false);
-        connectionFactoryProvider = new ConnectionFactoryProvider(argParser, app);
+        connectionFactoryProvider = new ConnectionFactoryProvider(argParser, app, getLDAPTestOptions());
     }
 
     @Test
diff --git a/opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/TestCaseUtils.java b/opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/TestCaseUtils.java
new file mode 100644
index 0000000..2ff091e
--- /dev/null
+++ b/opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/TestCaseUtils.java
@@ -0,0 +1,47 @@
+/*
+ * 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 2013 ForgeRock AS.
+ */
+
+package com.forgerock.opendj.ldap.tools;
+
+import org.forgerock.opendj.ldap.LDAPOptions;
+
+/**
+ * This class defines some utility functions which can be used by test cases.
+ */
+public final class TestCaseUtils {
+
+    /**
+     * Returns LDAP options with the parameter {@code LDAPOptions#getClassLoader()} already
+     * set to the test class loader.
+     *
+     * @return LDAPOptions already set with the class loader used by the test.
+     *         This is required if the test need to use a transport provider.
+     */
+    public static LDAPOptions getLDAPTestOptions() {
+        return new LDAPOptions().setProviderClassLoader(Thread.currentThread().getContextClassLoader());
+    }
+
+}
diff --git a/opendj3/opendj-server2x-adapter/src/test/java/org/forgerock/opendj/adapter/server2x/AdaptersTestCase.java b/opendj3/opendj-server2x-adapter/src/test/java/org/forgerock/opendj/adapter/server2x/AdaptersTestCase.java
index e191124..96146a3 100644
--- a/opendj3/opendj-server2x-adapter/src/test/java/org/forgerock/opendj/adapter/server2x/AdaptersTestCase.java
+++ b/opendj3/opendj-server2x-adapter/src/test/java/org/forgerock/opendj/adapter/server2x/AdaptersTestCase.java
@@ -73,13 +73,13 @@
 import org.forgerock.opendj.ldap.responses.WhoAmIExtendedResult;
 import org.forgerock.opendj.ldif.ConnectionEntryReader;
 import org.forgerock.testng.ForgeRockTestCase;
-
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import static org.forgerock.opendj.adapter.server2x.EmbeddedServerTestCaseUtils.CONFIG_PROPERTIES;
+import static org.forgerock.opendj.adapter.server2x.TestCaseUtils.getLDAPTestOptions;
 
 /**
  * This class defines a set of tests for the Adapters.class.
@@ -96,8 +96,9 @@
     @DataProvider
     public Object[][] anonymousConnectionFactories() {
         return new Object[][] {
-            { new LDAPConnectionFactory("localhost", Integer.valueOf(CONFIG_PROPERTIES
-                    .getProperty("listen-port"))) }, { Adapters.newAnonymousConnectionFactory() } };
+            { new LDAPConnectionFactory("localhost", Integer.valueOf(CONFIG_PROPERTIES.getProperty("listen-port")),
+                        getLDAPTestOptions()) },
+            { Adapters.newAnonymousConnectionFactory() } };
     }
 
     /**
@@ -108,9 +109,11 @@
     @DataProvider
     public Object[][] rootConnectionFactories() {
         return new Object[][] {
-            { Connections.newAuthenticatedConnectionFactory(new LDAPConnectionFactory("localhost",
-                    Integer.valueOf(CONFIG_PROPERTIES.getProperty("listen-port"))), Requests
-                    .newSimpleBindRequest("cn=directory manager", "password".toCharArray())) },
+            { Connections.newAuthenticatedConnectionFactory(
+                   new LDAPConnectionFactory("localhost",
+                           Integer.valueOf(CONFIG_PROPERTIES.getProperty("listen-port")),
+                           getLDAPTestOptions()),
+                   Requests.newSimpleBindRequest("cn=directory manager", "password".toCharArray())) },
             { Adapters.newConnectionFactoryForUser(DN.valueOf("cn=directory manager")) } };
     }
 
@@ -216,7 +219,7 @@
     public void testSimpleLDAPConnectionFactorySimpleBind() throws ErrorResultException {
         final LDAPConnectionFactory factory =
                 new LDAPConnectionFactory("localhost", Integer.valueOf(CONFIG_PROPERTIES
-                        .getProperty("listen-port")));
+                        .getProperty("listen-port")), getLDAPTestOptions());
         Connection connection = null;
         try {
             connection = factory.getConnection();
@@ -242,7 +245,7 @@
             ErrorResultException {
         LDAPConnectionFactory factory =
                 new LDAPConnectionFactory("localhost", Integer.valueOf(CONFIG_PROPERTIES
-                        .getProperty("listen-port")));
+                        .getProperty("listen-port")), getLDAPTestOptions());
 
         Connection connection = factory.getConnection();
         PlainSASLBindRequest request =
@@ -1020,7 +1023,7 @@
         // LDAP Connection
         final LDAPConnectionFactory factory =
                 new LDAPConnectionFactory("localhost", Integer.valueOf(CONFIG_PROPERTIES
-                        .getProperty("listen-port")));
+                        .getProperty("listen-port")), getLDAPTestOptions());
         Connection connection = null;
         connection = factory.getConnection();
         connection.bind("cn=Directory Manager", "password".toCharArray());
diff --git a/opendj3/opendj-server2x-adapter/src/test/java/org/forgerock/opendj/adapter/server2x/TestCaseUtils.java b/opendj3/opendj-server2x-adapter/src/test/java/org/forgerock/opendj/adapter/server2x/TestCaseUtils.java
new file mode 100644
index 0000000..e1aaf26
--- /dev/null
+++ b/opendj3/opendj-server2x-adapter/src/test/java/org/forgerock/opendj/adapter/server2x/TestCaseUtils.java
@@ -0,0 +1,47 @@
+/*
+ * 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 2013 ForgeRock AS.
+ */
+
+package org.forgerock.opendj.adapter.server2x;
+
+import org.forgerock.opendj.ldap.LDAPOptions;
+
+/**
+ * This class defines some utility functions which can be used by test cases.
+ */
+public final class TestCaseUtils {
+
+    /**
+     * Returns LDAP options with the parameter {@code LDAPOptions#getClassLoader()} already
+     * set to the test class loader.
+     *
+     * @return LDAPOptions already set with the class loader used by the test.
+     *         This is required if the test need to use a transport provider.
+     */
+    public static LDAPOptions getLDAPTestOptions() {
+        return new LDAPOptions().setProviderClassLoader(Thread.currentThread().getContextClassLoader());
+    }
+
+}

--
Gitblit v1.10.0