[FIX] Correctly close JPA EntityManager in a couple of places (#1574)
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 dcd23ba..fa1fcff 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.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 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 3e4c6d1..2f5c5a9 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.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 @@
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 @@
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 a974612..7dbea33 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.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 @@
@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)));