You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2021/06/11 07:36:57 UTC

[james-project] 01/18: JAMES-3594 Implement ReadOnlyLDAPUsersDAO with UnboundID library

This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 393c65a6e5196b8b167e679784957c290c7c976f
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Jun 6 13:13:53 2021 +0700

    JAMES-3594 Implement ReadOnlyLDAPUsersDAO with UnboundID library
---
 pom.xml                                            |   6 +-
 server/data/data-ldap/pom.xml                      |   4 +
 .../user/ldap/LdapRepositoryConfiguration.java     |  22 +-
 .../apache/james/user/ldap/ReadOnlyLDAPUser.java   |  76 ++--
 .../james/user/ldap/ReadOnlyLDAPUsersDAO.java      | 266 ++++-------
 .../apache/james/user/ldap/api/LdapConstants.java  |  32 --
 .../user/ldap/retry/DoublingRetrySchedule.java     |  99 ----
 .../user/ldap/retry/ExceptionRetryHandler.java     | 131 ------
 .../ldap/retry/api/ExceptionRetryingProxy.java     |  49 --
 .../james/user/ldap/retry/api/RetryHandler.java    |  52 ---
 .../james/user/ldap/retry/api/RetrySchedule.java   |  35 --
 .../ldap/retry/naming/LoggingRetryHandler.java     |  54 ---
 .../retry/naming/NamingExceptionRetryHandler.java  |  72 ---
 .../user/ldap/retry/naming/RetryingContext.java    | 497 ---------------------
 .../retry/naming/directory/RetryingDirContext.java | 407 -----------------
 .../retry/naming/ldap/RetryingLdapContext.java     | 129 ------
 .../user/ldap/retry/DoublingRetryScheduleTest.java |  71 ---
 .../user/ldap/retry/ExceptionRetryHandlerTest.java | 153 -------
 .../naming/NamingExceptionRetryHandlerTest.java    |  92 ----
 19 files changed, 132 insertions(+), 2115 deletions(-)

diff --git a/pom.xml b/pom.xml
index f7bc55a..21e035a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2105,7 +2105,6 @@
                 <artifactId>metrics-elasticsearch-reporter</artifactId>
                 <version>${es-reporter.version}</version>
             </dependency>
-
             <dependency>
                 <groupId>com.rabbitmq</groupId>
                 <artifactId>amqp-client</artifactId>
@@ -2153,6 +2152,11 @@
                 <version>2.9.2</version>
             </dependency>
             <dependency>
+                <groupId>com.unboundid</groupId>
+                <artifactId>unboundid-ldapsdk</artifactId>
+                <version>6.0.0</version>
+            </dependency>
+            <dependency>
                 <groupId>commons-beanutils</groupId>
                 <artifactId>commons-beanutils</artifactId>
                 <version>1.9.4</version>
diff --git a/server/data/data-ldap/pom.xml b/server/data/data-ldap/pom.xml
index 88492e1..aec06a1 100644
--- a/server/data/data-ldap/pom.xml
+++ b/server/data/data-ldap/pom.xml
@@ -70,6 +70,10 @@
             <artifactId>guavate</artifactId>
         </dependency>
         <dependency>
