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

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


The following commit(s) were added to refs/heads/postgresql by this push:
     new 52ebcbc2c4 JAMES-2586 postgres users dao and repository (#1803)
52ebcbc2c4 is described below

commit 52ebcbc2c4b374afd8091d17402eb45ef2b3b141
Author: hungphan227 <[email protected]>
AuthorDate: Thu Nov 23 11:02:46 2023 +0700

    JAMES-2586 postgres users dao and repository (#1803)
---
 .../backends/postgres/utils/PostgresUtils.java     |  20 +-
 .../postgres/mail/dao/PostgresMailboxDAO.java      |  10 +-
 .../org/apache/james/PostgresJamesServerMain.java  |  12 +-
 .../src/main/resources/META-INF/persistence.xml    |   1 -
 ...{JPADataModule.java => PostgresDataModule.java} |   3 +-
 ...ule.java => PostgresUsersRepositoryModule.java} |  37 ++-
 server/data/data-postgres/pom.xml                  |  11 +
 .../org/apache/james/user/jpa/JPAUsersDAO.java     | 267 ---------------------
 .../org/apache/james/user/jpa/model/JPAUser.java   | 193 ---------------
 .../james/user/postgres/PostgresUserModule.java}   |  46 ++--
 .../james/user/postgres/PostgresUsersDAO.java      | 143 +++++++++++
 .../user/postgres/PostgresUsersRepository.java}    |  28 +--
 .../PostgresUsersRepositoryConfiguration.java}     |  57 ++---
 .../rrt/jpa/JPARecipientRewriteTableTest.java      |   5 +-
 .../java/org/apache/james/rrt/jpa/JPAStepdefs.java |   7 +-
 .../apache/james/user/jpa/model/JPAUserTest.java   |  73 ------
 .../PostgresUsersRepositoryTest.java}              |  41 ++--
 17 files changed, 288 insertions(+), 666 deletions(-)

diff --git 
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPADataModule.java
 
b/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresUtils.java
similarity index 70%
copy from 
server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPADataModule.java
copy to 
backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresUtils.java
index ff1b84b449..9f8b075c14 100644
--- 
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPADataModule.java
+++ 
b/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresUtils.java
@@ -16,18 +16,16 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
-package org.apache.james.modules.data;
 
-import org.apache.james.CoreDataModule;
+package org.apache.james.backends.postgres.utils;
 
-import com.google.inject.AbstractModule;
+import java.util.function.Predicate;
 
-public class JPADataModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        install(new CoreDataModule());
-        install(new JPADomainListModule());
-        install(new JPARecipientRewriteTableModule());
-        install(new JPAMailRepositoryModule());
-    }
+import org.jooq.exception.DataAccessException;
+
+public class PostgresUtils {
+    private static final String UNIQUE_CONSTRAINT_VIOLATION_MESSAGE = 
"duplicate key value violates unique constraint";
+
+    public static final Predicate<Throwable> 
UNIQUE_CONSTRAINT_VIOLATION_PREDICATE =
+        throwable -> throwable instanceof DataAccessException && 
throwable.getMessage().contains(UNIQUE_CONSTRAINT_VIOLATION_MESSAGE);
 }
diff --git 
a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxDAO.java
 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxDAO.java
index ab0aec9532..f820a2ce07 100644
--- 
a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxDAO.java
+++ 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxDAO.java
@@ -19,6 +19,7 @@
 
 package org.apache.james.mailbox.postgres.mail.dao;
 
+import static 
org.apache.james.backends.postgres.utils.PostgresUtils.UNIQUE_CONSTRAINT_VIOLATION_PREDICATE;
 import static 
org.apache.james.mailbox.postgres.PostgresMailboxIdFaker.getMailboxId;
 import static 
org.apache.james.mailbox.postgres.mail.PostgresMailboxModule.PostgresMailboxTable.MAILBOX_ACL;
 import static 
org.apache.james.mailbox.postgres.mail.PostgresMailboxModule.PostgresMailboxTable.MAILBOX_HIGHEST_MODSEQ;
@@ -54,7 +55,6 @@ import org.apache.james.mailbox.model.search.MailboxQuery;
 import org.apache.james.mailbox.postgres.PostgresMailboxId;
 import org.apache.james.mailbox.store.MailboxExpressionBackwardCompatibility;
 import org.jooq.Record;
-import org.jooq.exception.DataAccessException;
 import org.jooq.impl.DSL;
 import org.jooq.postgres.extensions.types.Hstore;
 import org.slf4j.Logger;
