You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2023/05/30 01:56:24 UTC

[james-project] branch master updated: [FIX] Correctly close JPA EntityManager in a couple of places (#1574)

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


The following commit(s) were added to refs/heads/master by this push:
     new 11422aa6ae [FIX] Correctly close JPA EntityManager in a couple of places (#1574)
11422aa6ae is described below

commit 11422aa6ae5c3acdc30b15742bbf6066287979dd
Author: Benoit TELLIER <bt...@linagora.com>
AuthorDate: Tue May 30 08:56:18 2023 +0700

    [FIX] Correctly close JPA EntityManager in a couple of places (#1574)
---
 .../mailbox/jpa/quota/JPAPerUserMaxQuotaDAO.java   | 73 +++++++++++++++-------
 .../mailbox/jpa/quota/JpaCurrentQuotaManager.java  | 10 ++-
 .../james/jpa/healthcheck/JPAHealthCheck.java      | 17 ++---
 3 files changed, 65 insertions(+), 35 deletions(-)

diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaDAO.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaDAO.java
index dcd23bae35..fa1fcffaca 100644
--- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaDAO.java
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JPAPerUserMaxQuotaDAO.java
@@ -26,6 +26,7 @@ import javax.inject.Inject;
 import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
 
+import org.apache.james.backends.jpa.EntityManagerUtils;
 import org.apache.james.backends.jpa.TransactionRunner;
 import org.apache.james.core.Domain;
 import org.apache.james.core.quota.QuotaCountLimit;
@@ -163,56 +164,80 @@ public class JPAPerUserMaxQuotaDAO {
 
     public Optional<QuotaSizeLimit> getGlobalMaxStorage() {
         EntityManager entityManager = entityManagerFactory.createEntityManager();
-        MaxGlobalStorage storedValue = entityManager.find(MaxGlobalStorage.class, MaxGlobalStorage.DEFAULT_KEY);
-        if (storedValue == null) {
-            return Optional.empty();
+        try {
+            MaxGlobalStorage storedValue = entityManager.find(MaxGlobalStorage.class, MaxGlobalStorage.DEFAULT_KEY);
+            if (storedValue == null) {
+                return Optional.empty();
+            }
+            return longToQuotaSize(storedValue.getValue());
+        } finally {
+            EntityManagerUtils.safelyClose(entityManager);
         }
-        return longToQuotaSize(storedValue.getValue());
     }
 
     public Optional<QuotaCountLimit> getGlobalMaxMessage() {
         EntityManager entityManager = entityManagerFactory.createEntityManager();
-        MaxGlobalMessageCount storedValue = entityManager.find(MaxGlobalMessageCount.class, MaxGlobalMessageCount.DEFAULT_KEY);
-        if (storedValue == null) {
-            return Optional.empty();
+        try {
+            MaxGlobalMessageCount storedValue = entityManager.find(MaxGlobalMessageCount.class, MaxGlobalMessageCount.DEFAULT_KEY);
+            if (storedValue == null) {
+                return Optional.empty();
+            }
+            return longToQuotaCount(storedValue.getValue());
+        } finally {
+            EntityManagerUtils.safelyClose(entityManager);
         }
-        return longToQuotaCount(storedValue.getValue());
     }
 
     public Optional<QuotaSizeLimit> getMaxStorage(QuotaRoot quotaRoot) {
         EntityManager entityManager = entityManagerFactory.createEntityManager();
-        MaxUserStorage storedValue = entityManager.find(MaxUserStorage.class, quotaRoot.getValue());
-        if (storedValue == null) {
-            return Optional.empty();
+        try {
+            MaxUserStorage storedValue = entityManager.find(MaxUserStorage.class, quotaRoot.getValue());
+            if (storedValue == null) {
+                return Optional.empty();
+            }
+            return longToQuotaSize(storedValue.getValue());
+        } finally {
+            EntityManagerUtils.safelyClose(entityManager);
         }
-        return longToQuotaSize(storedValue.getValue());
     }
 
     public Optional<QuotaCountLimit> getMaxMessage(QuotaRoot quotaRoot) {
         EntityManager entityManager = entityManagerFactory.createEntityManager();
-        MaxUserMessageCount storedValue = entityManager.find(MaxUserMessageCount.class, quotaRoot.getValue());
-        if (storedValue == null) {
-            return Optional.empty();
+        try {
+            MaxUserMessageCount storedValue = entityManager.find(MaxUserMessageCount.class, quotaRoot.getValue());
+            if (storedValue == null) {
+                return Optional.empty();
+            }
+            return longToQuotaCount(storedValue.getValue());
+        } finally {
+            EntityManagerUtils.safelyClose(entityManager);
         }
-        return longToQuotaCount(storedValue.getValue());
     }
 
     public Optional<QuotaCountLimit> getDomainMaxMessage(Domain domain) {
         EntityManager entityManager = entityManagerFactory.createEntityManager();
-        MaxDomainMessageCount storedValue = entityManager.find(MaxDomainMessageCount.class, domain.asString());
-        if (storedValue == null) {
-            return Optional.empty();
+        try {
+            MaxDomainMessageCount storedValue = entityManager.find(MaxDomainMessageCount.class, domain.asString());
+            if (storedValue == null) {
+                return Optional.empty();
+            }
+            return longToQuotaCount(storedValue.getValue());
+        } finally {
+            EntityManagerUtils.safelyClose(entityManager);
         }
-        return longToQuotaCount(storedValue.getValue());
     }
 
     public Optional<QuotaSizeLimit> getDomainMaxStorage(Domain domain) {
         EntityManager entityManager = entityManagerFactory.createEntityManager();
-        MaxDomainStorage storedValue = entityManager.find(MaxDomainStorage.class, domain.asString());
-        if (storedValue == null) {
-            return Optional.empty();
+        try {
+            MaxDomainStorage storedValue = entityManager.find(MaxDomainStorage.class, domain.asString());
+            if (storedValue == null) {
+                return Optional.empty();
+            }
+            return longToQuotaSize(storedValue.getValue());
+        } finally {
+            EntityManagerUtils.safelyClose(entityManager);
         }
-        return longToQuotaSize(storedValue.getValue());
     }
 
 
diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JpaCurrentQuotaManager.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JpaCurrentQuotaManager.java
index 3e4c6d161a..2f5c5a980d 100644
--- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JpaCurrentQuotaManager.java
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/quota/JpaCurrentQuotaManager.java
@@ -25,6 +25,7 @@ import javax.inject.Inject;
 import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
 
+import org.apache.james.backends.jpa.EntityManagerUtils;
 import org.apache.james.backends.jpa.TransactionRunner;
 import org.apache.james.core.quota.QuotaCountUsage;
 import org.apache.james.core.quota.QuotaSizeUsage;
@@ -56,7 +57,8 @@ public class JpaCurrentQuotaManager implements CurrentQuotaManager {
 
         return Mono.fromCallable(() -> Optional.ofNullable(retrieveUserQuota(entityManager, quotaRoot))
             .map(JpaCurrentQuota::getMessageCount)
-            .orElse(QuotaCountUsage.count(NO_STORED_BYTES)));
+            .orElse(QuotaCountUsage.count(NO_STORED_BYTES)))
+            .doFinally(any -> EntityManagerUtils.safelyClose(entityManager));
     }
 
     @Override
@@ -65,14 +67,16 @@ public class JpaCurrentQuotaManager implements CurrentQuotaManager {
 
         return Mono.fromCallable(() -> Optional.ofNullable(retrieveUserQuota(entityManager, quotaRoot))
             .map(JpaCurrentQuota::getSize)
-            .orElse(QuotaSizeUsage.size(NO_STORED_BYTES)));
+            .orElse(QuotaSizeUsage.size(NO_STORED_BYTES)))
+            .doFinally(any -> EntityManagerUtils.safelyClose(entityManager));
     }
 
     public Mono<CurrentQuotas> getCurrentQuotas(QuotaRoot quotaRoot) {
         EntityManager entityManager = entityManagerFactory.createEntityManager();
         return Mono.fromCallable(() ->  Optional.ofNullable(retrieveUserQuota(entityManager, quotaRoot))
             .map(jpaCurrentQuota -> new CurrentQuotas(jpaCurrentQuota.getMessageCount(), jpaCurrentQuota.getSize()))
-            .orElse(CurrentQuotas.emptyQuotas()));
+            .orElse(CurrentQuotas.emptyQuotas()))
+            .doFinally(any -> EntityManagerUtils.safelyClose(entityManager));
     }
 
     @Override
diff --git a/server/data/data-jpa/src/main/java/org/apache/james/jpa/healthcheck/JPAHealthCheck.java b/server/data/data-jpa/src/main/java/org/apache/james/jpa/healthcheck/JPAHealthCheck.java
index a97461223a..7dbea33e7f 100644
--- a/server/data/data-jpa/src/main/java/org/apache/james/jpa/healthcheck/JPAHealthCheck.java
+++ b/server/data/data-jpa/src/main/java/org/apache/james/jpa/healthcheck/JPAHealthCheck.java
@@ -22,14 +22,15 @@ import static org.apache.james.core.healthcheck.Result.healthy;
 import static org.apache.james.core.healthcheck.Result.unhealthy;
 
 import javax.inject.Inject;
-import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
 
+import org.apache.james.backends.jpa.EntityManagerUtils;
 import org.apache.james.core.healthcheck.ComponentName;
 import org.apache.james.core.healthcheck.HealthCheck;
 import org.apache.james.core.healthcheck.Result;
 
 import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
 
 public class JPAHealthCheck implements HealthCheck {
 
@@ -47,15 +48,15 @@ public class JPAHealthCheck implements HealthCheck {
 
     @Override
     public Mono<Result> check() {
-        return Mono.fromCallable(entityManagerFactory::createEntityManager)
-            .map(EntityManager::isOpen)
-            .map(open -> {
-                if (open) {
-                    return healthy(componentName());
+        return Mono.usingWhen(Mono.fromCallable(entityManagerFactory::createEntityManager).subscribeOn(Schedulers.boundedElastic()),
+            entityManager -> {
+                if (entityManager.isOpen()) {
+                    return Mono.just(healthy(componentName()));
                 } else {
-                    return unhealthy(componentName(), "entityManager is not open");
+                    return Mono.just(unhealthy(componentName(), "entityManager is not open"));
                 }
-            })
+            },
+            entityManager -> Mono.fromRunnable(() -> EntityManagerUtils.safelyClose(entityManager)).subscribeOn(Schedulers.boundedElastic()))
             .onErrorResume(IllegalStateException.class,
                 e -> Mono.just(unhealthy(componentName(), "EntityManagerFactory or EntityManager thrown an IllegalStateException, the connection is unhealthy", e)))
             .onErrorResume(e -> Mono.just(unhealthy(componentName(), "Unexpected exception upon checking JPA driver", e)));


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