+            <groupId>com.unboundid</groupId>
+            <artifactId>unboundid-ldapsdk</artifactId>
+        </dependency>
+        <dependency>
             <groupId>javax.annotation</groupId>
             <artifactId>javax.annotation-api</artifactId>
         </dependency>
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/LdapRepositoryConfiguration.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/LdapRepositoryConfiguration.java
index f526cd2..efc79ed 100644
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/LdapRepositoryConfiguration.java
+++ b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/LdapRepositoryConfiguration.java
@@ -32,9 +32,8 @@ import com.google.common.base.Preconditions;
 public class LdapRepositoryConfiguration {
     public static final String SUPPORTS_VIRTUAL_HOSTING = "supportsVirtualHosting";
 
-    private static final boolean NO_CONNECTION_POOL = false;
-    private static final int NO_CONNECTION_TIMEOUT = -1;
-    private static final int NO_READ_TIME_OUT = -1;
+    private static final int NO_CONNECTION_TIMEOUT = 0;
+    private static final int NO_READ_TIME_OUT = 0;
     private static final boolean ENABLE_VIRTUAL_HOSTING = true;
     private static final ReadOnlyLDAPGroupRestriction NO_RESTRICTION = new ReadOnlyLDAPGroupRestriction(null);
     private static final String NO_FILTER = null;
@@ -134,7 +133,6 @@ public class LdapRepositoryConfiguration {
                 userBase.get(),
                 userIdAttribute.get(),
                 userObjectClass.get(),
-                NO_CONNECTION_POOL,
                 NO_CONNECTION_TIMEOUT,
                 NO_READ_TIME_OUT,
                 maxRetries.get(),
@@ -160,7 +158,6 @@ public class LdapRepositoryConfiguration {
         String userIdAttribute = configuration.getString("[@userIdAttribute]");
         String userObjectClass = configuration.getString("[@userObjectClass]");
         // Default is to use connection pooling
-        boolean useConnectionPool = configuration.getBoolean("[@useConnectionPool]", NO_CONNECTION_POOL);
         int connectionTimeout = configuration.getInt("[@connectionTimeout]", NO_CONNECTION_TIMEOUT);
         int readTimeout = configuration.getInt("[@readTimeout]", NO_READ_TIME_OUT);
         // Default maximum retries is 1, which allows an alternate connection to
@@ -193,7 +190,6 @@ public class LdapRepositoryConfiguration {
             userBase,
             userIdAttribute,
             userObjectClass,
-            useConnectionPool,
             connectionTimeout,
             readTimeout,
             maxRetries,
@@ -251,9 +247,6 @@ public class LdapRepositoryConfiguration {
      */
     private final String userObjectClass;
 
-    // Use a connection pool. Default is true.
-    private final boolean useConnectionPool;
-
     // The connection timeout in milliseconds.
     // A value of less than or equal to zero means to use the network protocol's
     // (i.e., TCP's) timeout value.
@@ -290,7 +283,7 @@ public class LdapRepositoryConfiguration {
     private final Optional<Username> administratorId;
 
     private LdapRepositoryConfiguration(String ldapHost, String principal, String credentials, String userBase, String userIdAttribute,
-                                       String userObjectClass, boolean useConnectionPool, int connectionTimeout, int readTimeout,
+                                       String userObjectClass, int connectionTimeout, int readTimeout,
                                        int maxRetries, boolean supportsVirtualHosting, long retryStartInterval, long retryMaxInterval,
                                        int scale, ReadOnlyLDAPGroupRestriction restriction, String filter,
                                        Optional<String> administratorId) throws ConfigurationException {
@@ -300,7 +293,6 @@ public class LdapRepositoryConfiguration {
         this.userBase = userBase;
         this.userIdAttribute = userIdAttribute;
         this.userObjectClass = userObjectClass;
-        this.useConnectionPool = useConnectionPool;
         this.connectionTimeout = connectionTimeout;
         this.readTimeout = readTimeout;
         this.maxRetries = maxRetries;
@@ -351,9 +343,6 @@ public class LdapRepositoryConfiguration {
         return userObjectClass;
     }
 
-    public boolean useConnectionPool() {
-        return useConnectionPool;
-    }
 
     public int getConnectionTimeout() {
         return connectionTimeout;
@@ -400,8 +389,7 @@ public class LdapRepositoryConfiguration {
         if (o instanceof LdapRepositoryConfiguration) {
             LdapRepositoryConfiguration that = (LdapRepositoryConfiguration) o;
 
-            return Objects.equals(this.useConnectionPool, that.useConnectionPool)
-                && Objects.equals(this.connectionTimeout, that.connectionTimeout)
+            return Objects.equals(this.connectionTimeout, that.connectionTimeout)
                 && Objects.equals(this.readTimeout, that.readTimeout)
                 && Objects.equals(this.maxRetries, that.maxRetries)
                 && Objects.equals(this.supportsVirtualHosting, that.supportsVirtualHosting)
@@ -423,7 +411,7 @@ public class LdapRepositoryConfiguration {
 
     @Override
     public final int hashCode() {
-        return Objects.hash(ldapHost, principal, credentials, userBase, userIdAttribute, userObjectClass, useConnectionPool,
+        return Objects.hash(ldapHost, principal, credentials, userBase, userIdAttribute, userObjectClass,
             connectionTimeout, readTimeout, maxRetries, supportsVirtualHosting, retryStartInterval, retryMaxInterval, scale,
             restriction, filter, administratorId);
     }
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyLDAPUser.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyLDAPUser.java
index 6946fa6..6125fb9 100644
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyLDAPUser.java
+++ b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyLDAPUser.java
@@ -21,13 +21,14 @@ package org.apache.james.user.ldap;
 
 import java.io.Serializable;
 
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.naming.ldap.LdapContext;
-
 import org.apache.james.core.Username;
 import org.apache.james.user.api.model.User;
-import org.apache.james.user.ldap.api.LdapConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.unboundid.ldap.sdk.BindResult;
+import com.unboundid.ldap.sdk.LDAPConnectionPool;
+import com.unboundid.ldap.sdk.LDAPException;
 
 /**
  * Encapsulates the details of a user as taken from an LDAP compliant directory.
@@ -38,14 +39,13 @@ import org.apache.james.user.ldap.api.LdapConstants;
  * means of authenticating the user against the LDAP server. Consequently
  * invocations of the contract method {@link User#setPassword(String)} always
  * returns <code>false</code>.
- * 
- * @see SimpleLDAPConnection
+ *
  * @see ReadOnlyUsersLDAPRepository
  * 
  */
 public class ReadOnlyLDAPUser implements User, Serializable {
-    // private static final long serialVersionUID = -6712066073820393235L; 
-    private static final long serialVersionUID = -5201235065842464013L;
+    private static final long serialVersionUID = -5201235065842464014L;
+    public static final Logger LOGGER = LoggerFactory.getLogger(ReadOnlyLDAPUser.class);
 
     /**
      * The user's identifier or name. This is the value that is returned by the
@@ -55,31 +55,28 @@ public class ReadOnlyLDAPUser implements User, Serializable {
      * <code>&quot;myorg.com&quot;</code>, the user's email address will be
      * <code>&quot;john.bold&#64;myorg.com&quot;</code>.
      */
-    private Username userName;
+    private final Username userName;
 
     /**
      * The distinguished name of the user-record in the LDAP directory.
      */
-    private String userDN;
+    private final String userDN;
 
     /**
      * The context for the LDAP server from which to retrieve the
      * user's details.
      */
-    private LdapContext ldapContext = null;
-
-    /**
-     * Creates a new instance of ReadOnlyLDAPUser.
-     *
-     */
-    private ReadOnlyLDAPUser() {
-        super();
-    }
+    private final LDAPConnectionPool connectionPool;
 
     /**
      * Constructs an instance for the given user-details, and which will
      * authenticate against the given host.
-     * 
+     *
+     * @param connectionPool
+     *            The connectionPool for the LDAP server on which the user details are held.
+     *            This is also the host against which the user will be
+     *            authenticated, when {@link #verifyPassword(String)} is
+     *            invoked.
      * @param userName
      *            The user-identifier/name. This is the value with which the
      *            field  will be initialised, and which will be
@@ -87,18 +84,11 @@ public class ReadOnlyLDAPUser implements User, Serializable {
      * @param userDN
      *            The distinguished (unique-key) of the user details as stored
      *            on the LDAP directory.
-     * @param ldapContext
-     *            The context for the LDAP server on which the user details are held.
-     *            This is also the host against which the user will be
-     *            authenticated, when {@link #verifyPassword(String)} is
-     *            invoked.
-     * @throws NamingException 
      */
-    public ReadOnlyLDAPUser(Username userName, String userDN, LdapContext ldapContext) {
-        this();
+    public ReadOnlyLDAPUser(Username userName, String userDN, LDAPConnectionPool connectionPool) {
         this.userName = userName;
         this.userDN = userDN;
-        this.ldapContext = ldapContext;
+        this.connectionPool = connectionPool;
     }
 
     /**
@@ -139,27 +129,13 @@ public class ReadOnlyLDAPUser implements User, Serializable {
      */
     @Override
     public boolean verifyPassword(String password) {
-        boolean result = false;
-        LdapContext ldapContext = null;
         try {
-            ldapContext = this.ldapContext.newInstance(null);
-            ldapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION,
-                    LdapConstants.SECURITY_AUTHENTICATION_SIMPLE);
-            ldapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN);
-            ldapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
-            ldapContext.reconnect(null);
-            result = true;
-        } catch (NamingException exception) {
-            // no-op
-        } finally {
-            if (null != ldapContext) {
-                try {
-                    ldapContext.close();
-                } catch (NamingException ex) {
-                    // no-op
-                }
-            }
+            BindResult bindResult = connectionPool.bindAndRevertAuthentication(userDN, password);
+            return bindResult.getResultCode()
+                .intValue() == 0;
+        } catch (LDAPException e) {
+            LOGGER.error("Unexpected error upon authentication", e);
+            return false;
         }
-        return result;
     }
 }
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyLDAPUsersDAO.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyLDAPUsersDAO.java
index 678a96a..fb450d0 100644
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyLDAPUsersDAO.java
+++ b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyLDAPUsersDAO.java
@@ -19,26 +19,18 @@
 
 package org.apache.james.user.ldap;
 
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.Properties;
 import java.util.Set;
 
+import javax.annotation.PreDestroy;
 import javax.inject.Inject;
-import javax.naming.Context;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-import javax.naming.ldap.InitialLdapContext;
-import javax.naming.ldap.LdapContext;
+import javax.net.SocketFactory;
 
 import org.apache.commons.configuration2.HierarchicalConfiguration;
 import org.apache.commons.configuration2.ex.ConfigurationException;
@@ -49,39 +41,26 @@ import org.apache.james.core.Username;
 import org.apache.james.lifecycle.api.Configurable;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.user.api.model.User;
-import org.apache.james.user.ldap.api.LdapConstants;
-import org.apache.james.user.ldap.retry.DoublingRetrySchedule;
-import org.apache.james.user.ldap.retry.api.RetrySchedule;
-import org.apache.james.user.ldap.retry.naming.ldap.RetryingLdapContext;
 import org.apache.james.user.lib.UsersDAO;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.github.fge.lambdas.Throwing;
 import com.github.steveash.guavate.Guavate;
-import com.google.common.base.Strings;
+import com.unboundid.ldap.sdk.LDAPConnection;
+import com.unboundid.ldap.sdk.LDAPConnectionOptions;
+import com.unboundid.ldap.sdk.LDAPConnectionPool;
+import com.unboundid.ldap.sdk.LDAPException;
+import com.unboundid.ldap.sdk.SearchResult;
+import com.unboundid.ldap.sdk.SearchResultEntry;
+import com.unboundid.ldap.sdk.SearchScope;
 
 public class ReadOnlyLDAPUsersDAO implements UsersDAO, Configurable {
     private static final Logger LOGGER = LoggerFactory.getLogger(ReadOnlyLDAPUsersDAO.class);
 
-    // The name of the factory class which creates the initial context
-    // for the LDAP service provider
-    private static final String INITIAL_CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
-
-    private static final String PROPERTY_NAME_CONNECTION_POOL = "com.sun.jndi.ldap.connect.pool";
-    private static final String PROPERTY_NAME_CONNECT_TIMEOUT = "com.sun.jndi.ldap.connect.timeout";
-    private static final String PROPERTY_NAME_READ_TIMEOUT = "com.sun.jndi.ldap.read.timeout";
-
-    /**
-     * The context for the LDAP server. This is the connection that is built
-     * from the configuration attributes &quot;ldapHost&quot;,
-     * &quot;principal&quot; and &quot;credentials&quot;.
-     */
-    private LdapContext ldapContext;
-    // The schedule for retry attempts
-    private RetrySchedule schedule = null;
-
     private LdapRepositoryConfiguration ldapConfiguration;
+    private String filterTemplate;
+    private LDAPConnectionPool ldapConnectionPool;
 
     @Inject
     public ReadOnlyLDAPUsersDAO() {
@@ -91,8 +70,6 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, Configurable {
     /**
      * Extracts the parameters required by the repository instance from the
      * James server configuration data. The fields extracted include
-     * {@link LdapRepositoryConfiguration#ldapHost}, {@link LdapRepositoryConfiguration#userIdAttribute}, {@link LdapRepositoryConfiguration#userBase},
-     * {@link LdapRepositoryConfiguration#principal}, {@link LdapRepositoryConfiguration#credentials} and {@link LdapRepositoryConfiguration#restriction}.
      *
      * @param configuration
      *            An encapsulation of the James server configuration data.
@@ -104,11 +81,6 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, Configurable {
 
     public void configure(LdapRepositoryConfiguration configuration) {
         ldapConfiguration = configuration;
-
-        schedule = new DoublingRetrySchedule(
-            configuration.getRetryStartInterval(),
-            configuration.getRetryMaxInterval(),
-            configuration.getScale());
     }
 
     /**
@@ -120,63 +92,34 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, Configurable {
      *             specified LDAP host.
      */
     public void init() throws Exception {
+
         if (LOGGER.isDebugEnabled()) {
             LOGGER.debug(this.getClass().getName() + ".init()" + '\n' + "LDAP host: " + ldapConfiguration.getLdapHost()
                 + '\n' + "User baseDN: " + ldapConfiguration.getUserBase() + '\n' + "userIdAttribute: "
                 + ldapConfiguration.getUserIdAttribute() + '\n' + "Group restriction: " + ldapConfiguration.getRestriction()
-                + '\n' + "UseConnectionPool: " + ldapConfiguration.useConnectionPool() + '\n' + "connectionTimeout: "
+                + '\n' + "connectionTimeout: "
                 + ldapConfiguration.getConnectionTimeout() + '\n' + "readTimeout: " + ldapConfiguration.getReadTimeout()
-                + '\n' + "retrySchedule: " + schedule + '\n' + "maxRetries: " + ldapConfiguration.getMaxRetries() + '\n');
+                + '\n' + "maxRetries: " + ldapConfiguration.getMaxRetries() + '\n');
         }
-        // Setup the initial LDAP context
-        updateLdapContext();
-    }
-
-    protected void updateLdapContext() throws NamingException {
-        ldapContext = computeLdapContext();
-    }
+        filterTemplate = "(&({0}={1})(objectClass={2})" + StringUtils.defaultString(ldapConfiguration.getFilter(), "") + ")";
 
-    /**
-     * Answers a new LDAP/JNDI context using the specified user credentials.
-     *
-     * @return an LDAP directory context
-     * @throws NamingException
-     *             Propagated from underlying LDAP communication API.
-     */
-    protected LdapContext computeLdapContext() throws NamingException {
-        return new RetryingLdapContext(schedule, ldapConfiguration.getMaxRetries()) {
+        LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions();
+        connectionOptions.setConnectTimeoutMillis(ldapConfiguration.getConnectionTimeout());
+        connectionOptions.setResponseTimeoutMillis(ldapConfiguration.getReadTimeout());
 
-            @Override
-            public Context newDelegate() throws NamingException {
-                return new InitialLdapContext(getContextEnvironment(), null);
-            }
-        };
+        URI uri = new URI(ldapConfiguration.getLdapHost());
+        SocketFactory socketFactory = null;
+        LDAPConnection ldapConnection = new LDAPConnection(socketFactory, connectionOptions, uri.getHost(), uri.getPort(), ldapConfiguration.getPrincipal(), ldapConfiguration.getCredentials());
+        ldapConnectionPool = new LDAPConnectionPool(ldapConnection, 4);
+        // TODO implement retries
     }
 
-    protected Properties getContextEnvironment() {
-        Properties props = new Properties();
-        props.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
-        props.put(Context.PROVIDER_URL, Optional.ofNullable(ldapConfiguration.getLdapHost())
-            .orElse(""));
-        if (Strings.isNullOrEmpty(ldapConfiguration.getCredentials())) {
-            props.put(Context.SECURITY_AUTHENTICATION, LdapConstants.SECURITY_AUTHENTICATION_NONE);
-        } else {
-            props.put(Context.SECURITY_AUTHENTICATION, LdapConstants.SECURITY_AUTHENTICATION_SIMPLE);
-            props.put(Context.SECURITY_PRINCIPAL, Optional.ofNullable(ldapConfiguration.getPrincipal())
-                .orElse(""));
-            props.put(Context.SECURITY_CREDENTIALS, ldapConfiguration.getCredentials());
-        }
-        // The following properties are specific to com.sun.jndi.ldap.LdapCtxFactory
-        props.put(PROPERTY_NAME_CONNECTION_POOL, String.valueOf(ldapConfiguration.useConnectionPool()));
-        if (ldapConfiguration.getConnectionTimeout() > -1) {
-            props.put(PROPERTY_NAME_CONNECT_TIMEOUT, String.valueOf(ldapConfiguration.getConnectionTimeout()));
-        }
-        if (ldapConfiguration.getReadTimeout() > -1) {
-            props.put(PROPERTY_NAME_READ_TIMEOUT, Integer.toString(ldapConfiguration.getReadTimeout()));
-        }
-        return props;
+    @PreDestroy
+    void dispose() {
+        ldapConnectionPool.close();
     }
 
+
     /**
      * Indicates if the user with the specified DN can be found in the group
      * membership map&#45;as encapsulated by the specified parameter map.
@@ -209,29 +152,20 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, Configurable {
         return result;
     }
 
-    /**
-     * Gets all the user entities taken from the LDAP server, as taken from the
-     * search-context given by the value of the attribute {@link LdapRepositoryConfiguration#userBase}.
-     *
-     * @return A set containing all the relevant users found in the LDAP
-     *         directory.
-     * @throws NamingException
-     *             Propagated from the LDAP communication layer.
-     */
-    private Set<String> getAllUsersFromLDAP() throws NamingException {
-        Set<String> result = new HashSet<>();
-
-        SearchControls sc = new SearchControls();
-        sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
-        sc.setReturningAttributes(new String[] { "distinguishedName" });
-        NamingEnumeration<SearchResult> sr = ldapContext.search(ldapConfiguration.getUserBase(), "(objectClass="
-                + ldapConfiguration.getUserObjectClass() + ")", sc);
-        while (sr.hasMore()) {
-            SearchResult r = sr.next();
-            result.add(r.getNameInNamespace());
-        }
+    private Set<String> getAllUsersFromLDAP() throws LDAPException {
+        LDAPConnection connection = ldapConnectionPool.getConnection();
+        try {
+            SearchResult searchResult = connection.search(ldapConfiguration.getUserBase(),
+                SearchScope.SUB,
+                filterTemplate);
 
-        return result;
+            return searchResult.getSearchEntries()
+                .stream()
+                .map(entry -> entry.getObjectClassAttribute().getName())
+                .collect(Guavate.toImmutableSet());
+        } finally {
+            ldapConnectionPool.releaseConnection(connection);
+        }
     }
 
     /**
@@ -245,11 +179,10 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, Configurable {
      *            is to be extracted from the LDAP repository.
      * @return A collection of {@link ReadOnlyLDAPUser}s as taken from the LDAP
      *         server.
-     * @throws NamingException
+     * @throws LDAPException
      *             Propagated from the underlying LDAP communication layer.
      */
-    private Collection<ReadOnlyLDAPUser> buildUserCollection(Collection<String> userDNs)
-            throws NamingException {
+    private Collection<ReadOnlyLDAPUser> buildUserCollection(Collection<String> userDNs) throws LDAPException {
         List<ReadOnlyLDAPUser> results = new ArrayList<>();
 
         for (String userDN : userDNs) {
@@ -260,42 +193,34 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, Configurable {
         return results;
     }
 
-    /**
-     * For a given name, this method makes ldap search in userBase with filter {@link LdapRepositoryConfiguration#userIdAttribute}=name
-     * and objectClass={@link LdapRepositoryConfiguration#userObjectClass} and builds {@link User} based on search result.
-     *
-     * @param name
-     *            The userId which should be value of the field {@link LdapRepositoryConfiguration#userIdAttribute}
-     * @return A {@link ReadOnlyLDAPUser} instance which is initialized with the
-     *         userId of this user and ldap connection information with which
-     *         the user was searched. Return null if such a user was not found.
-     * @throws NamingException
-     *             Propagated by the underlying LDAP communication layer.
-     */
-    private ReadOnlyLDAPUser searchAndBuildUser(Username name) throws NamingException {
-        SearchControls sc = new SearchControls();
-        sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
-        sc.setReturningAttributes(new String[] { ldapConfiguration.getUserIdAttribute() });
-        sc.setCountLimit(1);
-
-        String filterTemplate = "(&({0}={1})(objectClass={2})" +
-            StringUtils.defaultString(ldapConfiguration.getFilter(), "") +
-            ")";
-
-        String sanitizedFilter = FilterEncoder.format(
-            filterTemplate,
-            ldapConfiguration.getUserIdAttribute(),
-            name.asString(),
-            ldapConfiguration.getUserObjectClass());
-
-        NamingEnumeration<SearchResult> sr = ldapContext.search(ldapConfiguration.getUserBase(), sanitizedFilter, sc);
-
-        if (!sr.hasMore()) {
-            return null;
+    private ReadOnlyLDAPUser searchAndBuildUser(Username name) throws LDAPException {
+        LDAPConnection connection = ldapConnectionPool.getConnection();
+        try {
+            String sanitizedFilter = FilterEncoder.format(
+                filterTemplate,
+                ldapConfiguration.getUserIdAttribute(),
+                name.asString(),
+                ldapConfiguration.getUserObjectClass());
+
+            SearchResult searchResult = connection.search(ldapConfiguration.getUserBase(),
+                SearchScope.SUB,
+                sanitizedFilter,
+                ldapConfiguration.getUserIdAttribute());
+
+            return searchResult.getSearchEntries()
+                .stream()
+                .map(entry -> new ReadOnlyLDAPUser(
+                    Username.of(entry.getAttribute(ldapConfiguration.getUserIdAttribute()).getName()),
+                    entry.getDN(),
+                    ldapConnectionPool))
+                .findFirst()
+                .orElse(null);
+        } finally {
+            ldapConnectionPool.releaseConnection(connection);
         }
 
-        SearchResult r = sr.next();
-        Attribute userName = r.getAttributes().get(ldapConfiguration.getUserIdAttribute());
+        /*
+        TODO implement restrictions
 
         if (!ldapConfiguration.getRestriction().isActivated()
             || userInGroupsMembershipList(r.getNameInNamespace(), ldapConfiguration.getRestriction().getGroupMembershipLists(ldapContext))) {
@@ -303,31 +228,20 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, Configurable {
         }
 
         return null;
+        */
     }
 
-    /**
-     * Given a userDN, this method retrieves the user attributes from the LDAP
-     * server, so as to extract the items that are of interest to James.
-     * Specifically it extracts the userId, which is extracted from the LDAP
-     * attribute whose name is given by the value of the field
-     * {@link LdapRepositoryConfiguration#userIdAttribute}.
-     *
-     * @param userDN
-     *            The distinguished-name of the user whose details are to be
-     *            extracted from the LDAP repository.
-     * @return A {@link ReadOnlyLDAPUser} instance which is initialized with the
-     *         userId of this user and ldap connection information with which
-     *         the userDN and attributes were obtained.
-     * @throws NamingException
-     *             Propagated by the underlying LDAP communication layer.
-     */
-    private Optional<ReadOnlyLDAPUser> buildUser(String userDN) throws NamingException {
-      Attributes userAttributes = ldapContext.getAttributes(userDN);
-      Optional<Attribute> userName = Optional.ofNullable(userAttributes.get(ldapConfiguration.getUserIdAttribute()));
-      return userName
-          .map(Throwing.<Attribute, String>function(u -> u.get().toString()).sneakyThrow())
-          .map(Username::of)
-          .map(username -> new ReadOnlyLDAPUser(username, userDN, ldapContext));
+    private Optional<ReadOnlyLDAPUser> buildUser(String userDN) throws LDAPException {
+        LDAPConnection connection = ldapConnectionPool.getConnection();
+        try {
+            SearchResultEntry userAttributes = connection.getEntry(userDN);
+            Optional<String> userName = Optional.ofNullable(userAttributes.getAttributeValue(ldapConfiguration.getUserIdAttribute()));
+            return userName
+                .map(Username::of)
+                .map(username -> new ReadOnlyLDAPUser(username, userDN, ldapConnectionPool));
+        } finally {
+            ldapConnectionPool.releaseConnection(connection);
+        }
     }
 
     @Override
@@ -342,7 +256,7 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, Configurable {
                 .map(Throwing.function(this::buildUser).sneakyThrow())
                 .flatMap(Optional::stream)
                 .count());
-        } catch (NamingException e) {
+        } catch (LDAPException e) {
             throw new UsersRepositoryException("Unable to retrieve user count from ldap", e);
         }
     }
@@ -351,7 +265,7 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, Configurable {
     public Optional<User> getUserByName(Username name) throws UsersRepositoryException {
         try {
           return Optional.ofNullable(searchAndBuildUser(name));
-        } catch (NamingException e) {
+        } catch (LDAPException e) {
             throw new UsersRepositoryException("Unable to retrieve user from ldap", e);
         }
     }
@@ -362,19 +276,22 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, Configurable {
             return buildUserCollection(getValidUsers())
                 .stream()
                 .map(ReadOnlyLDAPUser::getUserName)
-                .collect(Guavate.toImmutableList())
                 .iterator();
-        } catch (NamingException namingException) {
+        } catch (LDAPException namingException) {
             throw new UsersRepositoryException(
                     "Unable to retrieve users list from LDAP due to unknown naming error.",
                     namingException);
         }
     }
 
-    private Collection<String> getValidUsers() throws NamingException {
-        Set<String> userDNs = getAllUsersFromLDAP();
-        Collection<String> validUserDNs;
+    private Collection<String> getValidUsers() throws LDAPException {
+        return getAllUsersFromLDAP();
 
+        /*
+        TODO Implement restrictions
+         */
+        /*
+        Collection<String> validUserDNs;
         if (ldapConfiguration.getRestriction().isActivated()) {
             Map<String, Collection<String>> groupMembershipList = ldapConfiguration.getRestriction()
                     .getGroupMembershipLists(ldapContext);
@@ -392,6 +309,7 @@ public class ReadOnlyLDAPUsersDAO implements UsersDAO, Configurable {
             validUserDNs = userDNs;
         }
         return validUserDNs;
+         */
     }
 
     @Override
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/api/LdapConstants.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/api/LdapConstants.java
deleted file mode 100644
index 1227bca..0000000
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/api/LdapConstants.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-
-package org.apache.james.user.ldap.api;
-
-/**
- * <code>LdapConstants</code>
- */
-public interface LdapConstants {
-
-    // The authentication mechanisms for the provider to use
-    String SECURITY_AUTHENTICATION_NONE = "none";
-    String SECURITY_AUTHENTICATION_SIMPLE = "simple";
-
-}
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/DoublingRetrySchedule.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/DoublingRetrySchedule.java
deleted file mode 100644
index f9e435e..0000000
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/DoublingRetrySchedule.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-
-package org.apache.james.user.ldap.retry;
-
-import org.apache.james.user.ldap.retry.api.RetrySchedule;
-
-
-/**
- * <code>DoublingRetrySchedule</code> is an implementation of <code>RetrySchedule</code> that
- * returns the lesser of an interval that is double the proceeding interval and the maximum interval.
- * 
- * <p>When the initial interval is 0, the next interval is 1.
- * 
- * <p>A multiplier can be specified to scale the results.
- */
-/**
- * <code>DoublingRetrySchedule</code>
- */
-public class DoublingRetrySchedule implements RetrySchedule {
-    
-    private long startInterval = 0;
-    private long maxInterval = 0;
-    private long multiplier = 1;
-
-    /**
-     * Creates a new instance of DoublingRetrySchedule.
-     *
-     */
-    private DoublingRetrySchedule() {
-    }
-    
-    /**
-     * Creates a new instance of DoublingRetrySchedule.
-     *
-     * @param startInterval
-     *      The interval for an index of 0
-     * @param maxInterval
-     *      The maximum interval for any index
-     */
-    public DoublingRetrySchedule(long startInterval, long maxInterval) {
-        this(startInterval, maxInterval, 1);
-    }
-    
-    /**
-     * Creates a new instance of DoublingRetrySchedule.
-     *
-     * @param startInterval
-     *      The interval for an index of 0
-     * @param maxInterval
-     *      The maximum interval for any index
-     * @param multiplier
-     *      The multiplier to apply to the result
-     */
-    public DoublingRetrySchedule(long startInterval, long maxInterval, int multiplier) {
-        this();
-        this.startInterval = Math.max(0, startInterval);
-        this.maxInterval = Math.max(0, maxInterval);
-        this.multiplier = Math.max(1, multiplier);
-    }
-
-    @Override
-    public long getInterval(int index) {
-        if (startInterval > 0) {
-            return getInterval(index, startInterval);
-        }
-        return index == 0 ? 0 : getInterval(index - 1, 1);
-    }
-    
-    private long getInterval(int index, long startInterval) {
-        return multiplier * Math.min((long) (startInterval * Math.pow(2, index)), maxInterval);
-    }    
-
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append("DoublingRetrySchedule [startInterval=").append(startInterval).append(
-                ", maxInterval=").append(maxInterval).append(", multiplier=").append(multiplier).append("]");
-        return builder.toString();
-    }
-
-}
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/ExceptionRetryHandler.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/ExceptionRetryHandler.java
deleted file mode 100644
index 218048b..0000000
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/ExceptionRetryHandler.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-
-package org.apache.james.user.ldap.retry;
-
-import org.apache.james.user.ldap.retry.api.ExceptionRetryingProxy;
-import org.apache.james.user.ldap.retry.api.RetryHandler;
-import org.apache.james.user.ldap.retry.api.RetrySchedule;
-
-/**
- * Abstract class <code>ExceptionRetryHandler</code> retries the behaviour defined in abstract method 
- * <code>operation()</code> implemented in a concrete subclass when nominated subclasses of <code>Exception</code>
- * are thrown. The intervals between retries are defined by a <code>RetrySchedule</code>.
- * <p>
- * Concrete subclasses are proxies that forward work via the <code>operation()</code> to a delegate
- * instance for which retry behaviour is required. Both the proxy and the delegate implement the
- * same interfaces. 
- * <p>
- * The method stubs required to perform the proxy call via <code>operation()</code> may be generated by many means,
- * including explicit code, a <code>DynamicProxy</code> and compile time aspect injection.
- *
- * @see org.apache.james.user.ldap.retry.naming.RetryingContext
- */
-public abstract class ExceptionRetryHandler implements RetryHandler {
-
-    private Class<?>[] exceptionClasses = null;
-    
-    private ExceptionRetryingProxy proxy = null;
-    private RetrySchedule schedule;
-    private int maxRetries = 0;
-
-        /**
-         * Creates a new instance of ExceptionRetryHandler.
-         *
-         */
-        private ExceptionRetryHandler() {
-            super();
-        }
-
-
-        /**
-         * Creates a new instance of ExceptionRetryHandler.
-         *
-         * @param exceptionClasses
-         * @param proxy
-         * @param maxRetries
-         */
-        public ExceptionRetryHandler(Class<?>[] exceptionClasses, ExceptionRetryingProxy proxy, RetrySchedule schedule, int maxRetries) {
-            this();
-            this.exceptionClasses = exceptionClasses;
-            this.proxy = proxy;
-            this.schedule = schedule;
-            this.maxRetries = maxRetries;
-        }
-
-        @Override
-        public Object perform() throws Exception {
-            boolean success = false;
-            Object result = null;
-            int retryCount = 0;
-            while (!success) {
-                try {
-                    if (retryCount > 0) {
-                        proxy.resetDelegate();
-                    }
-                    result = operation();
-                    success = true;
-
-                } catch (Exception ex) {
-                    if (retryCount >= maxRetries || !isRetryable(ex)) {
-                        throw ex;
-                    }
-                    postFailure(ex, retryCount);
-                    try {
-                        Thread.sleep(getRetryInterval(retryCount));
-                    } catch (InterruptedException ex1) {
-                        // no-op
-                    }
-                    retryCount = maxRetries < 0 ? maxRetries
-                            : retryCount + 1;
-                }
-            }
-            return result;
-        }
-        
-        /**
-         * @param ex
-         * The <code>Throwable</code> to test
-         * 
-         * @return true if the array of exception classes contains <strong>ex</strong>
-         */
-        private boolean isRetryable(Throwable ex) {
-            boolean isRetryable = false;
-            for (int i = 0; !isRetryable && i < exceptionClasses.length; i++) {
-                isRetryable = exceptionClasses[i].isInstance(ex);
-            }
-            return isRetryable;
-        }
-
-        @Override
-        public void postFailure(Exception ex, int retryCount) {
-            // no-op
-        }        
-
-        @Override
-        public abstract Object operation() throws Exception;
-        
-        /**
-         * @return the retryInterval
-         */
-        public long getRetryInterval(int retryCount) {
-            return schedule.getInterval(retryCount);
-        }
-}
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/api/ExceptionRetryingProxy.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/api/ExceptionRetryingProxy.java
deleted file mode 100644
index fb41fe9..0000000
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/api/ExceptionRetryingProxy.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-
-package org.apache.james.user.ldap.retry.api;
-
-
-/**
- * <code>ExceptionRetryingProxy</code> defines the behaviour for a
- * proxy that can retry <codeException</code> and its subclasses.
- */
-public interface ExceptionRetryingProxy {
-    /**
-     * @return a new instance that the proxy delegates to
-     * @throws Exception
-     */
-    Object newDelegate() throws Exception;
-    
-    /**
-     * @return the current instance of the proxy delegate
-     * @throws Exception
-     */
-    Object getDelegate();
-    
-    /**
-     * Resets the delegate instance to a state from which it can perform the 
-     * operations delegated to it.
-     *
-     * @throws Exception
-     */
-    void resetDelegate() throws Exception;
-
-}
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/api/RetryHandler.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/api/RetryHandler.java
deleted file mode 100644
index 77f7e56..0000000
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/api/RetryHandler.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-
-package org.apache.james.user.ldap.retry.api;
-
-
-/**
- * <code>RetryHandler</code>
- */
-public interface RetryHandler {
-
-    /**
-     * @return the result of invoking an operation
-     * @throws Exception
-     */
-    Object perform() throws Exception;
-
-    /**
-     * A hook invoked each time an operation fails if a retry is scheduled
-     *
-     * @param ex
-     *      The <code>Exception</code> thrown when the operation was invoked
-     * @param retryCount
-     *      The number of times  
-     */
-    void postFailure(Exception ex, int retryCount);
-
-    /**
-     * Encapsulates desired behaviour
-     * @return The result of performing the behaviour
-     * @throws Exception
-     */
-    Object operation() throws Exception;
-
-}
\ No newline at end of file
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/api/RetrySchedule.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/api/RetrySchedule.java
deleted file mode 100644
index 6607925..0000000
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/api/RetrySchedule.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-
-package org.apache.james.user.ldap.retry.api;
-
-/**
- * <code>RetrySchedule</code>
- */
-public interface RetrySchedule {
-    /**
-     * Returns the interval time in milliseconds at the specified zero based index.
-     *
-     * @param index
-     * @return
-     */
-    long getInterval(int index);
-
-}
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/LoggingRetryHandler.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/LoggingRetryHandler.java
deleted file mode 100644
index e9af6f4..0000000
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/LoggingRetryHandler.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-
-package org.apache.james.user.ldap.retry.naming;
-
-import javax.naming.NamingException;
-
-import org.apache.james.user.ldap.retry.api.ExceptionRetryingProxy;
-import org.apache.james.user.ldap.retry.api.RetrySchedule;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Abstract class <code>LoggingRetryHandler</code> implements logging of failures 
- */
-public abstract class LoggingRetryHandler extends NamingExceptionRetryHandler {
-    private static final Logger LOGGER = LoggerFactory.getLogger(LoggingRetryHandler.class);
-
-    /**
-     * Creates a new instance of LoggingRetryHandler.
-     *
-     * @param exceptionClasses
-     * @param proxy
-     * @param maxRetries
-     */
-    public LoggingRetryHandler(Class<?>[] exceptionClasses, ExceptionRetryingProxy proxy,
-                               RetrySchedule schedule, int maxRetries) {
-        super(exceptionClasses, proxy, schedule, maxRetries);
-    }
-
-    @Override
-    public void postFailure(NamingException ex, int retryCount) {
-        super.postFailure(ex, retryCount);
-        LOGGER.info("Retry failure. Retrying in {} seconds", getRetryInterval(retryCount) / 1000, ex);
-    }
-
-}
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/NamingExceptionRetryHandler.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/NamingExceptionRetryHandler.java
deleted file mode 100644
index 368b5d2..0000000
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/NamingExceptionRetryHandler.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-
-package org.apache.james.user.ldap.retry.naming;
-
-import javax.naming.NamingException;
-
-import org.apache.james.user.ldap.retry.ExceptionRetryHandler;
-import org.apache.james.user.ldap.retry.api.ExceptionRetryingProxy;
-import org.apache.james.user.ldap.retry.api.RetrySchedule;
-
-/**
- * Abstract class <code>NamingExceptionRetryHandler</code> narrows the set of Exceptions throwable 
- * by <code>perform</code> to <code>NamingException</code> and its subclasses.
- * <p><code>RuntimeException</code>s are <strong>not</strong> retried.
- * 
- * @see org.apache.james.user.ldap.retry.ExceptionRetryHandler
- * 
- */
-public abstract class NamingExceptionRetryHandler extends ExceptionRetryHandler {
-
-    /**
-     * Creates a new instance of NamingExceptionRetryHandler.
-     *
-     * @param exceptionClasses
-     * @param proxy
-     * @param schedule
-     * @param maxRetries
-     */
-    public NamingExceptionRetryHandler(Class<?>[] exceptionClasses, ExceptionRetryingProxy proxy,
-            RetrySchedule schedule, int maxRetries) {
-        super(exceptionClasses, proxy, schedule, maxRetries);
-    }
-
-    @Override
-    public Object perform() throws NamingException {
-        try {
-            return super.perform();
-        } catch (RuntimeException ex) {
-            throw ex;
-        } catch (Exception ex) {
-            // Should only ever be a NamingException
-            throw ((NamingException) ex);
-        }
-    }
-
-    @Override
-    public void postFailure(Exception ex, int retryCount) {
-        postFailure(((NamingException) ex), retryCount);        
-    }
-
-    public void postFailure(NamingException ex, int retryCount) {
-        // no-op
-    }
-}
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/RetryingContext.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/RetryingContext.java
deleted file mode 100644
index 65bbd1a..0000000
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/RetryingContext.java
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-
-package org.apache.james.user.ldap.retry.naming;
-
-import java.util.Hashtable;
-
-import javax.naming.Binding;
-import javax.naming.CommunicationException;
-import javax.naming.Context;
-import javax.naming.Name;
-import javax.naming.NameClassPair;
-import javax.naming.NameParser;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.NoInitialContextException;
-import javax.naming.ServiceUnavailableException;
-
-import org.apache.james.user.ldap.retry.ExceptionRetryHandler;
-import org.apache.james.user.ldap.retry.api.ExceptionRetryingProxy;
-import org.apache.james.user.ldap.retry.api.RetrySchedule;
-
-/**
- * <code>RetryingContext</code> retries the methods defined by <code>javax.naming.Context</code>
- * according to the specified schedule. 
- * 
- * @see ExceptionRetryHandler
- * @see org.apache.james.user.ldap.retry.api.ExceptionRetryingProxy
- * @see javax.naming.Context
- */
-public abstract class RetryingContext implements Context, ExceptionRetryingProxy {
-
-    public static final Class<?>[] DEFAULT_EXCEPTION_CLASSES = new Class<?>[] {
-            CommunicationException.class,
-            ServiceUnavailableException.class,
-            NoInitialContextException.class };
-
-    private Context delegate = null;
-    private RetrySchedule schedule = null;
-    private int maxRetries = 0;
-
-    /**
-     * Creates a new instance of RetryingContext.
-     * 
-     * @throws NamingException
-     * 
-     */
-    private RetryingContext() {
-        super();
-    }
-    
-    /**
-     * Creates a new instance of RetryingContext using the default exception
-     * classes thrown when an external interruption to services on which we
-     * depend occurs.
-     * 
-     * @param schedule
-     * @param maxRetries
-     * @throws NamingException
-     */
-    public RetryingContext(RetrySchedule schedule, int maxRetries)
-            throws NamingException {
-        this(DEFAULT_EXCEPTION_CLASSES, schedule, maxRetries);
-    }
-
-    /**
-     * Creates a new instance of RetryingContext.
-     *
-     * @param exceptionClasses
-     * @param schedule
-     * @param maxRetries
-     * @throws NamingException
-     */
-    public RetryingContext(Class<?>[] exceptionClasses, RetrySchedule schedule, int maxRetries)
-            throws NamingException {
-        this();
-        this.schedule = schedule;
-        this.maxRetries = maxRetries;
-        this.delegate = (Context) new LoggingRetryHandler(exceptionClasses, this,
-                this.schedule, this.maxRetries) {
-
-            @Override
-            public Object operation() throws Exception {
-                return newDelegate();
-            }
-        }.perform();
-    }
-
-    @Override
-    public Object addToEnvironment(final String propName, final Object propVal)
-            throws NamingException {
-        return new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().addToEnvironment(propName, propVal);
-            }
-        }.perform();
-    }
-
-    @Override
-    public void bind(final Name name, final Object obj) throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                getDelegate().bind(name, obj);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public void bind(final String name, final Object obj) throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                getDelegate().bind(name, obj);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public void close() throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                getDelegate().close();
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public Name composeName(final Name name, final Name prefix) throws NamingException {
-        return (Name) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().composeName(name, prefix);
-            }
-        }.perform();
-    }
-
-    @Override
-    public String composeName(final String name, final String prefix) throws NamingException {
-        return (String) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().composeName(name, prefix);
-            }
-        }.perform();
-    }
-
-    @Override
-    public Context createSubcontext(final Name name) throws NamingException {
-        final Context context = getDelegate();
-        return new RetryingContext(getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Context newDelegate() throws NamingException {
-                return context.createSubcontext(name);
-            }
-        };
-    }
-
-    @Override
-    public Context createSubcontext(final String name) throws NamingException {
-        final Context context = getDelegate();
-        return new RetryingContext(getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Context newDelegate() throws NamingException {
-                return context.createSubcontext(name);
-            }
-        };
-    }
-
-    @Override
-    public void destroySubcontext(final Name name) throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                getDelegate().destroySubcontext(name);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public void destroySubcontext(final String name) throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                getDelegate().destroySubcontext(name);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public Hashtable<?, ?> getEnvironment() throws NamingException {
-        return (Hashtable<?, ?>) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
-                schedule, maxRetries) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().getEnvironment();
-            }
-        }.perform();
-    }
-
-    @Override
-    public String getNameInNamespace() throws NamingException {
-        return (String) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().getNameInNamespace();
-            }
-        }.perform();
-    }
-
-    @Override
-    public NameParser getNameParser(final Name name) throws NamingException {
-        return (NameParser) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().getNameParser(name);
-            }
-        }.perform();
-    }
-
-    @Override
-    public NameParser getNameParser(final String name) throws NamingException {
-        return (NameParser) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().getNameParser(name);
-            }
-        }.perform();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public NamingEnumeration<NameClassPair> list(final Name name) throws NamingException {
-        return (NamingEnumeration<NameClassPair>) new LoggingRetryHandler(
-                DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().list(name);
-            }
-        }.perform();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public NamingEnumeration<NameClassPair> list(final String name) throws NamingException {
-        return (NamingEnumeration<NameClassPair>) new LoggingRetryHandler(
-                DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().list(name);
-            }
-        }.perform();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public NamingEnumeration<Binding> listBindings(final Name name) throws NamingException {
-        return (NamingEnumeration<Binding>) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES,
-                this, schedule, maxRetries) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().listBindings(name);
-            }
-        }.perform();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public NamingEnumeration<Binding> listBindings(final String name) throws NamingException {
-        return (NamingEnumeration<Binding>) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES,
-                this, schedule, maxRetries) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().listBindings(name);
-            }
-        }.perform();
-    }
-
-    @Override
-    public Object lookup(final Name name) throws NamingException {
-        return new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().lookup(name);
-            }
-        }.perform();
-    }
-
-    @Override
-    public Object lookup(final String name) throws NamingException {
-        return new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().lookup(name);
-            }
-        }.perform();
-    }
-
-    @Override
-    public Object lookupLink(final Name name) throws NamingException {
-        return new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().lookupLink(name);
-            }
-        }.perform();
-    }
-
-    @Override
-    public Object lookupLink(final String name) throws NamingException {
-        return new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().lookupLink(name);
-            }
-        }.perform();
-    }
-
-    @Override
-    public void rebind(final Name name, final Object obj) throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                getDelegate().rebind(name, obj);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public void rebind(final String name, final Object obj) throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                getDelegate().rebind(name, obj);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public Object removeFromEnvironment(final String propName) throws NamingException {
-        return new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return getDelegate().removeFromEnvironment(propName);
-            }
-        }.perform();
-    }
-
-    @Override
-    public void rename(final Name oldName, final Name newName) throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                getDelegate().rename(oldName, newName);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public void rename(final String oldName, final String newName) throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                getDelegate().rename(oldName, newName);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public void unbind(final Name name) throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries
-        ) {
-
-            @Override
-            public Object operation() throws NamingException {
-                getDelegate().unbind(name);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public void unbind(final String name) throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, schedule, maxRetries) {
-
-            @Override
-            public Object operation() throws NamingException {
-                getDelegate().unbind(name);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public Context getDelegate() {
-        return delegate;
-    }
-    
-    
-    @Override
-    public void resetDelegate() throws Exception {
-        if (null != delegate) {
-            delegate.close();
-        }
-        delegate = (Context)newDelegate();
-    }
-   
-    /**
-     * @return the schedule
-     */
-    public RetrySchedule getSchedule() {
-        return schedule;
-    }
-    
-    /**
-     * @return the maxRetries
-     */
-    public int getMaxRetries() {
-        return maxRetries;
-    }
-
-}
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/directory/RetryingDirContext.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/directory/RetryingDirContext.java
deleted file mode 100644
index 72c1679..0000000
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/directory/RetryingDirContext.java
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-
-package org.apache.james.user.ldap.retry.naming.directory;
-
-import javax.naming.Context;
-import javax.naming.Name;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.ModificationItem;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-
-import org.apache.james.user.ldap.retry.ExceptionRetryHandler;
-import org.apache.james.user.ldap.retry.api.RetrySchedule;
-import org.apache.james.user.ldap.retry.naming.LoggingRetryHandler;
-import org.apache.james.user.ldap.retry.naming.RetryingContext;
-
-/**
- * <code>RetryingDirContext</code> retries the methods defined by <code>javax.naming.directory.DirContext</code>
- * according to the specified schedule. 
- * 
- * @see ExceptionRetryHandler
- * @see org.apache.james.user.ldap.retry.api.ExceptionRetryingProxy
- * @see javax.naming.directory.DirContext
- */
-public abstract class RetryingDirContext extends RetryingContext implements DirContext {
-
-
-    /**
-     * Creates a new instance of RetryingDirContext.
-     *
-     * @param schedule
-     * @param maxRetries
-     * @throws NamingException
-     */
-    public RetryingDirContext(RetrySchedule schedule, int maxRetries)
-            throws NamingException {
-        super(schedule, maxRetries);
-    }
-
-    @Override
-    public void bind(final Name name, final Object obj, final Attributes attrs)
-            throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                ((DirContext) getDelegate()).bind(name, obj, attrs);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public void bind(final String name, final Object obj, final Attributes attrs)
-            throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                ((DirContext) getDelegate()).bind(name, obj, attrs);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public DirContext createSubcontext(final Name name, final Attributes attrs)
-            throws NamingException {
-        return (DirContext) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
-                getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).createSubcontext(name, attrs);
-            }
-        }.perform();
-    }
-
-    @Override
-    public DirContext createSubcontext(final String name, final Attributes attrs)
-            throws NamingException {
-        return (DirContext) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
-                getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).createSubcontext(name, attrs);
-            }
-        }.perform();
-    }
-
-    @Override
-    public Attributes getAttributes(final Name name) throws NamingException {
-        return (Attributes) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
-                getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).getAttributes(name);
-            }
-        }.perform();
-    }
-
-    @Override
-    public Attributes getAttributes(final String name) throws NamingException {
-        return (Attributes) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
-                getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).getAttributes(name);
-            }
-        }.perform();
-    }
-
-    @Override
-    public Attributes getAttributes(final Name name, final String[] attrIds) throws NamingException {
-        return (Attributes) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
-                getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).getAttributes(name, attrIds);
-            }
-        }.perform();
-    }
-
-    @Override
-    public Attributes getAttributes(final String name, final String[] attrIds)
-            throws NamingException {
-        return (Attributes) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this,
-                getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).getAttributes(name, attrIds);
-            }
-        }.perform();
-    }
-
-    @Override
-    public DirContext getSchema(final Name name) throws NamingException {
-        final Context context = getDelegate();
-        return new RetryingDirContext(getSchedule(), getMaxRetries()) {
-
-            @Override
-            public DirContext newDelegate() throws NamingException {
-                return ((DirContext) context).getSchema(name);
-            }
-        };
-    }
-
-    @Override
-    public DirContext getSchema(final String name) throws NamingException {
-        final Context context = getDelegate();
-        return new RetryingDirContext(getSchedule(), getMaxRetries()) {
-
-            @Override
-            public DirContext newDelegate() throws NamingException {
-                return ((DirContext) context).getSchema(name);
-            }
-        };
-    }
-
-    @Override
-    public DirContext getSchemaClassDefinition(final Name name) throws NamingException {
-        final Context context = getDelegate();
-        return new RetryingDirContext(getSchedule(), getMaxRetries()) {
-
-            @Override
-            public DirContext newDelegate() throws NamingException {
-                return ((DirContext) context).getSchemaClassDefinition(name);
-            }
-        };
-    }
-
-    @Override
-    public DirContext getSchemaClassDefinition(final String name) throws NamingException {
-        final Context context = getDelegate();
-        return new RetryingDirContext(getSchedule(), getMaxRetries()) {
-
-            @Override
-            public DirContext newDelegate() throws NamingException {
-                return ((DirContext) context).getSchemaClassDefinition(name);
-            }
-        };
-    }
-
-    @Override
-    public void modifyAttributes(final Name name, final ModificationItem[] mods)
-            throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                ((DirContext) getDelegate()).modifyAttributes(name, mods);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public void modifyAttributes(final String name, final ModificationItem[] mods)
-            throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                ((DirContext) getDelegate()).modifyAttributes(name, mods);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public void modifyAttributes(final Name name, final int modOp, final Attributes attrs)
-            throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                ((DirContext) getDelegate()).modifyAttributes(name, modOp, attrs);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public void modifyAttributes(final String name, final int modOp, final Attributes attrs)
-            throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                ((DirContext) getDelegate()).modifyAttributes(name, modOp, attrs);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public void rebind(final Name name, final Object obj, final Attributes attrs)
-            throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                ((DirContext) getDelegate()).rebind(name, obj, attrs);
-                return null;
-            }
-        }.perform();
-    }
-
-    @Override
-    public void rebind(final String name, final Object obj, final Attributes attrs)
-            throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                ((DirContext) getDelegate()).rebind(name, obj, attrs);
-                return null;
-            }
-        }.perform();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public NamingEnumeration<SearchResult> search(final Name name,
-            final Attributes matchingAttributes)
-            throws NamingException {
-        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
-                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).search(name, matchingAttributes);
-            }
-        }.perform();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public NamingEnumeration<SearchResult> search(final String name,
-            final Attributes matchingAttributes)
-            throws NamingException {
-        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
-                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).search(name, matchingAttributes);
-            }
-        }.perform();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public NamingEnumeration<SearchResult> search(final Name name,
-            final Attributes matchingAttributes,
-            String[] attributesToReturn) throws NamingException {
-        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
-                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).search(name, matchingAttributes);
-            }
-        }.perform();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public NamingEnumeration<SearchResult> search(final String name,
-            final Attributes matchingAttributes,
-            final String[] attributesToReturn) throws NamingException {
-        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
-                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).search(name, matchingAttributes,
-                        attributesToReturn);
-            }
-        }.perform();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public NamingEnumeration<SearchResult> search(final Name name, final String filter,
-            final SearchControls cons)
-            throws NamingException {
-        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
-                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).search(name, filter, cons);
-            }
-        }.perform();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public NamingEnumeration<SearchResult> search(final String name, final String filter,
-            final SearchControls cons)
-            throws NamingException {
-        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
-                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).search(name, filter, cons);
-            }
-        }.perform();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public NamingEnumeration<SearchResult> search(final Name name, final String filterExpr,
-            final Object[] filterArgs, final SearchControls cons) throws NamingException {
-        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
-                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).search(name, filterExpr, filterArgs, cons);
-            }
-        }.perform();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public NamingEnumeration<SearchResult> search(final String name, final String filterExpr,
-            final Object[] filterArgs, final SearchControls cons) throws NamingException {
-        return (NamingEnumeration<SearchResult>) new LoggingRetryHandler(
-                DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Object operation() throws NamingException {
-                return ((DirContext) getDelegate()).search(name, filterExpr, filterArgs, cons);
-            }
-        }.perform();
-    }
-
-}
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/ldap/RetryingLdapContext.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/ldap/RetryingLdapContext.java
deleted file mode 100644
index 0355c09..0000000
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/retry/naming/ldap/RetryingLdapContext.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-
-package org.apache.james.user.ldap.retry.naming.ldap;
-
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.naming.ldap.Control;
-import javax.naming.ldap.ExtendedRequest;
-import javax.naming.ldap.ExtendedResponse;
-import javax.naming.ldap.LdapContext;
-
-import org.apache.james.user.ldap.retry.ExceptionRetryHandler;
-import org.apache.james.user.ldap.retry.api.RetrySchedule;
-import org.apache.james.user.ldap.retry.naming.LoggingRetryHandler;
-import org.apache.james.user.ldap.retry.naming.directory.RetryingDirContext;
-
-/**
- * <code>RetryingLdapContext</code> retries the methods defined by <code>javax.naming.ldap.LdapContext</code>
- * according to the specified schedule. 
- * 
- * @see ExceptionRetryHandler
- * @see org.apache.james.user.ldap.retry.api.ExceptionRetryingProxy
- * @see javax.naming.ldap.LdapContext
- */
-public abstract class RetryingLdapContext extends RetryingDirContext implements LdapContext {
-   
-    /**
-     * Creates a new instance of RetryingLdapContext.
-     *
-     * @param maxRetries
-     * @throws NamingException
-     */
-    public RetryingLdapContext(RetrySchedule schedule, int maxRetries) throws NamingException {
-        super(schedule, maxRetries);
-    }
-
-    @Override
-    public ExtendedResponse extendedOperation(final ExtendedRequest request) throws NamingException {
-        return (ExtendedResponse) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-                @Override
-                public Object operation() throws NamingException {
-                    return ((LdapContext) getDelegate()).extendedOperation(request);
-                }
-            }.perform();
-    }
-
-    @Override
-    public Control[] getConnectControls() throws NamingException {
-        return (Control[]) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-                @Override
-                public Object operation() throws NamingException {
-                    return ((LdapContext) getDelegate()).getConnectControls();
-                }
-            }.perform();
-    }
-
-    @Override
-    public Control[] getRequestControls() throws NamingException {
-        return (Control[]) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-                @Override
-                public Object operation() throws NamingException {
-                    return ((LdapContext) getDelegate()).getRequestControls();
-                }
-            }.perform();
-    }
-
-    @Override
-    public Control[] getResponseControls() throws NamingException {
-        return (Control[]) new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-                @Override
-                public Object operation() throws NamingException {
-                    return ((LdapContext) getDelegate()).getResponseControls();
-                }
-            }.perform();
-    }
-
-    @Override
-    public LdapContext newInstance(final Control[] requestControls) throws NamingException {
-        final Context context = getDelegate();
-        return new RetryingLdapContext(getSchedule(), getMaxRetries()) {
-
-            @Override
-            public Context newDelegate() throws NamingException {
-                return ((LdapContext) context).newInstance(requestControls);
-            }
-        };
-    }
-
-    @Override
-    public void reconnect(final Control[] connCtls) throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-                @Override
-                public Object operation() throws NamingException {
-                    ((LdapContext) getDelegate()).reconnect(connCtls);
-                    return null;
-                }
-            }.perform();
-    }
-
-    @Override
-    public void setRequestControls(final Control[] requestControls) throws NamingException {
-        new LoggingRetryHandler(DEFAULT_EXCEPTION_CLASSES, this, getSchedule(), getMaxRetries()) {
-                @Override
-                public Object operation() throws NamingException {
-                    ((LdapContext) getDelegate()).setRequestControls(requestControls);
-                    return null;
-                }
-            }.perform();
-    }
-
-}
diff --git a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/retry/DoublingRetryScheduleTest.java b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/retry/DoublingRetryScheduleTest.java
deleted file mode 100644
index 7ec732c..0000000
--- a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/retry/DoublingRetryScheduleTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-package org.apache.james.user.ldap.retry;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.apache.james.user.ldap.retry.api.RetrySchedule;
-import org.junit.jupiter.api.Test;
-
-class DoublingRetryScheduleTest {
-
-    @Test
-    void testDoublingRetrySchedule() {
-        assertThat(RetrySchedule.class.isAssignableFrom(DoublingRetrySchedule.class)).isTrue();
-        assertThat(new DoublingRetrySchedule(0, 0).getInterval(0)).isEqualTo(0);
-        assertThat(new DoublingRetrySchedule(-1, -1).getInterval(0)).isEqualTo(0);
-        assertThat(new DoublingRetrySchedule(-1, 0).getInterval(0)).isEqualTo(0);
-        assertThat(new DoublingRetrySchedule(0, -1).getInterval(0)).isEqualTo(0);
-    }
-
-    @Test
-    void testGetInterval() {
-        assertThat(new DoublingRetrySchedule(0, 8).getInterval(0)).isEqualTo(0);
-        assertThat(new DoublingRetrySchedule(0, 8).getInterval(1)).isEqualTo(1);
-        assertThat(new DoublingRetrySchedule(0, 8).getInterval(2)).isEqualTo(2);
-        assertThat(new DoublingRetrySchedule(0, 8).getInterval(3)).isEqualTo(4);
-        assertThat(new DoublingRetrySchedule(0, 8).getInterval(4)).isEqualTo(8);
-        assertThat(new DoublingRetrySchedule(0, 8).getInterval(5)).isEqualTo(8);
-
-        assertThat(new DoublingRetrySchedule(1, 8).getInterval(0)).isEqualTo(1);
-        assertThat(new DoublingRetrySchedule(1, 8).getInterval(1)).isEqualTo(2);
-        assertThat(new DoublingRetrySchedule(1, 8).getInterval(2)).isEqualTo(4);
-        assertThat(new DoublingRetrySchedule(1, 8).getInterval(3)).isEqualTo(8);
-        assertThat(new DoublingRetrySchedule(1, 8).getInterval(4)).isEqualTo(8);
-
-        assertThat(new DoublingRetrySchedule(3, 12).getInterval(0)).isEqualTo(3);
-        assertThat(new DoublingRetrySchedule(3, 12).getInterval(1)).isEqualTo(6);
-        assertThat(new DoublingRetrySchedule(3, 12).getInterval(2)).isEqualTo(12);
-        assertThat(new DoublingRetrySchedule(3, 12).getInterval(3)).isEqualTo(12);
-
-        assertThat(new DoublingRetrySchedule(0, 8, 1000).getInterval(0)).isEqualTo(0);
-        assertThat(new DoublingRetrySchedule(0, 8, 1000).getInterval(1)).isEqualTo(1000);
-        assertThat(new DoublingRetrySchedule(0, 8, 1000).getInterval(2)).isEqualTo(2000);
-        assertThat(new DoublingRetrySchedule(0, 8, 1000).getInterval(3)).isEqualTo(4000);
-        assertThat(new DoublingRetrySchedule(0, 8, 1000).getInterval(4)).isEqualTo(8000);
-        assertThat(new DoublingRetrySchedule(0, 8, 1000).getInterval(5)).isEqualTo(8000);
-    }
-
-    @Test
-    void testToString() {
-        assertThat(new DoublingRetrySchedule(0, 1).toString())
-            .isEqualTo("DoublingRetrySchedule [startInterval=0, maxInterval=1, multiplier=1]");
-    }
-}
diff --git a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/retry/ExceptionRetryHandlerTest.java b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/retry/ExceptionRetryHandlerTest.java
deleted file mode 100644
index f3d921d..0000000
--- a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/retry/ExceptionRetryHandlerTest.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-package org.apache.james.user.ldap.retry;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.naming.Context;
-
-import org.apache.james.user.ldap.retry.api.ExceptionRetryingProxy;
-import org.apache.james.user.ldap.retry.api.RetryHandler;
-import org.apache.james.user.ldap.retry.api.RetrySchedule;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-class ExceptionRetryHandlerTest {
-    private static class TestRetryingProxy implements ExceptionRetryingProxy {
-
-        @Override
-        public Context getDelegate() {
-            return null;
-        }
-
-        @Override
-        public Context newDelegate() {
-            return null;
-        }
-
-        @Override
-        public void resetDelegate() {
-        }
-    }
-
-    private Class<?>[] exceptionClasses = null;
-    private ExceptionRetryingProxy proxy = null;
-    private RetrySchedule schedule = null;
-
-    @BeforeEach
-    void setUp() {
-        exceptionClasses = new Class<?>[]{Exception.class};
-        proxy = new TestRetryingProxy();
-        schedule = i -> i;
-    }
-
-    @Test
-    void testExceptionRetryHandler() {
-        assertThat(RetryHandler.class.isAssignableFrom(new ExceptionRetryHandler(
-            exceptionClasses, proxy, schedule, 0) {
-
-            @Override
-            public Object operation() {
-                return null;
-            }
-        }.getClass())).isTrue();
-    }
-
-    @Test
-    void testPerform() throws Exception {
-        Object result = new ExceptionRetryHandler(
-            exceptionClasses, proxy, schedule, 0) {
-
-            @Override
-            public Object operation() {
-                return "Hi!";
-            }
-        }.perform();
-        assertThat(result).isEqualTo("Hi!");
-
-        try {
-            new ExceptionRetryHandler(
-                exceptionClasses, proxy, schedule, 0) {
-
-                @Override
-                public Object operation() throws Exception {
-                    throw new Exception();
-                }
-            }.perform();
-        } catch (Exception ex) {
-            // no-op
-        }
-        assertThat(result).isEqualTo("Hi!");
-    }
-
-    @Test
-    void testPostFailure() {
-        final List<Exception> results = new ArrayList<>();
-        RetryHandler handler = new ExceptionRetryHandler(
-            exceptionClasses, proxy, schedule, 7) {
-
-            @Override
-            public void postFailure(Exception ex, int retryCount) {
-                super.postFailure(ex, retryCount);
-                results.add(ex);
-            }
-
-            @Override
-            public Object operation() throws Exception {
-                throw new Exception();
-            }
-        };
-        try {
-            handler.perform();
-        } catch (Exception ex) {
-            // no-op
-        }
-        assertThat(results.size()).isEqualTo(7);
-    }
-
-    @Test
-    void testOperation() throws Exception {
-        RetryHandler handler = new ExceptionRetryHandler(
-            exceptionClasses, proxy, schedule, 0) {
-
-            @Override
-            public Object operation() {
-                return "Hi!";
-            }
-        };
-        assertThat(handler.operation()).isEqualTo("Hi!");
-    }
-
-    @Test
-    void testGetRetryInterval() {
-        ExceptionRetryHandler handler = new ExceptionRetryHandler(
-            exceptionClasses, proxy, schedule, 0) {
-
-            @Override
-            public Object operation() {
-                return null;
-            }
-        };
-        assertThat(handler.getRetryInterval(8)).isEqualTo(8);
-    }
-}
diff --git a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/retry/naming/NamingExceptionRetryHandlerTest.java b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/retry/naming/NamingExceptionRetryHandlerTest.java
deleted file mode 100644
index 59c8fb8..0000000
--- a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/retry/naming/NamingExceptionRetryHandlerTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- *   Licensed to the Apache Software Foundation (ASF) under one
- *   or more contributor license agreements.  See the NOTICE file
- *   distributed with this work for additional information
- *   regarding copyright ownership.  The ASF licenses this file
- *   to you under the Apache License, Version 2.0 (the
- *   "License"); you may not use this file except in compliance
- *   with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *   Unless required by applicable law or agreed to in writing,
- *   software distributed under the License is distributed on an
- *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *   KIND, either express or implied.  See the License for the
- *   specific language governing permissions and limitations
- *   under the License.
- *
- */
-package org.apache.james.user.ldap.retry.naming;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import javax.naming.Context;
-import javax.naming.NamingException;
-
-import org.apache.james.user.ldap.retry.api.ExceptionRetryingProxy;
-import org.apache.james.user.ldap.retry.api.RetryHandler;
-import org.apache.james.user.ldap.retry.api.RetrySchedule;
-import org.junit.jupiter.api.Test;
-
-class NamingExceptionRetryHandlerTest {
-
-    private static class TestRetryingProxy implements ExceptionRetryingProxy {
-        @Override
-        public Context getDelegate() {
-            return null;
-        }
-
-        @Override
-        public Context newDelegate() {
-            return null;
-        }
-
-        @Override
-        public void resetDelegate() {
-        }
-    }
-
-    private static final Class<?>[] exceptionClasses = new Class<?>[]{NamingException.class};
-    private static final ExceptionRetryingProxy proxy = new TestRetryingProxy();
-    private static final RetrySchedule schedule = i -> i;
-
-    @Test
-    void testExceptionRetryHandler() {
-        assertThat(RetryHandler.class.isAssignableFrom(new NamingExceptionRetryHandler(
-            exceptionClasses, proxy, schedule, 0) {
-
-            @Override
-            public Object operation() {
-                return null;
-            }
-        }.getClass())).isTrue();
-    }
-
-    @Test
-    void testPerform() throws NamingException {
-        Object result = new NamingExceptionRetryHandler(
-            exceptionClasses, proxy, schedule, 0) {
-
-            @Override
-            public Object operation() {
-                return "Hi!";
-            }
-        }.perform();
-        assertThat(result).isEqualTo("Hi!");
-
-        try {
-            new NamingExceptionRetryHandler(
-                exceptionClasses, proxy, schedule, 0) {
-
-                @Override
-                public Object operation() throws Exception {
-                    throw new NamingException();
-                }
-            }.perform();
-        } catch (NamingException ex) {
-            // no-op
-        }
-        assertThat(result).isEqualTo("Hi!");
-    }
-}

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org