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

Reply via email to