This is an automated email from the ASF dual-hosted git repository. btellier 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 77fd764597 JAMES-2586 PostgresRecipientRewriteTableDAO and PostgresRecipientRewriteTable (#1844) 77fd764597 is described below commit 77fd7645972d82cae1c2a266bffbb67c5a60db29 Author: hungphan227 <45198168+hungphan...@users.noreply.github.com> AuthorDate: Mon Dec 11 18:43:21 2023 +0700 JAMES-2586 PostgresRecipientRewriteTableDAO and PostgresRecipientRewriteTable (#1844) --- .../src/main/resources/META-INF/persistence.xml | 1 - .../james/modules/data/PostgresDataModule.java | 2 +- ...va => PostgresRecipientRewriteTableModule.java} | 19 +- server/data/data-postgres/pom.xml | 2 - .../james/rrt/jpa/JPARecipientRewriteTable.java | 251 --------------------- .../james/rrt/jpa/model/JPARecipientRewrite.java | 147 ------------ .../postgres/PostgresRecipientRewriteTable.java | 88 ++++++++ .../postgres/PostgresRecipientRewriteTableDAO.java | 89 ++++++++ .../PostgresRecipientRewriteTableModule.java | 59 +++++ .../PostgresRecipientRewriteTableTest.java} | 29 +-- .../PostgresStepdefs.java} | 35 +-- .../rrt/{jpa => postgres}/RewriteTablesTest.java | 4 +- .../src/test/resources/persistence.xml | 1 - 13 files changed, 286 insertions(+), 441 deletions(-) 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 d074a13385..489b1e81d7 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 @@ -26,7 +26,6 @@ <persistence-unit name="Global" transaction-type="RESOURCE_LOCAL"> <class>org.apache.james.mailrepository.jpa.model.JPAUrl</class> <class>org.apache.james.mailrepository.jpa.model.JPAMail</class> - <class>org.apache.james.rrt.jpa.model.JPARecipientRewrite</class> <class>org.apache.james.sieve.postgres.model.JPASieveScript</class> <properties> diff --git a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataModule.java b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataModule.java index 39cec08889..905f346249 100644 --- a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataModule.java +++ b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataModule.java @@ -28,7 +28,7 @@ public class PostgresDataModule extends AbstractModule { protected void configure() { install(new CoreDataModule()); install(new PostgresDomainListModule()); - install(new JPARecipientRewriteTableModule()); + install(new PostgresRecipientRewriteTableModule()); install(new JPAMailRepositoryModule()); } } diff --git a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPARecipientRewriteTableModule.java b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresRecipientRewriteTableModule.java similarity index 71% rename from server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPARecipientRewriteTableModule.java rename to server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresRecipientRewriteTableModule.java index f00af56754..363c9879b8 100644 --- a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/JPARecipientRewriteTableModule.java +++ b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresRecipientRewriteTableModule.java @@ -16,37 +16,44 @@ * specific language governing permissions and limitations * * under the License. * ****************************************************************/ + package org.apache.james.modules.data; +import org.apache.james.backends.postgres.PostgresModule; import org.apache.james.rrt.api.AliasReverseResolver; import org.apache.james.rrt.api.CanSendFrom; import org.apache.james.rrt.api.RecipientRewriteTable; -import org.apache.james.rrt.jpa.JPARecipientRewriteTable; import org.apache.james.rrt.lib.AliasReverseResolverImpl; import org.apache.james.rrt.lib.CanSendFromImpl; +import org.apache.james.rrt.postgres.PostgresRecipientRewriteTable; +import org.apache.james.rrt.postgres.PostgresRecipientRewriteTableDAO; import org.apache.james.server.core.configuration.ConfigurationProvider; import org.apache.james.utils.InitializationOperation; import org.apache.james.utils.InitilizationOperationBuilder; import com.google.inject.AbstractModule; import com.google.inject.Scopes; +import com.google.inject.multibindings.Multibinder; import com.google.inject.multibindings.ProvidesIntoSet; -public class JPARecipientRewriteTableModule extends AbstractModule { +public class PostgresRecipientRewriteTableModule extends AbstractModule { @Override public void configure() { - bind(JPARecipientRewriteTable.class).in(Scopes.SINGLETON); - bind(RecipientRewriteTable.class).to(JPARecipientRewriteTable.class); + bind(PostgresRecipientRewriteTable.class).in(Scopes.SINGLETON); + bind(PostgresRecipientRewriteTableDAO.class).in(Scopes.SINGLETON); + bind(RecipientRewriteTable.class).to(PostgresRecipientRewriteTable.class); bind(AliasReverseResolverImpl.class).in(Scopes.SINGLETON); bind(AliasReverseResolver.class).to(AliasReverseResolverImpl.class); bind(CanSendFromImpl.class).in(Scopes.SINGLETON); bind(CanSendFrom.class).to(CanSendFromImpl.class); + + Multibinder.newSetBinder(binder(), PostgresModule.class).addBinding().toInstance(org.apache.james.rrt.postgres.PostgresRecipientRewriteTableModule.MODULE); } @ProvidesIntoSet - InitializationOperation configureRRT(ConfigurationProvider configurationProvider, JPARecipientRewriteTable recipientRewriteTable) { + InitializationOperation configureRecipientRewriteTable(ConfigurationProvider configurationProvider, PostgresRecipientRewriteTable recipientRewriteTable) { return InitilizationOperationBuilder - .forClass(JPARecipientRewriteTable.class) + .forClass(PostgresRecipientRewriteTable.class) .init(() -> recipientRewriteTable.configure(configurationProvider.getConfiguration("recipientrewritetable"))); } } diff --git a/server/data/data-postgres/pom.xml b/server/data/data-postgres/pom.xml index f5a2a5226e..88b2b88b9c 100644 --- a/server/data/data-postgres/pom.xml +++ b/server/data/data-postgres/pom.xml @@ -156,7 +156,6 @@ <version>${apache.openjpa.version}</version> <configuration> <includes>org/apache/james/sieve/postgres/model/JPASieveScript.class, - org/apache/james/rrt/jpa/model/JPARecipientRewrite.class, org/apache/james/mailrepository/jpa/model/JPAUrl.class, org/apache/james/mailrepository/jpa/model/JPAMail.class</includes> <addDefaultConstructor>true</addDefaultConstructor> @@ -169,7 +168,6 @@ <property> <name>metaDataFactory</name> <value>jpa(Types=org.apache.james.sieve.postgres.model.JPASieveScript; - org.apache.james.rrt.jpa.model.JPARecipientRewrite; org.apache.james.mailrepository.jpa.model.JPAUrl; org.apache.james.mailrepository.jpa.model.JPAMail)</value> </property> diff --git a/server/data/data-postgres/src/main/java/org/apache/james/rrt/jpa/JPARecipientRewriteTable.java b/server/data/data-postgres/src/main/java/org/apache/james/rrt/jpa/JPARecipientRewriteTable.java deleted file mode 100644 index 1d33448a54..0000000000 --- a/server/data/data-postgres/src/main/java/org/apache/james/rrt/jpa/JPARecipientRewriteTable.java +++ /dev/null @@ -1,251 +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.rrt.jpa; - -import static org.apache.james.rrt.jpa.model.JPARecipientRewrite.DELETE_MAPPING_QUERY; -import static org.apache.james.rrt.jpa.model.JPARecipientRewrite.SELECT_ALL_MAPPINGS_QUERY; -import static org.apache.james.rrt.jpa.model.JPARecipientRewrite.SELECT_SOURCES_BY_MAPPING_QUERY; -import static org.apache.james.rrt.jpa.model.JPARecipientRewrite.SELECT_USER_DOMAIN_MAPPING_QUERY; -import static org.apache.james.rrt.jpa.model.JPARecipientRewrite.UPDATE_MAPPING_QUERY; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import javax.inject.Inject; -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; -import javax.persistence.EntityTransaction; -import javax.persistence.PersistenceException; -import javax.persistence.PersistenceUnit; - -import org.apache.james.backends.jpa.EntityManagerUtils; -import org.apache.james.core.Domain; -import org.apache.james.rrt.api.RecipientRewriteTableException; -import org.apache.james.rrt.jpa.model.JPARecipientRewrite; -import org.apache.james.rrt.lib.AbstractRecipientRewriteTable; -import org.apache.james.rrt.lib.Mapping; -import org.apache.james.rrt.lib.MappingSource; -import org.apache.james.rrt.lib.Mappings; -import org.apache.james.rrt.lib.MappingsImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Preconditions; - -/** - * Class responsible to implement the Virtual User Table in database with JPA - * access. - */ -public class JPARecipientRewriteTable extends AbstractRecipientRewriteTable { - private static final Logger LOGGER = LoggerFactory.getLogger(JPARecipientRewriteTable.class); - - /** - * The entity manager to access the database. - */ - private EntityManagerFactory entityManagerFactory; - - /** - * Set the entity manager to use. - */ - @Inject - @PersistenceUnit(unitName = "James") - public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) { - this.entityManagerFactory = entityManagerFactory; - } - - @Override - public void addMapping(MappingSource source, Mapping mapping) throws RecipientRewriteTableException { - Mappings map = getStoredMappings(source); - if (!map.isEmpty()) { - Mappings updatedMappings = MappingsImpl.from(map).add(mapping).build(); - doUpdateMapping(source, updatedMappings.serialize()); - } else { - doAddMapping(source, mapping.asString()); - } - } - - @Override - protected Mappings mapAddress(String user, Domain domain) throws RecipientRewriteTableException { - Mappings userDomainMapping = getStoredMappings(MappingSource.fromUser(user, domain)); - if (userDomainMapping != null && !userDomainMapping.isEmpty()) { - return userDomainMapping; - } - Mappings domainMapping = getStoredMappings(MappingSource.fromDomain(domain)); - if (domainMapping != null && !domainMapping.isEmpty()) { - return domainMapping; - } - return MappingsImpl.empty(); - } - - @Override - public Mappings getStoredMappings(MappingSource source) throws RecipientRewriteTableException { - EntityManager entityManager = entityManagerFactory.createEntityManager(); - try { - @SuppressWarnings("unchecked") - List<JPARecipientRewrite> virtualUsers = entityManager.createNamedQuery(SELECT_USER_DOMAIN_MAPPING_QUERY) - .setParameter("user", source.getFixedUser()) - .setParameter("domain", source.getFixedDomain()) - .getResultList(); - if (virtualUsers.size() > 0) { - return MappingsImpl.fromRawString(virtualUsers.get(0).getTargetAddress()); - } - return MappingsImpl.empty(); - } catch (PersistenceException e) { - LOGGER.debug("Failed to get user domain mappings", e); - throw new RecipientRewriteTableException("Error while retrieve mappings", e); - } finally { - EntityManagerUtils.safelyClose(entityManager); - } - } - - @Override - public Map<MappingSource, Mappings> getAllMappings() throws RecipientRewriteTableException { - EntityManager entityManager = entityManagerFactory.createEntityManager(); - Map<MappingSource, Mappings> mapping = new HashMap<>(); - try { - @SuppressWarnings("unchecked") - List<JPARecipientRewrite> virtualUsers = entityManager.createNamedQuery(SELECT_ALL_MAPPINGS_QUERY).getResultList(); - for (JPARecipientRewrite virtualUser : virtualUsers) { - mapping.put(MappingSource.fromUser(virtualUser.getUser(), virtualUser.getDomain()), MappingsImpl.fromRawString(virtualUser.getTargetAddress())); - } - return mapping; - } catch (PersistenceException e) { - LOGGER.debug("Failed to get all mappings", e); - throw new RecipientRewriteTableException("Error while retrieve mappings", e); - } finally { - EntityManagerUtils.safelyClose(entityManager); - } - } - - @Override - public Stream<MappingSource> listSources(Mapping mapping) throws RecipientRewriteTableException { - Preconditions.checkArgument(listSourcesSupportedType.contains(mapping.getType()), - "Not supported mapping of type %s", mapping.getType()); - - EntityManager entityManager = entityManagerFactory.createEntityManager(); - try { - return entityManager.createNamedQuery(SELECT_SOURCES_BY_MAPPING_QUERY, JPARecipientRewrite.class) - .setParameter("targetAddress", mapping.asString()) - .getResultList() - .stream() - .map(user -> MappingSource.fromUser(user.getUser(), user.getDomain())); - } catch (PersistenceException e) { - String error = "Unable to list sources by mapping"; - LOGGER.debug(error, e); - throw new RecipientRewriteTableException(error, e); - } finally { - EntityManagerUtils.safelyClose(entityManager); - } - } - - @Override - public void removeMapping(MappingSource source, Mapping mapping) throws RecipientRewriteTableException { - Mappings map = getStoredMappings(source); - if (map.size() > 1) { - Mappings updatedMappings = map.remove(mapping); - doUpdateMapping(source, updatedMappings.serialize()); - } else { - doRemoveMapping(source, mapping.asString()); - } - } - - /** - * Update the mapping for the given user and domain - * - * @return true if update was successfully - */ - private boolean doUpdateMapping(MappingSource source, String mapping) throws RecipientRewriteTableException { - EntityManager entityManager = entityManagerFactory.createEntityManager(); - final EntityTransaction transaction = entityManager.getTransaction(); - try { - transaction.begin(); - int updated = entityManager - .createNamedQuery(UPDATE_MAPPING_QUERY) - .setParameter("targetAddress", mapping) - .setParameter("user", source.getFixedUser()) - .setParameter("domain", source.getFixedDomain()) - .executeUpdate(); - transaction.commit(); - if (updated > 0) { - return true; - } - } catch (PersistenceException e) { - LOGGER.debug("Failed to update mapping", e); - if (transaction.isActive()) { - transaction.rollback(); - } - throw new RecipientRewriteTableException("Unable to update mapping", e); - } finally { - EntityManagerUtils.safelyClose(entityManager); - } - return false; - } - - /** - * Remove a mapping for the given user and domain - */ - private void doRemoveMapping(MappingSource source, String mapping) throws RecipientRewriteTableException { - EntityManager entityManager = entityManagerFactory.createEntityManager(); - final EntityTransaction transaction = entityManager.getTransaction(); - try { - transaction.begin(); - entityManager.createNamedQuery(DELETE_MAPPING_QUERY) - .setParameter("user", source.getFixedUser()) - .setParameter("domain", source.getFixedDomain()) - .setParameter("targetAddress", mapping) - .executeUpdate(); - transaction.commit(); - - } catch (PersistenceException e) { - LOGGER.debug("Failed to remove mapping", e); - if (transaction.isActive()) { - transaction.rollback(); - } - throw new RecipientRewriteTableException("Unable to remove mapping", e); - - } finally { - EntityManagerUtils.safelyClose(entityManager); - } - } - - /** - * Add mapping for given user and domain - */ - private void doAddMapping(MappingSource source, String mapping) throws RecipientRewriteTableException { - EntityManager entityManager = entityManagerFactory.createEntityManager(); - final EntityTransaction transaction = entityManager.getTransaction(); - try { - transaction.begin(); - JPARecipientRewrite jpaRecipientRewrite = new JPARecipientRewrite(source.getFixedUser(), Domain.of(source.getFixedDomain()), mapping); - entityManager.persist(jpaRecipientRewrite); - transaction.commit(); - } catch (PersistenceException e) { - LOGGER.debug("Failed to save virtual user", e); - if (transaction.isActive()) { - transaction.rollback(); - } - throw new RecipientRewriteTableException("Unable to add mapping", e); - } finally { - EntityManagerUtils.safelyClose(entityManager); - } - } - -} diff --git a/server/data/data-postgres/src/main/java/org/apache/james/rrt/jpa/model/JPARecipientRewrite.java b/server/data/data-postgres/src/main/java/org/apache/james/rrt/jpa/model/JPARecipientRewrite.java deleted file mode 100644 index 47402762c0..0000000000 --- a/server/data/data-postgres/src/main/java/org/apache/james/rrt/jpa/model/JPARecipientRewrite.java +++ /dev/null @@ -1,147 +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.rrt.jpa.model; - -import static org.apache.james.rrt.jpa.model.JPARecipientRewrite.DELETE_MAPPING_QUERY; -import static org.apache.james.rrt.jpa.model.JPARecipientRewrite.SELECT_ALL_MAPPINGS_QUERY; -import static org.apache.james.rrt.jpa.model.JPARecipientRewrite.SELECT_SOURCES_BY_MAPPING_QUERY; -import static org.apache.james.rrt.jpa.model.JPARecipientRewrite.SELECT_USER_DOMAIN_MAPPING_QUERY; -import static org.apache.james.rrt.jpa.model.JPARecipientRewrite.UPDATE_MAPPING_QUERY; - -import java.io.Serializable; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.IdClass; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; - -import org.apache.james.core.Domain; - -import com.google.common.base.Objects; - -/** - * RecipientRewriteTable class for the James Virtual User Table to be used for JPA - * persistence. - */ -@Entity(name = "JamesRecipientRewrite") -@Table(name = JPARecipientRewrite.JAMES_RECIPIENT_REWRITE) -@NamedQueries({ - @NamedQuery(name = SELECT_USER_DOMAIN_MAPPING_QUERY, query = "SELECT rrt FROM JamesRecipientRewrite rrt WHERE rrt.user=:user AND rrt.domain=:domain"), - @NamedQuery(name = SELECT_ALL_MAPPINGS_QUERY, query = "SELECT rrt FROM JamesRecipientRewrite rrt"), - @NamedQuery(name = DELETE_MAPPING_QUERY, query = "DELETE FROM JamesRecipientRewrite rrt WHERE rrt.user=:user AND rrt.domain=:domain AND rrt.targetAddress=:targetAddress"), - @NamedQuery(name = UPDATE_MAPPING_QUERY, query = "UPDATE JamesRecipientRewrite rrt SET rrt.targetAddress=:targetAddress WHERE rrt.user=:user AND rrt.domain=:domain"), - @NamedQuery(name = SELECT_SOURCES_BY_MAPPING_QUERY, query = "SELECT rrt FROM JamesRecipientRewrite rrt WHERE rrt.targetAddress=:targetAddress")}) -@IdClass(JPARecipientRewrite.RecipientRewriteTableId.class) -public class JPARecipientRewrite { - public static final String SELECT_USER_DOMAIN_MAPPING_QUERY = "selectUserDomainMapping"; - public static final String SELECT_ALL_MAPPINGS_QUERY = "selectAllMappings"; - public static final String DELETE_MAPPING_QUERY = "deleteMapping"; - public static final String UPDATE_MAPPING_QUERY = "updateMapping"; - public static final String SELECT_SOURCES_BY_MAPPING_QUERY = "selectSourcesByMapping"; - - public static final String JAMES_RECIPIENT_REWRITE = "JAMES_RECIPIENT_REWRITE"; - - public static class RecipientRewriteTableId implements Serializable { - - private static final long serialVersionUID = 1L; - - private String user; - - private String domain; - - public RecipientRewriteTableId() { - } - - @Override - public int hashCode() { - return Objects.hashCode(user, domain); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final RecipientRewriteTableId other = (RecipientRewriteTableId) obj; - return Objects.equal(this.user, other.user) && Objects.equal(this.domain, other.domain); - } - } - - /** - * The name of the user. - */ - @Id - @Column(name = "USER_NAME", nullable = false, length = 100) - private String user = ""; - - /** - * The name of the domain. Column name is chosen to be compatible with the - * JDBCRecipientRewriteTableList. - */ - @Id - @Column(name = "DOMAIN_NAME", nullable = false, length = 100) - private String domain = ""; - - /** - * The target address. column name is chosen to be compatible with the - * JDBCRecipientRewriteTableList. - */ - @Column(name = "TARGET_ADDRESS", nullable = false, length = 100) - private String targetAddress = ""; - - /** - * Default no-args constructor for JPA class enhancement. - * The constructor need to be public or protected to be used by JPA. - * See: http://docs.oracle.com/javaee/6/tutorial/doc/bnbqa.html - * Do not us this constructor, it is for JPA only. - */ - protected JPARecipientRewrite() { - } - - /** - * Use this simple constructor to create a new RecipientRewriteTable. - * - * @param user - * , domain and their associated targetAddress - */ - public JPARecipientRewrite(String user, Domain domain, String targetAddress) { - this.user = user; - this.domain = domain.asString(); - this.targetAddress = targetAddress; - } - - public String getUser() { - return user; - } - - public String getDomain() { - return domain; - } - - public String getTargetAddress() { - return targetAddress; - } - -} diff --git a/server/data/data-postgres/src/main/java/org/apache/james/rrt/postgres/PostgresRecipientRewriteTable.java b/server/data/data-postgres/src/main/java/org/apache/james/rrt/postgres/PostgresRecipientRewriteTable.java new file mode 100644 index 0000000000..862e19de40 --- /dev/null +++ b/server/data/data-postgres/src/main/java/org/apache/james/rrt/postgres/PostgresRecipientRewriteTable.java @@ -0,0 +1,88 @@ +/**************************************************************** + * 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.rrt.postgres; + +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import javax.inject.Inject; + +import org.apache.commons.lang3.tuple.Pair; +import org.apache.james.core.Domain; +import org.apache.james.rrt.lib.AbstractRecipientRewriteTable; +import org.apache.james.rrt.lib.Mapping; +import org.apache.james.rrt.lib.MappingSource; +import org.apache.james.rrt.lib.Mappings; +import org.apache.james.rrt.lib.MappingsImpl; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; + +public class PostgresRecipientRewriteTable extends AbstractRecipientRewriteTable { + private PostgresRecipientRewriteTableDAO postgresRecipientRewriteTableDAO; + + @Inject + public PostgresRecipientRewriteTable(PostgresRecipientRewriteTableDAO postgresRecipientRewriteTableDAO) { + this.postgresRecipientRewriteTableDAO = postgresRecipientRewriteTableDAO; + } + + @Override + public void addMapping(MappingSource source, Mapping mapping) { + postgresRecipientRewriteTableDAO.addMapping(source, mapping).block(); + } + + @Override + public void removeMapping(MappingSource source, Mapping mapping) { + postgresRecipientRewriteTableDAO.removeMapping(source, mapping).block(); + } + + @Override + public Mappings getStoredMappings(MappingSource source) { + return postgresRecipientRewriteTableDAO.getMappings(source).block(); + } + + @Override + public Map<MappingSource, Mappings> getAllMappings() { + return postgresRecipientRewriteTableDAO.getAllMappings() + .collect(ImmutableMap.toImmutableMap( + Pair::getLeft, + pair -> MappingsImpl.fromMappings(pair.getRight()), + Mappings::union)) + .block(); + } + + @Override + protected Mappings mapAddress(String user, Domain domain) { + return postgresRecipientRewriteTableDAO.getMappings(MappingSource.fromUser(user, domain)) + .filter(Predicate.not(Mappings::isEmpty)) + .blockOptional() + .orElse(postgresRecipientRewriteTableDAO.getMappings(MappingSource.fromDomain(domain)).block()); + } + + @Override + public Stream<MappingSource> listSources(Mapping mapping) { + Preconditions.checkArgument(listSourcesSupportedType.contains(mapping.getType()), + "Not supported mapping of type %s", mapping.getType()); + + return postgresRecipientRewriteTableDAO.getSources(mapping).toStream(); + } + +} diff --git a/server/data/data-postgres/src/main/java/org/apache/james/rrt/postgres/PostgresRecipientRewriteTableDAO.java b/server/data/data-postgres/src/main/java/org/apache/james/rrt/postgres/PostgresRecipientRewriteTableDAO.java new file mode 100644 index 0000000000..c5bbf9d1c3 --- /dev/null +++ b/server/data/data-postgres/src/main/java/org/apache/james/rrt/postgres/PostgresRecipientRewriteTableDAO.java @@ -0,0 +1,89 @@ +/**************************************************************** + * 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.rrt.postgres; + +import static org.apache.james.rrt.postgres.PostgresRecipientRewriteTableModule.PostgresRecipientRewriteTableTable.DOMAIN_NAME; +import static org.apache.james.rrt.postgres.PostgresRecipientRewriteTableModule.PostgresRecipientRewriteTableTable.PK_CONSTRAINT_NAME; +import static org.apache.james.rrt.postgres.PostgresRecipientRewriteTableModule.PostgresRecipientRewriteTableTable.TABLE_NAME; +import static org.apache.james.rrt.postgres.PostgresRecipientRewriteTableModule.PostgresRecipientRewriteTableTable.TARGET_ADDRESS; +import static org.apache.james.rrt.postgres.PostgresRecipientRewriteTableModule.PostgresRecipientRewriteTableTable.USERNAME; + +import javax.inject.Inject; + +import org.apache.commons.lang3.tuple.Pair; +import org.apache.james.backends.postgres.utils.PostgresExecutor; +import org.apache.james.rrt.lib.Mapping; +import org.apache.james.rrt.lib.MappingSource; +import org.apache.james.rrt.lib.Mappings; +import org.apache.james.rrt.lib.MappingsImpl; + +import com.google.common.collect.ImmutableList; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class PostgresRecipientRewriteTableDAO { + private final PostgresExecutor postgresExecutor; + + @Inject + public PostgresRecipientRewriteTableDAO(PostgresExecutor postgresExecutor) { + this.postgresExecutor = postgresExecutor; + } + + public Mono<Void> addMapping(MappingSource source, Mapping mapping) { + return postgresExecutor.executeVoid(dslContext -> + Mono.from(dslContext.insertInto(TABLE_NAME, USERNAME, DOMAIN_NAME, TARGET_ADDRESS) + .values(source.getFixedUser(), + source.getFixedDomain(), + mapping.asString()) + .onConflictOnConstraint(PK_CONSTRAINT_NAME) + .doUpdate() + .set(TARGET_ADDRESS, mapping.asString()))); + } + + public Mono<Void> removeMapping(MappingSource source, Mapping mapping) { + return postgresExecutor.executeVoid(dsl -> Mono.from(dsl.deleteFrom(TABLE_NAME) + .where(USERNAME.eq(source.getFixedUser())) + .and(DOMAIN_NAME.eq(source.getFixedDomain())) + .and(TARGET_ADDRESS.eq(mapping.asString())))); + } + + public Mono<Mappings> getMappings(MappingSource source) { + return postgresExecutor.executeRows(dsl -> Flux.from(dsl.selectFrom(TABLE_NAME) + .where(USERNAME.eq(source.getFixedUser())) + .and(DOMAIN_NAME.eq(source.getFixedDomain())))) + .map(record -> record.get(TARGET_ADDRESS)) + .collect(ImmutableList.toImmutableList()) + .map(MappingsImpl::fromCollection); + } + + public Flux<Pair<MappingSource, Mapping>> getAllMappings() { + return postgresExecutor.executeRows(dsl -> Flux.from(dsl.selectFrom(TABLE_NAME))) + .map(record -> Pair.of( + MappingSource.fromUser(record.get(USERNAME), record.get(DOMAIN_NAME)), + Mapping.of(record.get(TARGET_ADDRESS)))); + } + + public Flux<MappingSource> getSources(Mapping mapping) { + return postgresExecutor.executeRows(dsl -> Flux.from(dsl.selectFrom(TABLE_NAME) + .where(TARGET_ADDRESS.eq(mapping.asString())))) + .map(record -> MappingSource.fromUser(record.get(USERNAME), record.get(DOMAIN_NAME))); + } +} diff --git a/server/data/data-postgres/src/main/java/org/apache/james/rrt/postgres/PostgresRecipientRewriteTableModule.java b/server/data/data-postgres/src/main/java/org/apache/james/rrt/postgres/PostgresRecipientRewriteTableModule.java new file mode 100644 index 0000000000..7574483439 --- /dev/null +++ b/server/data/data-postgres/src/main/java/org/apache/james/rrt/postgres/PostgresRecipientRewriteTableModule.java @@ -0,0 +1,59 @@ +/**************************************************************** + * 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.rrt.postgres; + +import org.apache.james.backends.postgres.PostgresIndex; +import org.apache.james.backends.postgres.PostgresModule; +import org.apache.james.backends.postgres.PostgresTable; +import org.jooq.Field; +import org.jooq.Name; +import org.jooq.Record; +import org.jooq.Table; +import org.jooq.impl.DSL; +import org.jooq.impl.SQLDataType; + +public interface PostgresRecipientRewriteTableModule { + interface PostgresRecipientRewriteTableTable { + Table<Record> TABLE_NAME = DSL.table("rrt"); + + Field<String> USERNAME = DSL.field("username", SQLDataType.VARCHAR(255).notNull()); + Field<String> DOMAIN_NAME = DSL.field("domain_name", SQLDataType.VARCHAR(255).notNull()); + Field<String> TARGET_ADDRESS = DSL.field("target_address", SQLDataType.VARCHAR(255).notNull()); + + Name PK_CONSTRAINT_NAME = DSL.name("rrt_pkey"); + + PostgresTable TABLE = PostgresTable.name(TABLE_NAME.getName()) + .createTableStep(((dsl, tableName) -> dsl.createTableIfNotExists(tableName) + .column(USERNAME) + .column(DOMAIN_NAME) + .column(TARGET_ADDRESS) + .constraint(DSL.constraint(PK_CONSTRAINT_NAME).primaryKey(USERNAME, DOMAIN_NAME, TARGET_ADDRESS)))) + .supportsRowLevelSecurity(); + + PostgresIndex INDEX = PostgresIndex.name("idx_rrt_target_address") + .createIndexStep((dslContext, indexName) -> dslContext.createIndex(indexName) + .on(TABLE_NAME, TARGET_ADDRESS)); + } + + PostgresModule MODULE = PostgresModule.builder() + .addTable(PostgresRecipientRewriteTableTable.TABLE) + .addIndex(PostgresRecipientRewriteTableTable.INDEX) + .build(); +} 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/postgres/PostgresRecipientRewriteTableTest.java similarity index 59% rename from server/data/data-postgres/src/test/java/org/apache/james/rrt/jpa/JPARecipientRewriteTableTest.java rename to server/data/data-postgres/src/test/java/org/apache/james/rrt/postgres/PostgresRecipientRewriteTableTest.java index 308f448d69..757778dd7b 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/postgres/PostgresRecipientRewriteTableTest.java @@ -16,25 +16,27 @@ * specific language governing permissions and limitations * * under the License. * ****************************************************************/ -package org.apache.james.rrt.jpa; -import static org.mockito.Mockito.mock; +package org.apache.james.rrt.postgres; -import org.apache.james.backends.jpa.JpaTestCluster; -import org.apache.james.domainlist.api.DomainList; -import org.apache.james.rrt.jpa.model.JPARecipientRewrite; +import org.apache.james.backends.postgres.PostgresExtension; +import org.apache.james.backends.postgres.PostgresModule; +import org.apache.james.domainlist.api.mock.SimpleDomainList; import org.apache.james.rrt.lib.AbstractRecipientRewriteTable; import org.apache.james.rrt.lib.RecipientRewriteTableContract; +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 org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; -class JPARecipientRewriteTableTest implements RecipientRewriteTableContract { +public class PostgresRecipientRewriteTableTest implements RecipientRewriteTableContract { + @RegisterExtension + static PostgresExtension postgresExtension = PostgresExtension.withoutRowLevelSecurity(PostgresModule.aggregateModules(PostgresRecipientRewriteTableModule.MODULE, PostgresUserModule.MODULE)); - static final JpaTestCluster JPA_TEST_CLUSTER = JpaTestCluster.create(JPARecipientRewrite.class); - - AbstractRecipientRewriteTable recipientRewriteTable; + private PostgresRecipientRewriteTable postgresRecipientRewriteTable; @BeforeEach void setup() throws Exception { @@ -48,14 +50,13 @@ class JPARecipientRewriteTableTest implements RecipientRewriteTableContract { @Override public void createRecipientRewriteTable() { - JPARecipientRewriteTable localVirtualUserTable = new JPARecipientRewriteTable(); - localVirtualUserTable.setEntityManagerFactory(JPA_TEST_CLUSTER.getEntityManagerFactory()); - localVirtualUserTable.setUsersRepository(new PostgresUsersRepository(mock(DomainList.class), mock(PostgresUsersDAO.class))); - recipientRewriteTable = localVirtualUserTable; + postgresRecipientRewriteTable = new PostgresRecipientRewriteTable(new PostgresRecipientRewriteTableDAO(postgresExtension.getPostgresExecutor())); + postgresRecipientRewriteTable.setUsersRepository(new PostgresUsersRepository(new SimpleDomainList(), + new PostgresUsersDAO(postgresExtension.getPostgresExecutor(), PostgresUsersRepositoryConfiguration.DEFAULT))); } @Override public AbstractRecipientRewriteTable virtualUserTable() { - return recipientRewriteTable; + return postgresRecipientRewriteTable; } } 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/postgres/PostgresStepdefs.java similarity index 57% rename from server/data/data-postgres/src/test/java/org/apache/james/rrt/jpa/JPAStepdefs.java rename to server/data/data-postgres/src/test/java/org/apache/james/rrt/postgres/PostgresStepdefs.java index 6ff9058402..dc89ddf929 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/postgres/PostgresStepdefs.java @@ -16,48 +16,51 @@ * specific language governing permissions and limitations * * under the License. * ****************************************************************/ -package org.apache.james.rrt.jpa; +package org.apache.james.rrt.postgres; -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.backends.postgres.PostgresExtension; +import org.apache.james.backends.postgres.PostgresModule; +import org.apache.james.domainlist.api.DomainListException; 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.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.github.fge.lambdas.Throwing; import cucumber.api.java.After; import cucumber.api.java.Before; -public class JPAStepdefs { - - private static final JpaTestCluster JPA_TEST_CLUSTER = JpaTestCluster.create(JPARecipientRewrite.class); +public class PostgresStepdefs { + static PostgresExtension postgresExtension = PostgresExtension.withoutRowLevelSecurity(PostgresModule.aggregateModules(PostgresRecipientRewriteTableModule.MODULE, PostgresUserModule.MODULE)); private final RewriteTablesStepdefs mainStepdefs; - public JPAStepdefs(RewriteTablesStepdefs mainStepdefs) { + public PostgresStepdefs(RewriteTablesStepdefs mainStepdefs) { this.mainStepdefs = mainStepdefs; } @Before public void setup() throws Throwable { + postgresExtension.beforeAll(null); + postgresExtension.beforeEach(null); mainStepdefs.setUp(Throwing.supplier(this::getRecipientRewriteTable).sneakyThrow()); } @After public void tearDown() { - JPA_TEST_CLUSTER.clear(JPARecipientRewrite.JAMES_RECIPIENT_REWRITE); + postgresExtension.afterEach(null); + postgresExtension.afterAll(null); } - private AbstractRecipientRewriteTable getRecipientRewriteTable() throws Exception { - JPARecipientRewriteTable localVirtualUserTable = new JPARecipientRewriteTable(); - localVirtualUserTable.setEntityManagerFactory(JPA_TEST_CLUSTER.getEntityManagerFactory()); - localVirtualUserTable.setUsersRepository(new PostgresUsersRepository(RecipientRewriteTableFixture.domainListForCucumberTests(), mock(PostgresUsersDAO.class))); - localVirtualUserTable.setDomainList(RecipientRewriteTableFixture.domainListForCucumberTests()); - return localVirtualUserTable; + private AbstractRecipientRewriteTable getRecipientRewriteTable() throws DomainListException { + PostgresRecipientRewriteTable postgresRecipientRewriteTable = new PostgresRecipientRewriteTable(new PostgresRecipientRewriteTableDAO(postgresExtension.getPostgresExecutor())); + postgresRecipientRewriteTable.setUsersRepository(new PostgresUsersRepository(RecipientRewriteTableFixture.domainListForCucumberTests(), + new PostgresUsersDAO(postgresExtension.getPostgresExecutor(), PostgresUsersRepositoryConfiguration.DEFAULT))); + postgresRecipientRewriteTable.setDomainList(RecipientRewriteTableFixture.domainListForCucumberTests()); + return postgresRecipientRewriteTable; } } diff --git a/server/data/data-postgres/src/test/java/org/apache/james/rrt/jpa/RewriteTablesTest.java b/server/data/data-postgres/src/test/java/org/apache/james/rrt/postgres/RewriteTablesTest.java similarity index 96% rename from server/data/data-postgres/src/test/java/org/apache/james/rrt/jpa/RewriteTablesTest.java rename to server/data/data-postgres/src/test/java/org/apache/james/rrt/postgres/RewriteTablesTest.java index 7cb0a007f0..4d0077187c 100644 --- a/server/data/data-postgres/src/test/java/org/apache/james/rrt/jpa/RewriteTablesTest.java +++ b/server/data/data-postgres/src/test/java/org/apache/james/rrt/postgres/RewriteTablesTest.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * * under the License. * ****************************************************************/ -package org.apache.james.rrt.jpa; +package org.apache.james.rrt.postgres; import org.junit.runner.RunWith; @@ -26,7 +26,7 @@ import cucumber.api.junit.Cucumber; @RunWith(Cucumber.class) @CucumberOptions( features = { "classpath:cucumber/" }, - glue = { "org.apache.james.rrt.lib", "org.apache.james.rrt.jpa" } + glue = { "org.apache.james.rrt.lib", "org.apache.james.rrt.postgres" } ) public class RewriteTablesTest { } diff --git a/server/data/data-postgres/src/test/resources/persistence.xml b/server/data/data-postgres/src/test/resources/persistence.xml index 4a6b7c3c5b..6ac35df9a4 100644 --- a/server/data/data-postgres/src/test/resources/persistence.xml +++ b/server/data/data-postgres/src/test/resources/persistence.xml @@ -26,7 +26,6 @@ <persistence-unit name="James" transaction-type="JTA"> <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider> <jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/james)</jta-data-source> - <class>org.apache.james.rrt.jpa.model.JPARecipientRewrite</class> <class>org.apache.james.mailrepository.jpa.model.JPAUrl</class> <class>org.apache.james.mailrepository.jpa.model.JPAMail</class> <class>org.apache.james.sieve.postgres.model.JPASieveScript</class> --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org