From 3637aaa009b753b2da0729cc3ec3ce47e2b15389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Mon, 2 Jan 2023 10:52:23 +0100 Subject: [PATCH] Allow accessing the MongoDB ClientSession programmatively --- docs/src/main/asciidoc/mongodb-panache.adoc | 2 ++ .../common/runtime/MongoOperations.java | 8 +++-- .../quarkus/mongodb/panache/kotlin/Panache.kt | 27 +++++++++++++++++ .../io/quarkus/mongodb/panache/Panache.java | 30 +++++++++++++++++++ .../TransactionPersonResource.java | 4 +++ 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 extensions/panache/mongodb-panache-kotlin/runtime/src/main/kotlin/io/quarkus/mongodb/panache/kotlin/Panache.kt create mode 100644 extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/Panache.java diff --git a/docs/src/main/asciidoc/mongodb-panache.adoc b/docs/src/main/asciidoc/mongodb-panache.adoc index 1c2140715c483..e7fc011781d0e 100644 --- a/docs/src/main/asciidoc/mongodb-panache.adoc +++ b/docs/src/main/asciidoc/mongodb-panache.adoc @@ -770,6 +770,8 @@ MongoDB offers ACID transactions since version 4.0. To use them with MongoDB with Panache you need to annotate the method that starts the transaction with the `@Transactional` annotation. +Inside methods annotated with `@Transactional` you can access the `ClientSession` with `Panache.getClientSession()` if needed. + In MongoDB, a transaction is only possible on a replicaset, luckily our xref:mongodb.adoc#dev-services[Dev Services for MongoDB] setups a single node replicaset so it is compatible with transactions. diff --git a/extensions/panache/mongodb-panache-common/runtime/src/main/java/io/quarkus/mongodb/panache/common/runtime/MongoOperations.java b/extensions/panache/mongodb-panache-common/runtime/src/main/java/io/quarkus/mongodb/panache/common/runtime/MongoOperations.java index c2285c29c4356..93f411727938b 100644 --- a/extensions/panache/mongodb-panache-common/runtime/src/main/java/io/quarkus/mongodb/panache/common/runtime/MongoOperations.java +++ b/extensions/panache/mongodb-panache-common/runtime/src/main/java/io/quarkus/mongodb/panache/common/runtime/MongoOperations.java @@ -333,9 +333,8 @@ ClientSession getSession(Object entity) { return getSession(entity.getClass()); } - ClientSession getSession(Class entityClass) { + public ClientSession getSession(Class entityClass) { ClientSession clientSession = null; - MongoEntity mongoEntity = entityClass.getAnnotation(MongoEntity.class); InstanceHandle instance = Arc.container() .instance(TransactionSynchronizationRegistry.class); if (instance.isAvailable()) { @@ -343,6 +342,7 @@ ClientSession getSession(Class entityClass) { if (registry.getTransactionStatus() == Status.STATUS_ACTIVE) { clientSession = (ClientSession) registry.getResource(SESSION_KEY); if (clientSession == null) { + MongoEntity mongoEntity = entityClass == null ? null : entityClass.getAnnotation(MongoEntity.class); return registerClientSession(mongoEntity, registry); } } @@ -350,6 +350,10 @@ ClientSession getSession(Class entityClass) { return clientSession; } + public ClientSession getSession() { + return getSession(null); + } + private ClientSession registerClientSession(MongoEntity mongoEntity, TransactionSynchronizationRegistry registry) { TransactionManager transactionManager = Arc.container().instance(TransactionManager.class).get(); diff --git a/extensions/panache/mongodb-panache-kotlin/runtime/src/main/kotlin/io/quarkus/mongodb/panache/kotlin/Panache.kt b/extensions/panache/mongodb-panache-kotlin/runtime/src/main/kotlin/io/quarkus/mongodb/panache/kotlin/Panache.kt new file mode 100644 index 0000000000000..817c55f54bd43 --- /dev/null +++ b/extensions/panache/mongodb-panache-kotlin/runtime/src/main/kotlin/io/quarkus/mongodb/panache/kotlin/Panache.kt @@ -0,0 +1,27 @@ +package io.quarkus.mongodb.panache.kotlin + +import com.mongodb.session.ClientSession +import io.quarkus.mongodb.panache.kotlin.runtime.KotlinMongoOperations + +object Panache { + /** + * Access the current MongoDB ClientSession from the transaction context. Can be used inside a + * method annotated with `@Transactional` to manually access the client session. + * + * @return ClientSession or null if not in the context of a transaction. + */ + val session: ClientSession + get() = KotlinMongoOperations.INSTANCE.session + + /** + * Access the current MongoDB ClientSession from the transaction context. + * + * @param entityClass the class of the MongoDB entity in case it is configured to use the + * non-default client. + * @return ClientSession or null if not in the context of a transaction. + * @see [session] + */ + fun getSession(entityClass: Class<*>?): ClientSession { + return KotlinMongoOperations.INSTANCE.getSession(entityClass) + } +} diff --git a/extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/Panache.java b/extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/Panache.java new file mode 100644 index 0000000000000..2e1f900dee367 --- /dev/null +++ b/extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/Panache.java @@ -0,0 +1,30 @@ +package io.quarkus.mongodb.panache; + +import com.mongodb.session.ClientSession; + +import io.quarkus.mongodb.panache.runtime.JavaMongoOperations; + +public class Panache { + + /** + * Access the current MongoDB ClientSession from the transaction context. + * Can be used inside a method annotated with `@Transactional` to manually access the client session. + * + * @return ClientSession or null if not in the context of a transaction. + */ + public static ClientSession getSession() { + return JavaMongoOperations.INSTANCE.getSession(); + } + + /** + * Access the current MongoDB ClientSession from the transaction context. + * + * @see #getSession() + * + * @param entityClass the class of the MongoDB entity in case it is configured to use the non-default client. + * @return ClientSession or null if not in the context of a transaction. + */ + public static ClientSession getSession(Class entityClass) { + return JavaMongoOperations.INSTANCE.getSession(entityClass); + } +} diff --git a/integration-tests/mongodb-panache/src/main/java/io/quarkus/it/mongodb/panache/transaction/TransactionPersonResource.java b/integration-tests/mongodb-panache/src/main/java/io/quarkus/it/mongodb/panache/transaction/TransactionPersonResource.java index 27763f671c453..1b2b5e2a76377 100644 --- a/integration-tests/mongodb-panache/src/main/java/io/quarkus/it/mongodb/panache/transaction/TransactionPersonResource.java +++ b/integration-tests/mongodb-panache/src/main/java/io/quarkus/it/mongodb/panache/transaction/TransactionPersonResource.java @@ -1,5 +1,7 @@ package io.quarkus.it.mongodb.panache.transaction; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import java.net.URI; import java.util.ArrayList; import java.util.List; @@ -14,6 +16,7 @@ import com.mongodb.client.MongoClient; +import io.quarkus.mongodb.panache.Panache; import io.quarkus.runtime.StartupEvent; @Path("/transaction") @@ -42,6 +45,7 @@ public List getPersons() { @Transactional public Response addPerson(TransactionPerson person) { person.persist(); + assertNotNull(Panache.getSession(TransactionPerson.class)); return Response.created(URI.create("/transaction/" + person.id.toString())).build(); }