@@ -69,7 +69,6 @@ import reactor.core.publisher.Mono;
 public class PostgresMailboxDAO {
     private static final Logger LOGGER = 
LoggerFactory.getLogger(PostgresMailboxDAO.class);
     private static final char SQL_WILDCARD_CHAR = '%';
-    private static final String DUPLICATE_VIOLATION_MESSAGE = "duplicate key 
value violates unique constraint";
     private static final Function<MailboxACL, Hstore> 
MAILBOX_ACL_TO_HSTORE_FUNCTION = acl -> Hstore.hstore(acl.getEntries()
         .entrySet()
         .stream()
@@ -105,10 +104,11 @@ public class PostgresMailboxDAO {
     public Mono<Mailbox> create(MailboxPath mailboxPath, UidValidity 
uidValidity) {
         final PostgresMailboxId mailboxId = PostgresMailboxId.generate();
 
-        return postgresExecutor.executeVoid(dslContext -> 
Mono.from(dslContext.insertInto(TABLE_NAME, MAILBOX_ID, MAILBOX_NAME, 
USER_NAME, MAILBOX_NAMESPACE, MAILBOX_UID_VALIDITY)
-                .values(mailboxId.asUuid(), mailboxPath.getName(), 
mailboxPath.getUser().asString(), mailboxPath.getNamespace(), 
uidValidity.asLong())))
+        return postgresExecutor.executeVoid(dslContext ->
+                Mono.from(dslContext.insertInto(TABLE_NAME, MAILBOX_ID, 
MAILBOX_NAME, USER_NAME, MAILBOX_NAMESPACE, MAILBOX_UID_VALIDITY)
+                    .values(mailboxId.asUuid(), mailboxPath.getName(), 
mailboxPath.getUser().asString(), mailboxPath.getNamespace(), 
uidValidity.asLong())))
             .thenReturn(new Mailbox(mailboxPath, uidValidity, mailboxId))
-            .onErrorMap(e -> e instanceof DataAccessException && 
e.getMessage().contains(DUPLICATE_VIOLATION_MESSAGE),
+            .onErrorMap(UNIQUE_CONSTRAINT_VIOLATION_PREDICATE,
                 e -> new MailboxExistsException(mailboxPath.getName()));
     }
 
diff --git 
a/server/apps/postgres-app/src/main/java/org/apache/james/PostgresJamesServerMain.java
 
b/server/apps/postgres-app/src/main/java/org/apache/james/PostgresJamesServerMain.java
index fe536100f7..7c5f47c086 100644
--- 
a/server/apps/postgres-app/src/main/java/org/apache/james/PostgresJamesServerMain.java
+++ 
b/server/apps/postgres-app/src/main/java/org/apache/james/PostgresJamesServerMain.java
@@ -23,8 +23,8 @@ import org.apache.james.data.UsersRepositoryModuleChooser;
 import org.apache.james.modules.MailboxModule;
 import org.apache.james.modules.MailetProcessingModule;
 import org.apache.james.modules.RunArgumentsModule;
-import org.apache.james.modules.data.JPADataModule;
-import org.apache.james.modules.data.JPAUsersRepositoryModule;
+import org.apache.james.modules.data.PostgresDataModule;
+import org.apache.james.modules.data.PostgresUsersRepositoryModule;
 import org.apache.james.modules.data.SieveJPARepositoryModules;
 import org.apache.james.modules.mailbox.DefaultEventModule;
 import org.apache.james.modules.mailbox.JPAMailboxModule;
@@ -82,9 +82,9 @@ public class PostgresJamesServerMain implements 
JamesServerMain {
         new ActiveMQQueueModule(),
         new NaiveDelegationStoreModule(),
         new DefaultProcessorsConfigurationProviderModule(),
-        new JPADataModule(),
         new JPAMailboxModule(),
         new PostgresMailboxModule(),
+        new PostgresDataModule(),
         new MailboxModule(),
         new LuceneSearchMailboxModule(),
         new NoJwtModule(),
@@ -114,8 +114,8 @@ public class PostgresJamesServerMain implements 
JamesServerMain {
 
     static GuiceJamesServer createServer(PostgresJamesConfiguration 
configuration) {
         return GuiceJamesServer.forConfiguration(configuration)
-            .combineWith(POSTGRES_MODULE_AGGREGATE)
-            .combineWith(new UsersRepositoryModuleChooser(new 
JPAUsersRepositoryModule())
-                
.chooseModules(configuration.getUsersRepositoryImplementation()));
+            .combineWith(new UsersRepositoryModuleChooser(new 
PostgresUsersRepositoryModule())
+                
.chooseModules(configuration.getUsersRepositoryImplementation()))
+            .combineWith(POSTGRES_MODULE_AGGREGATE);
     }
 }
diff --git 
a/server/apps/postgres-app/src/main/resources/META-INF/persistence.xml 
b/server/apps/postgres-app/src/main/resources/META-INF/persistence.xml
index d9e49513f3..5d55f9b767 100644
--- a/server/apps/postgres-app/src/main/resources/META-INF/persistence.xml
+++ b/server/apps/postgres-app/src/main/resources/META-INF/persistence.xml
@@ -33,7 +33,6 @@
         <class>org.apache.james.domainlist.jpa.model.JPADomain</class>
         <class>org.apache.james.mailrepository.jpa.model.JPAUrl</class>
         <class>org.apache.james.mailrepository.jpa.model.JPAMail</class>
-        <class>org.apache.james.user.jpa.model.JPAUser</class>
         <class>org.apache.james.rrt.jpa.model.JPARecipientRewrite</class>
         <class>org.apache.james.sieve.jpa.model.JPASieveQuota</class>
         <class>org.apache.james.sieve.jpa.model.JPASieveScript</class>
diff --git 
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPADataModule.java
 
b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataModule.java
similarity index 96%
rename from 
server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPADataModule.java
rename to 
server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataModule.java
index ff1b84b449..125746063b 100644
--- 
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPADataModule.java
+++ 
b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataModule.java
@@ -16,13 +16,14 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
+
 package org.apache.james.modules.data;
 
 import org.apache.james.CoreDataModule;
 
 import com.google.inject.AbstractModule;
 
-public class JPADataModule extends AbstractModule {
+public class PostgresDataModule extends AbstractModule {
     @Override
     protected void configure() {
         install(new CoreDataModule());
diff --git 
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPAUsersRepositoryModule.java
 
b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresUsersRepositoryModule.java
similarity index 52%
copy from 
server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPAUsersRepositoryModule.java
copy to 
server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresUsersRepositoryModule.java
index 5a719244a4..99289c5ce4 100644
--- 
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPAUsersRepositoryModule.java
+++ 
b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresUsersRepositoryModule.java
@@ -16,29 +16,42 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
+
 package org.apache.james.modules.data;
 
+import org.apache.commons.configuration2.ex.ConfigurationException;
+import org.apache.james.backends.postgres.PostgresModule;
 import org.apache.james.server.core.configuration.ConfigurationProvider;
 import org.apache.james.user.api.UsersRepository;
-import org.apache.james.user.jpa.JPAUsersRepository;
-import org.apache.james.utils.InitializationOperation;
-import org.apache.james.utils.InitilizationOperationBuilder;
+import org.apache.james.user.lib.UsersDAO;
+import org.apache.james.user.postgres.PostgresUserModule;
+import org.apache.james.user.postgres.PostgresUsersDAO;
+import org.apache.james.user.postgres.PostgresUsersRepository;
+import org.apache.james.user.postgres.PostgresUsersRepositoryConfiguration;
 
 import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
 import com.google.inject.Scopes;
-import com.google.inject.multibindings.ProvidesIntoSet;
+import com.google.inject.Singleton;
+import com.google.inject.multibindings.Multibinder;
 
-public class JPAUsersRepositoryModule extends AbstractModule {
+public class PostgresUsersRepositoryModule extends AbstractModule {
     @Override
     public void configure() {
-        bind(JPAUsersRepository.class).in(Scopes.SINGLETON);
-        bind(UsersRepository.class).to(JPAUsersRepository.class);
+        bind(PostgresUsersRepository.class).in(Scopes.SINGLETON);
+        bind(UsersRepository.class).to(PostgresUsersRepository.class);
+
+        bind(PostgresUsersDAO.class).in(Scopes.SINGLETON);
+        bind(UsersDAO.class).to(PostgresUsersDAO.class);
+
+        Multibinder<PostgresModule> postgresDataDefinitions = 
Multibinder.newSetBinder(binder(), PostgresModule.class);
+        
postgresDataDefinitions.addBinding().toInstance(PostgresUserModule.MODULE);
     }
 
-    @ProvidesIntoSet
-    InitializationOperation configureJpaUsers(ConfigurationProvider 
configurationProvider, JPAUsersRepository usersRepository) {
-        return InitilizationOperationBuilder
-            .forClass(JPAUsersRepository.class)
-            .init(() -> 
usersRepository.configure(configurationProvider.getConfiguration("usersrepository")));
+    @Provides
+    @Singleton
+    public PostgresUsersRepositoryConfiguration 
provideConfiguration(ConfigurationProvider configurationProvider) throws 
ConfigurationException {
+        return PostgresUsersRepositoryConfiguration.from(
+            configurationProvider.getConfiguration("usersrepository"));
     }
 }
diff --git a/server/data/data-postgres/pom.xml 
b/server/data/data-postgres/pom.xml
index dc021f1075..82e0bec73b 100644
--- a/server/data/data-postgres/pom.xml
+++ b/server/data/data-postgres/pom.xml
@@ -65,6 +65,12 @@
             <artifactId>james-server-dnsservice-test</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-guice-common</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-lifecycle-api</artifactId>
@@ -134,6 +140,11 @@
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>postgresql</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git 
a/server/data/data-postgres/src/main/java/org/apache/james/user/jpa/JPAUsersDAO.java
 
b/server/data/data-postgres/src/main/java/org/apache/james/user/jpa/JPAUsersDAO.java
deleted file mode 100644
index fc12e0eaa0..0000000000
--- 
a/server/data/data-postgres/src/main/java/org/apache/james/user/jpa/JPAUsersDAO.java
+++ /dev/null
@@ -1,267 +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.jpa;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Optional;
-
-import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.EntityTransaction;
-import javax.persistence.NoResultException;
-import javax.persistence.PersistenceException;
-
-import org.apache.commons.configuration2.HierarchicalConfiguration;
-import org.apache.commons.configuration2.tree.ImmutableNode;
-import org.apache.james.backends.jpa.EntityManagerUtils;
-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.jpa.model.JPAUser;
-import org.apache.james.user.lib.UsersDAO;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-
-/**
- * JPA based UserRepository
- */
-public class JPAUsersDAO implements UsersDAO, Configurable {
-    private static final Logger LOGGER = 
LoggerFactory.getLogger(JPAUsersDAO.class);
-
-    private EntityManagerFactory entityManagerFactory;
-    private String algo;
-
-    @Override
-    public void configure(HierarchicalConfiguration<ImmutableNode> config) {
-        algo = config.getString("algorithm", "PBKDF2");
-    }
-
-    /**
-     * Sets entity manager.
-     * 
-     * @param entityManagerFactory
-     *            the entityManager to set
-     */
-    public final void setEntityManagerFactory(EntityManagerFactory 
entityManagerFactory) {
-        this.entityManagerFactory = entityManagerFactory;
-    }
-
-    public void init() {
-        EntityManagerUtils.safelyClose(createEntityManager());
-    }
-
-    /**
-     * Get the user object with the specified user name. Return null if no such
-     * user.
-     * 
-     * @param name
-     *            the name of the user to retrieve
-     * @return the user being retrieved, null if the user doesn't exist
-     * 
-     * @since James 1.2.2
-     */
-    @Override
-    public Optional<User> getUserByName(Username name) throws 
UsersRepositoryException {
-        EntityManager entityManager = 
entityManagerFactory.createEntityManager();
-
-        try {
-            JPAUser singleResult = (JPAUser) entityManager
-                .createNamedQuery("findUserByName")
-                .setParameter("name", name.asString())
-                .getSingleResult();
-            return Optional.of(singleResult);
-        } catch (NoResultException e) {
-            return Optional.empty();
-        } catch (PersistenceException e) {
-            LOGGER.debug("Failed to find user", e);
-            throw new UsersRepositoryException("Unable to search user", e);
-        } finally {
-            EntityManagerUtils.safelyClose(entityManager);
-        }
-    }
-
-    /**
-     * Update the repository with the specified user object. A user object with
-     * this username must already exist.
-     */
-    @Override
-    public void updateUser(User user) throws UsersRepositoryException {
-        Preconditions.checkNotNull(user);
-
-        EntityManager entityManager = 
entityManagerFactory.createEntityManager();
-
-        final EntityTransaction transaction = entityManager.getTransaction();
-        try {
-            if (contains(user.getUserName())) {
-                transaction.begin();
-                entityManager.merge(user);
-                transaction.commit();
-            } else {
-                LOGGER.debug("User not found");
-                throw new UsersRepositoryException("User " + 
user.getUserName() + " not found");
-            }
-        } catch (PersistenceException e) {
-            LOGGER.debug("Failed to update user", e);
-            if (transaction.isActive()) {
-                transaction.rollback();
-            }
-            throw new UsersRepositoryException("Failed to update user " + 
user.getUserName().asString(), e);
-        } finally {
-            EntityManagerUtils.safelyClose(entityManager);
-        }
-    }
-
-    /**
-     * Removes a user from the repository
-     * 
-     * @param name
-     *            the user to remove from the repository
-     */
-    @Override
-    public void removeUser(Username name) throws UsersRepositoryException {
-        EntityManager entityManager = 
entityManagerFactory.createEntityManager();
-
-        final EntityTransaction transaction = entityManager.getTransaction();
-        try {
-            transaction.begin();
-            if 
(entityManager.createNamedQuery("deleteUserByName").setParameter("name", 
name.asString()).executeUpdate() < 1) {
-                transaction.commit();
-                throw new UsersRepositoryException("User " + name.asString() + 
" does not exist");
-            } else {
-                transaction.commit();
-            }
-        } catch (PersistenceException e) {
-            LOGGER.debug("Failed to remove user", e);
-            if (transaction.isActive()) {
-                transaction.rollback();
-            }
-            throw new UsersRepositoryException("Failed to remove user " + 
name.asString(), e);
-        } finally {
-            EntityManagerUtils.safelyClose(entityManager);
-        }
-    }
-
-    /**
-     * Returns whether or not this user is in the repository
-     * 
-     * @param name
-     *            the name to check in the repository
-     * @return whether the user is in the repository
-     */
-    @Override
-    public boolean contains(Username name) throws UsersRepositoryException {
-        EntityManager entityManager = 
entityManagerFactory.createEntityManager();
-
-        try {
-            return (Long) entityManager.createNamedQuery("containsUser")
-                .setParameter("name", name.asString().toLowerCase(Locale.US))
-                .getSingleResult() > 0;
-        } catch (PersistenceException e) {
-            LOGGER.debug("Failed to find user", e);
-            throw new UsersRepositoryException("Failed to find user" + 
name.asString(), e);
-        } finally {
-            EntityManagerUtils.safelyClose(entityManager);
-        }
-    }
-
-    /**
-     * Returns a count of the users in the repository.
-     * 
-     * @return the number of users in the repository
-     */
-    @Override
-    public int countUsers() throws UsersRepositoryException {
-        EntityManager entityManager = 
entityManagerFactory.createEntityManager();
-
-        try {
-            return ((Long) 
entityManager.createNamedQuery("countUsers").getSingleResult()).intValue();
-        } catch (PersistenceException e) {
-            LOGGER.debug("Failed to find user", e);
-            throw new UsersRepositoryException("Failed to count users", e);
-        } finally {
-            EntityManagerUtils.safelyClose(entityManager);
-        }
-    }
-
-    /**
-     * List users in repository.
-     * 
-     * @return Iterator over a collection of Strings, each being one user in 
the
-     *         repository.
-     */
-    @Override
-    @SuppressWarnings("unchecked")
-    public Iterator<Username> list() throws UsersRepositoryException {
-        EntityManager entityManager = 
entityManagerFactory.createEntityManager();
-
-        try {
-            return ((List<String>) 
entityManager.createNamedQuery("listUserNames").getResultList())
-                .stream()
-                .map(Username::of)
-                .collect(ImmutableList.toImmutableList()).iterator();
-
-        } catch (PersistenceException e) {
-            LOGGER.debug("Failed to find user", e);
-            throw new UsersRepositoryException("Failed to list users", e);
-        } finally {
-            EntityManagerUtils.safelyClose(entityManager);
-        }
-    }
-
-    /**
-     * Return a new {@link EntityManager} instance
-     * 
-     * @return manager
-     */
-    private EntityManager createEntityManager() {
-        return entityManagerFactory.createEntityManager();
-    }
-
-    @Override
-    public void addUser(Username username, String password) throws 
UsersRepositoryException {
-        Username lowerCasedUsername = 
Username.of(username.asString().toLowerCase(Locale.US));
-        if (contains(lowerCasedUsername)) {
-            throw new UsersRepositoryException(lowerCasedUsername.asString() + 
" already exists.");
-        }
-        EntityManager entityManager = 
entityManagerFactory.createEntityManager();
-        final EntityTransaction transaction = entityManager.getTransaction();
-        try {
-            transaction.begin();
-            JPAUser user = new JPAUser(lowerCasedUsername.asString(), 
password, algo);
-            entityManager.persist(user);
-            transaction.commit();
-        } catch (PersistenceException e) {
-            LOGGER.debug("Failed to save user", e);
-            if (transaction.isActive()) {
-                transaction.rollback();
-            }
-            throw new UsersRepositoryException("Failed to add user" + 
username.asString(), e);
-        } finally {
-            EntityManagerUtils.safelyClose(entityManager);
-        }
-    }
-
-}
diff --git 
a/server/data/data-postgres/src/main/java/org/apache/james/user/jpa/model/JPAUser.java
 
b/server/data/data-postgres/src/main/java/org/apache/james/user/jpa/model/JPAUser.java
deleted file mode 100644
index 8a5cad22ef..0000000000
--- 
a/server/data/data-postgres/src/main/java/org/apache/james/user/jpa/model/JPAUser.java
+++ /dev/null
@@ -1,193 +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.jpa.model;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Optional;
-import java.util.function.Function;
-
-import javax.persistence.Basic;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.NamedQueries;
-import javax.persistence.NamedQuery;
-import javax.persistence.Table;
-import javax.persistence.Version;
-
-import org.apache.james.core.Username;
-import org.apache.james.user.api.model.User;
-import org.apache.james.user.lib.model.Algorithm;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.hash.HashFunction;
-import com.google.common.hash.Hashing;
-
-@Entity(name = "JamesUser")
-@Table(name = "JAMES_USER")
-@NamedQueries({ 
-    @NamedQuery(name = "findUserByName", query = "SELECT user FROM JamesUser 
user WHERE user.name=:name"),
-    @NamedQuery(name = "deleteUserByName", query = "DELETE FROM JamesUser user 
WHERE user.name=:name"),
-    @NamedQuery(name = "containsUser", query = "SELECT COUNT(user) FROM 
JamesUser user WHERE user.name=:name"), 
-    @NamedQuery(name = "countUsers", query = "SELECT COUNT(user) FROM 
JamesUser user"), 
-    @NamedQuery(name = "listUserNames", query = "SELECT user.name FROM 
JamesUser user") })
-public class JPAUser implements User {
-
-    /**
-     * Hash password.
-     * 
-     * @param password
-     *            not null
-     * @return not null
-     */
-    @VisibleForTesting
-    static String hashPassword(String password, String nullableSalt, String 
nullableAlgorithm) {
-        Algorithm algorithm = 
Algorithm.of(Optional.ofNullable(nullableAlgorithm).orElse("SHA-512"));
-        if (algorithm.isPBKDF2()) {
-            return algorithm.digest(password, nullableSalt);
-        }
-        String credentials = password;
-        if (algorithm.isSalted() && nullableSalt != null) {
-            credentials = nullableSalt + password;
-        }
-        return chooseHashFunction(algorithm.getName()).apply(credentials);
-    }
-
-    interface PasswordHashFunction extends Function<String, String> {}
-
-    private static PasswordHashFunction chooseHashFunction(String algorithm) {
-        switch (algorithm) {
-            case "NONE":
-                return password -> password;
-            default:
-                return password -> 
chooseHashing(algorithm).hashString(password, 
StandardCharsets.UTF_8).toString();
-        }
-    }
-
-    @SuppressWarnings("deprecation")
-    private static HashFunction chooseHashing(String algorithm) {
-        switch (algorithm) {
-            case "MD5":
-                return Hashing.md5();
-            case "SHA-256":
-                return Hashing.sha256();
-            case "SHA-512":
-                return Hashing.sha512();
-            case "SHA-1":
-            case "SHA1":
-                return Hashing.sha1();
-            default:
-                return Hashing.sha512();
-        }
-    }
-
-    /** Prevents concurrent modification */
-    @Version
-    private int version;
-
-    /** Key by user name */
-    @Id
-    @Column(name = "USER_NAME", nullable = false, length = 100)
-    private String name;
-
-    /** Hashed password */
-    @Basic
-    @Column(name = "PASSWORD", nullable = false, length = 128)
-    private String password;
-
-    @Basic
-    @Column(name = "PASSWORD_HASH_ALGORITHM", nullable = false, length = 100)
-    private String alg;
-
-    protected JPAUser() {
-    }
-
-    public JPAUser(String userName, String password, String alg) {
-        super();
-        this.name = userName;
-        this.alg = alg;
-        this.password = hashPassword(password, userName, alg);
-    }
-
-    @Override
-    public Username getUserName() {
-        return Username.of(name);
-    }
-
-    @Override
-    public boolean setPassword(String newPass) {
-        final boolean result;
-        if (newPass == null) {
-            result = false;
-        } else {
-            password = hashPassword(newPass, name, alg);
-            result = true;
-        }
-        return result;
-    }
-
-    @Override
-    public boolean verifyPassword(String pass) {
-        final boolean result;
-        if (pass == null) {
-            result = password == null;
-        } else {
-            result = password != null && password.equals(hashPassword(pass, 
name, alg));
-        }
-
-        return result;
-    }
-
-    @Override
-    public int hashCode() {
-        final int PRIME = 31;
-        int result = 1;
-        result = PRIME * result + ((name == null) ? 0 : name.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final JPAUser other = (JPAUser) obj;
-        if (name == null) {
-            if (other.name != null) {
-                return false;
-            }
-        } else if (!name.equals(other.name)) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return "[User " + name + "]";
-    }
-
-}
diff --git 
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPAUsersRepositoryModule.java
 
b/server/data/data-postgres/src/main/java/org/apache/james/user/postgres/PostgresUserModule.java
similarity index 50%
copy from 
server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPAUsersRepositoryModule.java
copy to 
server/data/data-postgres/src/main/java/org/apache/james/user/postgres/PostgresUserModule.java
index 5a719244a4..6aae9183f8 100644
--- 
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPAUsersRepositoryModule.java
+++ 
b/server/data/data-postgres/src/main/java/org/apache/james/user/postgres/PostgresUserModule.java
@@ -16,29 +16,35 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
-package org.apache.james.modules.data;
 
-import org.apache.james.server.core.configuration.ConfigurationProvider;
-import org.apache.james.user.api.UsersRepository;
-import org.apache.james.user.jpa.JPAUsersRepository;
-import org.apache.james.utils.InitializationOperation;
-import org.apache.james.utils.InitilizationOperationBuilder;
+package org.apache.james.user.postgres;
 
-import com.google.inject.AbstractModule;
-import com.google.inject.Scopes;
-import com.google.inject.multibindings.ProvidesIntoSet;
+import org.apache.james.backends.postgres.PostgresModule;
+import org.apache.james.backends.postgres.PostgresTable;
+import org.jooq.Field;
+import org.jooq.Record;
+import org.jooq.Table;
+import org.jooq.impl.DSL;
+import org.jooq.impl.SQLDataType;
 
-public class JPAUsersRepositoryModule extends AbstractModule {
-    @Override
-    public void configure() {
-        bind(JPAUsersRepository.class).in(Scopes.SINGLETON);
-        bind(UsersRepository.class).to(JPAUsersRepository.class);
-    }
+public interface PostgresUserModule {
+    interface PostgresUserTable {
+        Table<Record> TABLE_NAME = DSL.table("users");
+
+        Field<String> USERNAME = DSL.field("username", 
SQLDataType.VARCHAR(255).notNull());
+        Field<String> HASHED_PASSWORD = DSL.field("hashed_password", 
SQLDataType.VARCHAR.notNull());
+        Field<String> ALGORITHM = DSL.field("algorithm", 
SQLDataType.VARCHAR(100).notNull());
 
-    @ProvidesIntoSet
-    InitializationOperation configureJpaUsers(ConfigurationProvider 
configurationProvider, JPAUsersRepository usersRepository) {
-        return InitilizationOperationBuilder
-            .forClass(JPAUsersRepository.class)
-            .init(() -> 
usersRepository.configure(configurationProvider.getConfiguration("usersrepository")));
+        PostgresTable TABLE = PostgresTable.name(TABLE_NAME.getName())
+            .createTableStep(((dsl, tableName) -> 
dsl.createTableIfNotExists(tableName)
+                .column(USERNAME)
+                .column(HASHED_PASSWORD)
+                .column(ALGORITHM)
+                .constraint(DSL.primaryKey(USERNAME))))
+            .disableRowLevelSecurity();
     }
+
+    PostgresModule MODULE = PostgresModule.builder()
+        .addTable(PostgresUserTable.TABLE)
+        .build();
 }
diff --git 
a/server/data/data-postgres/src/main/java/org/apache/james/user/postgres/PostgresUsersDAO.java
 
b/server/data/data-postgres/src/main/java/org/apache/james/user/postgres/PostgresUsersDAO.java
new file mode 100644
index 0000000000..67c998b09a
--- /dev/null
+++ 
b/server/data/data-postgres/src/main/java/org/apache/james/user/postgres/PostgresUsersDAO.java
@@ -0,0 +1,143 @@
+/****************************************************************
+ * 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.postgres;
+
+import static 
org.apache.james.backends.postgres.utils.PostgresUtils.UNIQUE_CONSTRAINT_VIOLATION_PREDICATE;
+import static 
org.apache.james.user.postgres.PostgresUserModule.PostgresUserTable.ALGORITHM;
+import static 
org.apache.james.user.postgres.PostgresUserModule.PostgresUserTable.HASHED_PASSWORD;
+import static 
org.apache.james.user.postgres.PostgresUserModule.PostgresUserTable.TABLE_NAME;
+import static 
org.apache.james.user.postgres.PostgresUserModule.PostgresUserTable.USERNAME;
+import static org.jooq.impl.DSL.count;
+
+import java.util.Iterator;
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import org.apache.james.backends.postgres.utils.JamesPostgresConnectionFactory;
+import org.apache.james.backends.postgres.utils.PostgresExecutor;
+import org.apache.james.core.Username;
+import org.apache.james.user.api.AlreadyExistInUsersRepositoryException;
+import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.james.user.api.model.User;
+import org.apache.james.user.lib.UsersDAO;
+import org.apache.james.user.lib.model.Algorithm;
+import org.apache.james.user.lib.model.DefaultUser;
+
+import com.google.common.base.Preconditions;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public class PostgresUsersDAO implements UsersDAO {
+    private final PostgresExecutor postgresExecutor;
+    private final Algorithm algorithm;
+    private final Algorithm.HashingMode fallbackHashingMode;
+
+    @Inject
+    public PostgresUsersDAO(JamesPostgresConnectionFactory 
jamesPostgresConnectionFactory,
+                            PostgresUsersRepositoryConfiguration 
postgresUsersRepositoryConfiguration) {
+        this.postgresExecutor = new 
PostgresExecutor(jamesPostgresConnectionFactory.getConnection(Optional.empty()));
+        this.algorithm = 
postgresUsersRepositoryConfiguration.getPreferredAlgorithm();
+        this.fallbackHashingMode = 
postgresUsersRepositoryConfiguration.getFallbackHashingMode();
+    }
+
+    @Override
+    public Optional<? extends User> getUserByName(Username name) {
+        return getUserByNameReactive(name).blockOptional();
+    }
+
+    private Mono<DefaultUser> getUserByNameReactive(Username name) {
+        return postgresExecutor.executeRow(dsl -> 
Mono.from(dsl.selectFrom(TABLE_NAME)
+                .where(USERNAME.eq(name.asString()))))
+            .map(record -> new DefaultUser(name, record.get(HASHED_PASSWORD),
+                Algorithm.of(record.get(ALGORITHM), fallbackHashingMode), 
algorithm));
+    }
+
+    @Override
+    public void updateUser(User user) throws UsersRepositoryException {
+        Preconditions.checkArgument(user instanceof DefaultUser);
+        DefaultUser defaultUser = (DefaultUser) user;
+
+        boolean executed = postgresExecutor.executeRow(dslContext -> 
Mono.from(dslContext.update(TABLE_NAME)
+                .set(HASHED_PASSWORD, defaultUser.getHashedPassword())
+                .set(ALGORITHM, defaultUser.getHashAlgorithm().asString())
+                .where(USERNAME.eq(user.getUserName().asString()))
+                .returning(USERNAME)))
+            .map(record -> record.get(USERNAME))
+            .blockOptional()
+            .isPresent();
+
+        if (!executed) {
+            throw new UsersRepositoryException("Unable to update user");
+        }
+    }
+
+    @Override
+    public void removeUser(Username name) throws UsersRepositoryException {
+        boolean executed = postgresExecutor.executeRow(dslContext -> 
Mono.from(dslContext.deleteFrom(TABLE_NAME)
+                .where(USERNAME.eq(name.asString()))
+                .returning(USERNAME)))
+            .map(record -> record.get(USERNAME))
+            .blockOptional()
+            .isPresent();
+
+        if (!executed) {
+            throw new UsersRepositoryException("Unable to update user");
+        }
+    }
+
+    @Override
+    public boolean contains(Username name) {
+        return getUserByName(name).isPresent();
+    }
+
+    @Override
+    public int countUsers() {
+        return postgresExecutor.executeRow(dsl -> 
Mono.from(dsl.select(count()).from(TABLE_NAME)))
+            .map(record -> record.get(0, Integer.class))
+            .block();
+    }
+
+    @Override
+    public Iterator<Username> list() throws UsersRepositoryException {
+        return listReactive()
+            .toIterable()
+            .iterator();
+    }
+
+    @Override
+    public Flux<Username> listReactive() {
+        return postgresExecutor.executeRows(dslContext -> 
Flux.from(dslContext.selectFrom(TABLE_NAME)))
+            .map(record -> Username.of(record.get(USERNAME)));
+    }
+
+    @Override
+    public void addUser(Username username, String password) {
+        DefaultUser user = new DefaultUser(username, algorithm, algorithm);
+        user.setPassword(password);
+
+        postgresExecutor.executeVoid(dslContext -> 
Mono.from(dslContext.insertInto(TABLE_NAME, USERNAME, HASHED_PASSWORD, 
ALGORITHM)
+                .values(user.getUserName().asString(), 
user.getHashedPassword(), user.getHashAlgorithm().asString())))
+            .onErrorMap(UNIQUE_CONSTRAINT_VIOLATION_PREDICATE,
+                e -> new AlreadyExistInUsersRepositoryException("User with 
username " + username + " already exist!"))
+            .block();
+    }
+}
diff --git 
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPAUsersRepositoryModule.java
 
b/server/data/data-postgres/src/main/java/org/apache/james/user/postgres/PostgresUsersRepository.java
similarity index 53%
rename from 
server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPAUsersRepositoryModule.java
rename to 
server/data/data-postgres/src/main/java/org/apache/james/user/postgres/PostgresUsersRepository.java
index 5a719244a4..610dc90529 100644
--- 
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPAUsersRepositoryModule.java
+++ 
b/server/data/data-postgres/src/main/java/org/apache/james/user/postgres/PostgresUsersRepository.java
@@ -16,29 +16,17 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
-package org.apache.james.modules.data;
 
-import org.apache.james.server.core.configuration.ConfigurationProvider;
-import org.apache.james.user.api.UsersRepository;
-import org.apache.james.user.jpa.JPAUsersRepository;
-import org.apache.james.utils.InitializationOperation;
-import org.apache.james.utils.InitilizationOperationBuilder;
+package org.apache.james.user.postgres;
 
-import com.google.inject.AbstractModule;
-import com.google.inject.Scopes;
-import com.google.inject.multibindings.ProvidesIntoSet;
+import javax.inject.Inject;
 
-public class JPAUsersRepositoryModule extends AbstractModule {
-    @Override
-    public void configure() {
-        bind(JPAUsersRepository.class).in(Scopes.SINGLETON);
-        bind(UsersRepository.class).to(JPAUsersRepository.class);
-    }
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.user.lib.UsersRepositoryImpl;
 
-    @ProvidesIntoSet
-    InitializationOperation configureJpaUsers(ConfigurationProvider 
configurationProvider, JPAUsersRepository usersRepository) {
-        return InitilizationOperationBuilder
-            .forClass(JPAUsersRepository.class)
-            .init(() -> 
usersRepository.configure(configurationProvider.getConfiguration("usersrepository")));
+public class PostgresUsersRepository extends 
UsersRepositoryImpl<PostgresUsersDAO> {
+    @Inject
+    public PostgresUsersRepository(DomainList domainList, PostgresUsersDAO 
usersDAO) {
+        super(domainList, usersDAO);
     }
 }
diff --git 
a/server/data/data-postgres/src/main/java/org/apache/james/user/jpa/JPAUsersRepository.java
 
b/server/data/data-postgres/src/main/java/org/apache/james/user/postgres/PostgresUsersRepositoryConfiguration.java
similarity index 50%
rename from 
server/data/data-postgres/src/main/java/org/apache/james/user/jpa/JPAUsersRepository.java
rename to 
server/data/data-postgres/src/main/java/org/apache/james/user/postgres/PostgresUsersRepositoryConfiguration.java
index b3f9397abe..8e891c185f 100644
--- 
a/server/data/data-postgres/src/main/java/org/apache/james/user/jpa/JPAUsersRepository.java
+++ 
b/server/data/data-postgres/src/main/java/org/apache/james/user/postgres/PostgresUsersRepositoryConfiguration.java
@@ -17,48 +17,41 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.user.jpa;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.PersistenceUnit;
+package org.apache.james.user.postgres;
 
 import org.apache.commons.configuration2.HierarchicalConfiguration;
 import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.commons.configuration2.tree.ImmutableNode;
-import org.apache.james.domainlist.api.DomainList;
-import org.apache.james.user.lib.UsersRepositoryImpl;
+import org.apache.james.user.lib.model.Algorithm;
+import org.apache.james.user.lib.model.Algorithm.HashingMode;
+
+public class PostgresUsersRepositoryConfiguration {
+    public static final String DEFAULT_ALGORITHM = "PBKDF2-SHA512";
+    public static final String DEFAULT_HASHING_MODE = HashingMode.PLAIN.name();
+
+    public static final PostgresUsersRepositoryConfiguration DEFAULT = new 
PostgresUsersRepositoryConfiguration(
+        Algorithm.of(DEFAULT_ALGORITHM), 
HashingMode.parse(DEFAULT_HASHING_MODE)
+    );
+
+    private final Algorithm preferredAlgorithm;
+    private final HashingMode fallbackHashingMode;
 
-/**
- * JPA based UserRepository
- */
-public class JPAUsersRepository extends UsersRepositoryImpl<JPAUsersDAO> {
-    @Inject
-    public JPAUsersRepository(DomainList domainList) {
-        super(domainList, new JPAUsersDAO());
+    public PostgresUsersRepositoryConfiguration(Algorithm preferredAlgorithm, 
HashingMode fallbackHashingMode) {
+        this.preferredAlgorithm = preferredAlgorithm;
+        this.fallbackHashingMode = fallbackHashingMode;
     }
 
-    /**
-     * Sets entity manager.
-     * 
-     * @param entityManagerFactory
-     *            the entityManager to set
-     */
-    @Inject
-    @PersistenceUnit(unitName = "James")
-    public final void setEntityManagerFactory(EntityManagerFactory 
entityManagerFactory) {
-        usersDAO.setEntityManagerFactory(entityManagerFactory);
+    public Algorithm getPreferredAlgorithm() {
+        return preferredAlgorithm;
     }
 
-    @PostConstruct
-    public void init() {
-        usersDAO.init();
+    public HashingMode getFallbackHashingMode() {
+        return fallbackHashingMode;
     }
 
-    @Override
-    public void configure(HierarchicalConfiguration<ImmutableNode> config) 
throws ConfigurationException {
-        usersDAO.configure(config);
-        super.configure(config);
+    public static PostgresUsersRepositoryConfiguration 
from(HierarchicalConfiguration<ImmutableNode> config) throws 
ConfigurationException {
+        return new PostgresUsersRepositoryConfiguration(
+            Algorithm.of(config.getString("algorithm", DEFAULT_ALGORITHM)),
+            HashingMode.parse(config.getString("hashingMode", 
DEFAULT_HASHING_MODE)));
     }
 }
diff --git 
a/server/data/data-postgres/src/test/java/org/apache/james/rrt/jpa/JPARecipientRewriteTableTest.java
 
b/server/data/data-postgres/src/test/java/org/apache/james/rrt/jpa/JPARecipientRewriteTableTest.java
index 2f60f58192..308f448d69 100644
--- 
a/server/data/data-postgres/src/test/java/org/apache/james/rrt/jpa/JPARecipientRewriteTableTest.java
+++ 
b/server/data/data-postgres/src/test/java/org/apache/james/rrt/jpa/JPARecipientRewriteTableTest.java
@@ -25,7 +25,8 @@ import org.apache.james.domainlist.api.DomainList;
 import org.apache.james.rrt.jpa.model.JPARecipientRewrite;
 import org.apache.james.rrt.lib.AbstractRecipientRewriteTable;
 import org.apache.james.rrt.lib.RecipientRewriteTableContract;
-import org.apache.james.user.jpa.JPAUsersRepository;
+import org.apache.james.user.postgres.PostgresUsersDAO;
+import org.apache.james.user.postgres.PostgresUsersRepository;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 
@@ -49,7 +50,7 @@ class JPARecipientRewriteTableTest implements 
RecipientRewriteTableContract {
     public void createRecipientRewriteTable() {
         JPARecipientRewriteTable localVirtualUserTable = new 
JPARecipientRewriteTable();
         
localVirtualUserTable.setEntityManagerFactory(JPA_TEST_CLUSTER.getEntityManagerFactory());
-        localVirtualUserTable.setUsersRepository(new 
JPAUsersRepository(mock(DomainList.class)));
+        localVirtualUserTable.setUsersRepository(new 
PostgresUsersRepository(mock(DomainList.class), mock(PostgresUsersDAO.class)));
         recipientRewriteTable = localVirtualUserTable;
     }
 
diff --git 
a/server/data/data-postgres/src/test/java/org/apache/james/rrt/jpa/JPAStepdefs.java
 
b/server/data/data-postgres/src/test/java/org/apache/james/rrt/jpa/JPAStepdefs.java
index 3908dfe98e..6ff9058402 100644
--- 
a/server/data/data-postgres/src/test/java/org/apache/james/rrt/jpa/JPAStepdefs.java
+++ 
b/server/data/data-postgres/src/test/java/org/apache/james/rrt/jpa/JPAStepdefs.java
@@ -18,12 +18,15 @@
  ****************************************************************/
 package org.apache.james.rrt.jpa;
 
+import static org.mockito.Mockito.mock;
+
 import org.apache.james.backends.jpa.JpaTestCluster;
 import org.apache.james.rrt.jpa.model.JPARecipientRewrite;
 import org.apache.james.rrt.lib.AbstractRecipientRewriteTable;
 import org.apache.james.rrt.lib.RecipientRewriteTableFixture;
 import org.apache.james.rrt.lib.RewriteTablesStepdefs;
-import org.apache.james.user.jpa.JPAUsersRepository;
+import org.apache.james.user.postgres.PostgresUsersDAO;
+import org.apache.james.user.postgres.PostgresUsersRepository;
 
 import com.github.fge.lambdas.Throwing;
 
@@ -53,7 +56,7 @@ public class JPAStepdefs {
     private AbstractRecipientRewriteTable getRecipientRewriteTable() throws 
Exception {
         JPARecipientRewriteTable localVirtualUserTable = new 
JPARecipientRewriteTable();
         
localVirtualUserTable.setEntityManagerFactory(JPA_TEST_CLUSTER.getEntityManagerFactory());
-        localVirtualUserTable.setUsersRepository(new 
JPAUsersRepository(RecipientRewriteTableFixture.domainListForCucumberTests()));
+        localVirtualUserTable.setUsersRepository(new 
PostgresUsersRepository(RecipientRewriteTableFixture.domainListForCucumberTests(),
 mock(PostgresUsersDAO.class)));
         
localVirtualUserTable.setDomainList(RecipientRewriteTableFixture.domainListForCucumberTests());
         return localVirtualUserTable;
     }
diff --git 
a/server/data/data-postgres/src/test/java/org/apache/james/user/jpa/model/JPAUserTest.java
 
b/server/data/data-postgres/src/test/java/org/apache/james/user/jpa/model/JPAUserTest.java
deleted file mode 100644
index fa11b2504d..0000000000
--- 
a/server/data/data-postgres/src/test/java/org/apache/james/user/jpa/model/JPAUserTest.java
+++ /dev/null
@@ -1,73 +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.jpa.model;
-
-import org.assertj.core.api.Assertions;
-import org.junit.jupiter.api.Test;
-
-class JPAUserTest {
-
-    private static final String RANDOM_PASSWORD = "baeMiqu7";
-
-    @Test
-    void hashPasswordShouldBeNoopWhenNone() {
-        //I doubt the expected result was the author intent
-        Assertions.assertThat(JPAUser.hashPassword(RANDOM_PASSWORD, null, 
"NONE")).isEqualTo("baeMiqu7");
-    }
-
-    @Test
-    void hashPasswordShouldHashWhenMD5() {
-        Assertions.assertThat(JPAUser.hashPassword(RANDOM_PASSWORD, null, 
"MD5")).isEqualTo("702000e50c9fd3755b8fc20ecb07d1ac");
-    }
-
-    @Test
-    void hashPasswordShouldHashWhenSHA1() {
-        Assertions.assertThat(JPAUser.hashPassword(RANDOM_PASSWORD, null, 
"SHA1")).isEqualTo("05dbbaa7b4bcae245f14d19ae58ef1b80adf3363");
-    }
-
-    @Test
-    void hashPasswordShouldHashWhenSHA256() {
-        Assertions.assertThat(JPAUser.hashPassword(RANDOM_PASSWORD, null, 
"SHA-256")).isEqualTo("6d06c72a578fe0b78ede2393b07739831a287774dcad0b18bc4bde8b0c948b82");
-    }
-
-    @Test
-    void hashPasswordShouldHashWhenSHA512() {
-        Assertions.assertThat(JPAUser.hashPassword(RANDOM_PASSWORD, null, 
"SHA-512")).isEqualTo("f9cc82d1c04bb2ce0494a51f7a21d07ac60b6f79a8a55397f454603acac29d8589fdfd694d5c01ba01a346c76b090abca9ad855b5b0c92c6062ad6d93cdc0d03");
-    }
-
-    @Test
-    void hashPasswordShouldSha512WhenRandomString() {
-        Assertions.assertThat(JPAUser.hashPassword(RANDOM_PASSWORD, null, 
"random")).isEqualTo("f9cc82d1c04bb2ce0494a51f7a21d07ac60b6f79a8a55397f454603acac29d8589fdfd694d5c01ba01a346c76b090abca9ad855b5b0c92c6062ad6d93cdc0d03");
-    }
-
-    @Test
-    void hashPasswordShouldSha512WhenNull() {
-        Assertions.assertThat(JPAUser.hashPassword(RANDOM_PASSWORD, null, 
null)).isEqualTo("f9cc82d1c04bb2ce0494a51f7a21d07ac60b6f79a8a55397f454603acac29d8589fdfd694d5c01ba01a346c76b090abca9ad855b5b0c92c6062ad6d93cdc0d03");
-    }
-
-    @Test
-    void hashPasswordShouldHashWithNullSalt() {
-        Assertions.assertThat(JPAUser.hashPassword(RANDOM_PASSWORD, null, 
"SHA-512/salted")).isEqualTo("f9cc82d1c04bb2ce0494a51f7a21d07ac60b6f79a8a55397f454603acac29d8589fdfd694d5c01ba01a346c76b090abca9ad855b5b0c92c6062ad6d93cdc0d03");
-    }
-
-    @Test
-    void hashPasswordShouldHashWithSalt() {
-        Assertions.assertThat(JPAUser.hashPassword(RANDOM_PASSWORD, "salt", 
"SHA-512/salted")).isEqualTo("b7941dcdc380ec414623834919f7d5cbe241a2b6a23be79a61cd9f36178382901b8d83642b743297ac72e5de24e4111885dd05df06e14e47c943c05fdd1ff15a");
-    }
-}
\ No newline at end of file
diff --git 
a/server/data/data-postgres/src/test/java/org/apache/james/user/jpa/JpaUsersRepositoryTest.java
 
b/server/data/data-postgres/src/test/java/org/apache/james/user/postgres/PostgresUsersRepositoryTest.java
similarity index 74%
rename from 
server/data/data-postgres/src/test/java/org/apache/james/user/jpa/JpaUsersRepositoryTest.java
rename to 
server/data/data-postgres/src/test/java/org/apache/james/user/postgres/PostgresUsersRepositoryTest.java
index 55355b0a9d..e83f03bf10 100644
--- 
a/server/data/data-postgres/src/test/java/org/apache/james/user/jpa/JpaUsersRepositoryTest.java
+++ 
b/server/data/data-postgres/src/test/java/org/apache/james/user/postgres/PostgresUsersRepositoryTest.java
@@ -16,32 +16,34 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
-package org.apache.james.user.jpa;
 
-import java.util.Optional;
+package org.apache.james.user.postgres;
 
 import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
-import org.apache.james.backends.jpa.JpaTestCluster;
+import org.apache.james.backends.postgres.PostgresExtension;
+import 
org.apache.james.backends.postgres.utils.SinglePostgresConnectionFactory;
 import org.apache.james.core.Username;
 import org.apache.james.domainlist.api.DomainList;
 import org.apache.james.user.api.UsersRepository;
-import org.apache.james.user.jpa.model.JPAUser;
 import org.apache.james.user.lib.UsersRepositoryContract;
-import org.junit.jupiter.api.AfterEach;
+import org.apache.james.user.lib.UsersRepositoryImpl;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-class JpaUsersRepositoryTest {
+import java.util.Optional;
+
+class PostgresUsersRepositoryTest {
 
-    private static final JpaTestCluster JPA_TEST_CLUSTER = 
JpaTestCluster.create(JPAUser.class);
+    @RegisterExtension
+    static PostgresExtension postgresExtension = 
PostgresExtension.withoutRowLevelSecurity(PostgresUserModule.MODULE);
 
     @Nested
     class WhenEnableVirtualHosting implements 
UsersRepositoryContract.WithVirtualHostingContract {
         @RegisterExtension
         UserRepositoryExtension extension = 
UserRepositoryExtension.withVirtualHost();
 
-        private JPAUsersRepository usersRepository;
+        private UsersRepositoryImpl<PostgresUsersDAO> usersRepository;
         private TestSystem testSystem;
 
         @BeforeEach
@@ -51,7 +53,7 @@ class JpaUsersRepositoryTest {
         }
 
         @Override
-        public UsersRepository testee() {
+        public UsersRepositoryImpl<PostgresUsersDAO> testee() {
             return usersRepository;
         }
 
@@ -66,7 +68,7 @@ class JpaUsersRepositoryTest {
         @RegisterExtension
         UserRepositoryExtension extension = 
UserRepositoryExtension.withoutVirtualHosting();
 
-        private JPAUsersRepository usersRepository;
+        private UsersRepositoryImpl<PostgresUsersDAO> usersRepository;
         private TestSystem testSystem;
 
         @BeforeEach
@@ -76,7 +78,7 @@ class JpaUsersRepositoryTest {
         }
 
         @Override
-        public UsersRepository testee() {
+        public UsersRepositoryImpl<PostgresUsersDAO> testee() {
             return usersRepository;
         }
 
@@ -86,18 +88,15 @@ class JpaUsersRepositoryTest {
         }
     }
 
-    @AfterEach
-    void tearDown() {
-        JPA_TEST_CLUSTER.clear("JAMES_USER");
-    }
-
-    private static JPAUsersRepository getUsersRepository(DomainList 
domainList, boolean enableVirtualHosting, Optional<Username> administrator) 
throws Exception {
-        JPAUsersRepository repos = new JPAUsersRepository(domainList);
-        
repos.setEntityManagerFactory(JPA_TEST_CLUSTER.getEntityManagerFactory());
+    private static UsersRepositoryImpl<PostgresUsersDAO> 
getUsersRepository(DomainList domainList, boolean enableVirtualHosting, 
Optional<Username> administrator) throws Exception {
+        PostgresUsersDAO usersDAO = new PostgresUsersDAO(new 
SinglePostgresConnectionFactory(postgresExtension.getConnection().block()),
+            PostgresUsersRepositoryConfiguration.DEFAULT);
         BaseHierarchicalConfiguration configuration = new 
BaseHierarchicalConfiguration();
         configuration.addProperty("enableVirtualHosting", 
String.valueOf(enableVirtualHosting));
         administrator.ifPresent(username -> 
configuration.addProperty("administratorId", username.asString()));
-        repos.configure(configuration);
-        return repos;
+
+        UsersRepositoryImpl<PostgresUsersDAO> usersRepository = new 
PostgresUsersRepository(domainList, usersDAO);
+        usersRepository.configure(configuration);
+        return usersRepository;
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to