This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 883ced728517756aed0039e70517e9ae69ecd57e Author: Simon Levesque <si...@simonlevesque.com> AuthorDate: Sun Jan 12 08:47:01 2020 -0500 JAMES-3026 Fix OpenJPA transaction memory leak --- .../james/backends/jpa/EntityManagerUtils.java | 45 ++++++++++++++++++++++ .../james/backends/jpa/TransactionRunner.java | 4 +- .../apache/james/backends/jpa/JpaTestCluster.java | 2 +- .../jpa/JPAMailboxSessionMapperFactory.java | 3 +- .../james/mailbox/jpa/JPATransactionalMapper.java | 9 ++--- .../james/mailbox/jpa/mail/JPAModSeqProvider.java | 9 ++--- .../james/mailbox/jpa/mail/JPAUidProvider.java | 9 ++--- .../apache/james/domainlist/jpa/JPADomainList.java | 11 +++--- .../james/rrt/jpa/JPARecipientRewriteTable.java | 11 +++--- .../apache/james/user/jpa/JPAUsersRepository.java | 17 ++++---- 10 files changed, 80 insertions(+), 40 deletions(-) diff --git a/backends-common/jpa/src/main/java/org/apache/james/backends/jpa/EntityManagerUtils.java b/backends-common/jpa/src/main/java/org/apache/james/backends/jpa/EntityManagerUtils.java new file mode 100644 index 0000000..db7085c --- /dev/null +++ b/backends-common/jpa/src/main/java/org/apache/james/backends/jpa/EntityManagerUtils.java @@ -0,0 +1,45 @@ +/**************************************************************** + * 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.backends.jpa; + +import javax.persistence.EntityManager; + +public class EntityManagerUtils { + + /** + * Safely close an EntityManager by rolling back any active transaction and then closing it. That is needed to prevent memory leaks. + * @param entityManager the entity manager to close + */ + public static void safelyClose(EntityManager entityManager) { + + if (entityManager == null) { + return; + } + + if (entityManager.isOpen()) { + if (entityManager.getTransaction().isActive()) { + entityManager.getTransaction().rollback(); + } + entityManager.close(); + } + + } + +} diff --git a/backends-common/jpa/src/main/java/org/apache/james/backends/jpa/TransactionRunner.java b/backends-common/jpa/src/main/java/org/apache/james/backends/jpa/TransactionRunner.java index dd1e151..e3575a1 100644 --- a/backends-common/jpa/src/main/java/org/apache/james/backends/jpa/TransactionRunner.java +++ b/backends-common/jpa/src/main/java/org/apache/james/backends/jpa/TransactionRunner.java @@ -72,7 +72,7 @@ public class TransactionRunner { } return errorHandler.apply(e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } @@ -91,7 +91,7 @@ public class TransactionRunner { } errorHandler.apply(e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } } diff --git a/backends-common/jpa/src/test/java/org/apache/james/backends/jpa/JpaTestCluster.java b/backends-common/jpa/src/test/java/org/apache/james/backends/jpa/JpaTestCluster.java index d80f4ff..cd93112 100644 --- a/backends-common/jpa/src/test/java/org/apache/james/backends/jpa/JpaTestCluster.java +++ b/backends-common/jpa/src/test/java/org/apache/james/backends/jpa/JpaTestCluster.java @@ -75,6 +75,6 @@ public class JpaTestCluster { entityManager.createNativeQuery("DELETE FROM " + tableName).executeUpdate(); } entityManager.getTransaction().commit(); - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMailboxSessionMapperFactory.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMailboxSessionMapperFactory.java index 6f6c39e..3d5017b 100644 --- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMailboxSessionMapperFactory.java +++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMailboxSessionMapperFactory.java @@ -23,6 +23,7 @@ import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import org.apache.commons.lang3.NotImplementedException; +import org.apache.james.backends.jpa.EntityManagerUtils; import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.jpa.mail.JPAAnnotationMapper; @@ -53,7 +54,7 @@ public class JPAMailboxSessionMapperFactory extends MailboxSessionMapperFactory this.entityManagerFactory = entityManagerFactory; this.uidProvider = uidProvider; this.modSeqProvider = modSeqProvider; - createEntityManager().close(); + EntityManagerUtils.safelyClose(createEntityManager()); } @Override diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPATransactionalMapper.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPATransactionalMapper.java index 6e053fa..9bfcf8e 100644 --- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPATransactionalMapper.java +++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPATransactionalMapper.java @@ -23,6 +23,7 @@ import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.PersistenceException; +import org.apache.james.backends.jpa.EntityManagerUtils; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.store.transaction.TransactionalMapper; @@ -87,12 +88,8 @@ public abstract class JPATransactionalMapper extends TransactionalMapper { */ @Override public void endRequest() { - if (entityManager != null) { - if (entityManager.isOpen()) { - entityManager.close(); - } - entityManager = null; - } + EntityManagerUtils.safelyClose(entityManager); + entityManager = null; } diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAModSeqProvider.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAModSeqProvider.java index da24f12..6f41819 100644 --- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAModSeqProvider.java +++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAModSeqProvider.java @@ -23,6 +23,7 @@ import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.PersistenceException; +import org.apache.james.backends.jpa.EntityManagerUtils; import org.apache.james.mailbox.ModSeq; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.jpa.JPAId; @@ -77,9 +78,7 @@ public class JPAModSeqProvider implements ModSeqProvider { } throw new MailboxException("Unable to save highest mod-sequence for mailbox " + mailboxId.serialize(), e); } finally { - if (manager != null) { - manager.close(); - } + EntityManagerUtils.safelyClose(manager); } } @@ -94,9 +93,7 @@ public class JPAModSeqProvider implements ModSeqProvider { } catch (PersistenceException e) { throw new MailboxException("Unable to get highest mod-sequence for mailbox " + mailboxId.serialize(), e); } finally { - if (manager != null) { - manager.close(); - } + EntityManagerUtils.safelyClose(manager); } } } diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAUidProvider.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAUidProvider.java index c4fd608..85e140e 100644 --- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAUidProvider.java +++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAUidProvider.java @@ -25,6 +25,7 @@ import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.PersistenceException; +import org.apache.james.backends.jpa.EntityManagerUtils; import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.jpa.JPAId; @@ -56,9 +57,7 @@ public class JPAUidProvider implements UidProvider { } catch (PersistenceException e) { throw new MailboxException("Unable to get last uid for mailbox " + mailbox, e); } finally { - if (manager != null) { - manager.close(); - } + EntityManagerUtils.safelyClose(manager); } } @@ -88,9 +87,7 @@ public class JPAUidProvider implements UidProvider { } throw new MailboxException("Unable to save next uid for mailbox " + mailboxId.serialize(), e); } finally { - if (manager != null) { - manager.close(); - } + EntityManagerUtils.safelyClose(manager); } } diff --git a/server/data/data-jpa/src/main/java/org/apache/james/domainlist/jpa/JPADomainList.java b/server/data/data-jpa/src/main/java/org/apache/james/domainlist/jpa/JPADomainList.java index 0aaca0d..6391ab0 100644 --- a/server/data/data-jpa/src/main/java/org/apache/james/domainlist/jpa/JPADomainList.java +++ b/server/data/data-jpa/src/main/java/org/apache/james/domainlist/jpa/JPADomainList.java @@ -29,6 +29,7 @@ import javax.persistence.NoResultException; 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.dnsservice.api.DNSService; import org.apache.james.domainlist.api.DomainListException; @@ -69,7 +70,7 @@ public class JPADomainList extends AbstractDomainList { @PostConstruct public void init() { - createEntityManager().close(); + EntityManagerUtils.safelyClose(createEntityManager()); } @SuppressWarnings("unchecked") @@ -88,7 +89,7 @@ public class JPADomainList extends AbstractDomainList { LOGGER.error("Failed to list domains", e); throw new DomainListException("Unable to retrieve domains", e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } @@ -101,7 +102,7 @@ public class JPADomainList extends AbstractDomainList { LOGGER.error("Failed to find domain", e); throw new DomainListException("Unable to retrieve domains", e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } @@ -123,7 +124,7 @@ public class JPADomainList extends AbstractDomainList { rollback(transaction); throw new DomainListException("Unable to add domain " + domain.name(), e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } @@ -144,7 +145,7 @@ public class JPADomainList extends AbstractDomainList { rollback(transaction); throw new DomainListException("Unable to remove domain " + domain.name(), e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } diff --git a/server/data/data-jpa/src/main/java/org/apache/james/rrt/jpa/JPARecipientRewriteTable.java b/server/data/data-jpa/src/main/java/org/apache/james/rrt/jpa/JPARecipientRewriteTable.java index 83c364b..2b6d74e 100644 --- a/server/data/data-jpa/src/main/java/org/apache/james/rrt/jpa/JPARecipientRewriteTable.java +++ b/server/data/data-jpa/src/main/java/org/apache/james/rrt/jpa/JPARecipientRewriteTable.java @@ -29,6 +29,7 @@ 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; @@ -102,7 +103,7 @@ public class JPARecipientRewriteTable extends AbstractRecipientRewriteTable { LOGGER.debug("Failed to get user domain mappings", e); throw new RecipientRewriteTableException("Error while retrieve mappings", e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } @@ -121,7 +122,7 @@ public class JPARecipientRewriteTable extends AbstractRecipientRewriteTable { LOGGER.debug("Failed to get all mappings", e); throw new RecipientRewriteTableException("Error while retrieve mappings", e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } @@ -163,7 +164,7 @@ public class JPARecipientRewriteTable extends AbstractRecipientRewriteTable { } throw new RecipientRewriteTableException("Unable to update mapping", e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } return false; } @@ -191,7 +192,7 @@ public class JPARecipientRewriteTable extends AbstractRecipientRewriteTable { throw new RecipientRewriteTableException("Unable to remove mapping", e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } @@ -213,7 +214,7 @@ public class JPARecipientRewriteTable extends AbstractRecipientRewriteTable { } throw new RecipientRewriteTableException("Unable to add mapping", e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } diff --git a/server/data/data-jpa/src/main/java/org/apache/james/user/jpa/JPAUsersRepository.java b/server/data/data-jpa/src/main/java/org/apache/james/user/jpa/JPAUsersRepository.java index 7934b16..e949a52 100644 --- a/server/data/data-jpa/src/main/java/org/apache/james/user/jpa/JPAUsersRepository.java +++ b/server/data/data-jpa/src/main/java/org/apache/james/user/jpa/JPAUsersRepository.java @@ -35,6 +35,7 @@ import javax.persistence.PersistenceUnit; import org.apache.commons.configuration2.HierarchicalConfiguration; import org.apache.commons.configuration2.ex.ConfigurationException; import org.apache.commons.configuration2.tree.ImmutableNode; +import org.apache.james.backends.jpa.EntityManagerUtils; import org.apache.james.core.Username; import org.apache.james.domainlist.api.DomainList; import org.apache.james.user.api.UsersRepositoryException; @@ -75,7 +76,7 @@ public class JPAUsersRepository extends AbstractUsersRepository { @PostConstruct public void init() { - createEntityManager().close(); + EntityManagerUtils.safelyClose(createEntityManager()); } /** @@ -100,7 +101,7 @@ public class JPAUsersRepository extends AbstractUsersRepository { LOGGER.debug("Failed to find user", e); throw new UsersRepositoryException("Unable to search user", e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } @@ -129,7 +130,7 @@ public class JPAUsersRepository extends AbstractUsersRepository { } throw new UsersRepositoryException("Failed to update user " + user.getUserName().asString(), e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } @@ -159,7 +160,7 @@ public class JPAUsersRepository extends AbstractUsersRepository { } throw new UsersRepositoryException("Failed to remove user " + name.asString(), e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } @@ -182,7 +183,7 @@ public class JPAUsersRepository extends AbstractUsersRepository { LOGGER.debug("Failed to find user", e); throw new UsersRepositoryException("Failed to find user" + name.asString(), e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } @@ -222,7 +223,7 @@ public class JPAUsersRepository extends AbstractUsersRepository { LOGGER.debug("Failed to find user", e); throw new UsersRepositoryException("Failed to count users", e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } @@ -247,7 +248,7 @@ public class JPAUsersRepository extends AbstractUsersRepository { LOGGER.debug("Failed to find user", e); throw new UsersRepositoryException("Failed to list users", e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } @@ -286,7 +287,7 @@ public class JPAUsersRepository extends AbstractUsersRepository { } throw new UsersRepositoryException("Failed to add user" + username.asString(), e); } finally { - entityManager.close(); + EntityManagerUtils.safelyClose(entityManager); } } --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org