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

Nicolas Capponi
08.16.2013 f2090c0d863b07e3bad8d16a3efddfad6ff77960
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

* LDAPConnectionFactory/LDAPListener load its implementation via java.util.ServiceLoader, the JDK loader facility.
An implementation is given by a transport provider.

Common code to load a provider is implemented in StaticUtils#getProvider

* New package org.forgerock.opendj.ldap.spi that contains interfaces for providers and implementations.
TransportProvider interface which provides:
- LDAPConnectionFactoryImpl, implementation for LDAPConnectionFactory
- LDAPListenerImpl, implementation for LDAPListener

* There is one transport provider based on Grizzly: GrizzlyTransportProvider class which provides the two implementation classes
- GrizzlyLDAPConnectionFactory
- GrizzlyLDAPListener
In order to locate transport provider to use, the file 'org.forgerock.opendj.ldap.spi.TransportProvider'
must be available in the classpath in META-INF/services directory.

That file is included with the value "com.forgerock.opendj.ldap.GrizzlyTransportProvider" to have Grizzly as the default provider

* LDAPOptions and LDAPListenerOptions:
- have no more TCPNIOTransport option,
- have two new options transportProvider and providerClassLoader to tune loading of providers.
- transportProvider allow to require a given provider (eg, "Grizzly"), otherwise the first provider found will be used.
- providerClassLoader allow to provide a class loader to use when several class loaders are used by an application.
ServiceLoader needs to load both provider-configuration file and provider class from the same class loader,
so there are case where you must provide the correct class loader to find the provider class.

* Fixed all the tests in opendj-ldap-sdk, because they suffer from the class loader problem if not providing the right class loader
- Systematically provide the class loader used by test class when creating LDAPConnectionFactory or LDAPListener
- Added utility methods in TestCaseUtils class to ease the use of custom class loader

* Fixed tests in modules: opendj-ldap-toolkit and opendj-server2x-adapter
- Same fix than for opendj-ldap-sdk
- Added new TestCaseUtils.java class in both modules to hold utility methods

10 files added
4 files renamed
16 files modified
1306 ■■■■ changed files
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnection.java 8 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnectionFactory.java 50 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPListener.java 45 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyTransportProvider.java 81 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPClientFilter.java 36 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPServerFilter.java 4 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/TimeoutChecker.java 10 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/StaticUtils.java 46 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java 41 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListener.java 34 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListenerOptions.java 114 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPOptions.java 133 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ProviderNotFoundException.java 76 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/LDAPConnectionFactoryImpl.java 52 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/LDAPListenerImpl.java 58 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/Provider.java 45 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/TransportProvider.java 79 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/package-info.java 31 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/resources/META-INF/services/org.forgerock.opendj.ldap.spi.TransportProvider 26 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnectionTestCase.java 13 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java 41 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPConnectionFactoryTestCase.java 22 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPListenerTestCase.java 94 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java 6 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/TestCaseUtils.java 22 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConnectionFactoryProvider.java 20 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/ConnectionFactoryProviderTest.java 4 ●●● patch | view | raw | blame | history
opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/TestCaseUtils.java 47 ●●●●● patch | view | raw | blame | history
opendj3/opendj-server2x-adapter/src/test/java/org/forgerock/opendj/adapter/server2x/AdaptersTestCase.java 21 ●●●●● patch | view | raw | blame | history
opendj3/opendj-server2x-adapter/src/test/java/org/forgerock/opendj/adapter/server2x/TestCaseUtils.java 47 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnection.java
File was renamed from opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnection.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;
    }
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnectionFactory.java
File was renamed from opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPConnectionFactoryImpl.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
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyLDAPListener.java
File was renamed from opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPListenerImpl.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();
    }
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/GrizzlyTransportProvider.java
New file
@@ -0,0 +1,81 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at 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";
    }
}
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);
    }
}
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;
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.
    }
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()));
        }
    }
}
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();
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() {
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;
    }
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;
    }
}
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ProviderNotFoundException.java
New file
@@ -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;
    }
}
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/LDAPConnectionFactoryImpl.java
New file
@@ -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();
}
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/LDAPListenerImpl.java
New file
@@ -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();
}
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/Provider.java
New file
@@ -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();
}
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/TransportProvider.java
New file
@@ -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;
}
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/spi/package-info.java
New file
@@ -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;
opendj3/opendj-ldap-sdk/src/main/resources/META-INF/services/org.forgerock.opendj.ldap.spi.TransportProvider
New file
@@ -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
opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/GrizzlyLDAPConnectionTestCase.java
File was renamed from opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/LDAPConnectionTestCase.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=*)");
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();
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());
    }
}
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");
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;
    }
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());
    }
}
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;
    }
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
opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/TestCaseUtils.java
New file
@@ -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());
    }
}
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());
opendj3/opendj-server2x-adapter/src/test/java/org/forgerock/opendj/adapter/server2x/TestCaseUtils.java
New file
@@ -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());
    }
}