diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/BsonDiscriminatorBuildItem.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/BsonDiscriminatorBuildItem.java index dee6c429ac529..386d9f43501ff 100644 --- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/BsonDiscriminatorBuildItem.java +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/BsonDiscriminatorBuildItem.java @@ -4,6 +4,9 @@ import io.quarkus.builder.item.SimpleBuildItem; +/** + * Register additional BsonDiscriminator's for the MongoDB clients. + */ public final class BsonDiscriminatorBuildItem extends SimpleBuildItem { private List bsonDiscriminatorClassNames; diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/CodecProviderBuildItem.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/CodecProviderBuildItem.java index 20079947bdd1e..46a4be300320c 100644 --- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/CodecProviderBuildItem.java +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/CodecProviderBuildItem.java @@ -2,8 +2,13 @@ import java.util.List; +import org.bson.codecs.configuration.CodecProvider; + import io.quarkus.builder.item.SimpleBuildItem; +/** + * Register additional {@link CodecProvider}s for the MongoDB clients. + */ public final class CodecProviderBuildItem extends SimpleBuildItem { private List codecProviderClassNames; diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/CommandListenerBuildItem.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/CommandListenerBuildItem.java new file mode 100644 index 0000000000000..5dad5b89e0757 --- /dev/null +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/CommandListenerBuildItem.java @@ -0,0 +1,23 @@ +package io.quarkus.mongodb.deployment; + +import java.util.List; + +import com.mongodb.event.CommandListener; + +import io.quarkus.builder.item.SimpleBuildItem; + +/** + * Register additional {@link CommandListener}s for the MongoDB clients. + */ +public final class CommandListenerBuildItem extends SimpleBuildItem { + + private List commandListenerClassNames; + + public CommandListenerBuildItem(List commandListenerClassNames) { + this.commandListenerClassNames = commandListenerClassNames; + } + + public List getCommandListenerClassNames() { + return commandListenerClassNames; + } +} diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientBuildItem.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientBuildItem.java index 353eab886d24c..9cb7d0fd62a89 100644 --- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientBuildItem.java +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientBuildItem.java @@ -6,6 +6,9 @@ import io.quarkus.mongodb.reactive.ReactiveMongoClient; import io.quarkus.runtime.RuntimeValue; +/** + * Provide the MongoDB clients as RuntimeValue's. + */ public final class MongoClientBuildItem extends MultiBuildItem { private final RuntimeValue client; private final RuntimeValue reactive; diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientNameBuildItem.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientNameBuildItem.java index 2236b56790c63..f6165bbf0e570 100644 --- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientNameBuildItem.java +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientNameBuildItem.java @@ -4,7 +4,7 @@ import io.quarkus.mongodb.MongoClientName; /** - * Represents the values of the {@link MongoClientName} + * Represents the values of the {@link MongoClientName}. */ public final class MongoClientNameBuildItem extends MultiBuildItem { diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java index 91b47eea174c5..97c88992762d8 100644 --- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java @@ -24,6 +24,7 @@ import org.jboss.jandex.IndexView; import com.mongodb.client.MongoClient; +import com.mongodb.event.CommandListener; import com.mongodb.event.ConnectionPoolListener; import io.quarkus.arc.deployment.AdditionalBeanBuildItem; @@ -91,12 +92,22 @@ BsonDiscriminatorBuildItem collectBsonDiscriminators(CombinedIndexBuildItem inde } @BuildStep - List addCodecsAndDiscriminatorsToNative(CodecProviderBuildItem codecProviders, - PropertyCodecProviderBuildItem propertyCodecProviders, BsonDiscriminatorBuildItem bsonDiscriminators) { + CommandListenerBuildItem collectCommandListeners(CombinedIndexBuildItem indexBuildItem) { + Collection commandListenerClasses = indexBuildItem.getIndex() + .getAllKnownImplementors(DotName.createSimple(CommandListener.class.getName())); + List names = commandListenerClasses.stream().map(ci -> ci.name().toString()).collect(Collectors.toList()); + return new CommandListenerBuildItem(names); + } + + @BuildStep + List addExtensionPointsToNative(CodecProviderBuildItem codecProviders, + PropertyCodecProviderBuildItem propertyCodecProviders, BsonDiscriminatorBuildItem bsonDiscriminators, + CommandListenerBuildItem commandListeners) { List reflectiveClassNames = new ArrayList<>(); reflectiveClassNames.addAll(codecProviders.getCodecProviderClassNames()); reflectiveClassNames.addAll(propertyCodecProviders.getPropertyCodecProviderClassNames()); reflectiveClassNames.addAll(bsonDiscriminators.getBsonDiscriminatorClassNames()); + reflectiveClassNames.addAll(commandListeners.getCommandListenerClassNames()); return reflectiveClassNames.stream() .map(s -> new ReflectiveClassBuildItem(true, true, false, s)) @@ -160,6 +171,7 @@ void build( CodecProviderBuildItem codecProvider, PropertyCodecProviderBuildItem propertyCodecProvider, BsonDiscriminatorBuildItem bsonDiscriminator, + CommandListenerBuildItem commandListener, List connectionPoolListenerProvider, BuildProducer mongoConnections, BuildProducer syntheticBeanBuildItemBuildProducer, @@ -183,7 +195,7 @@ void build( .scope(Singleton.class) .supplier(recorder.mongoClientSupportSupplier(codecProvider.getCodecProviderClassNames(), propertyCodecProvider.getPropertyCodecProviderClassNames(), - bsonDiscriminator.getBsonDiscriminatorClassNames(), + bsonDiscriminator.getBsonDiscriminatorClassNames(), commandListener.getCommandListenerClassNames(), poolListenerList, sslNativeConfig.isExplicitlyDisabled())) .done()); diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoConnectionNameBuildItem.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoConnectionNameBuildItem.java index 7cd1a3e9c7572..d144b88c65a52 100644 --- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoConnectionNameBuildItem.java +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoConnectionNameBuildItem.java @@ -3,7 +3,7 @@ import io.quarkus.builder.item.MultiBuildItem; /** - * Holds a Mongo connection name + * Holds a MongoDB connection name. */ final class MongoConnectionNameBuildItem extends MultiBuildItem { diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoConnectionPoolListenerBuildItem.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoConnectionPoolListenerBuildItem.java index 9dc6639dd730a..1f021cc242313 100644 --- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoConnectionPoolListenerBuildItem.java +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoConnectionPoolListenerBuildItem.java @@ -6,7 +6,11 @@ import io.quarkus.builder.item.MultiBuildItem; +/** + * Register additional {@link ConnectionPoolListener}s. + */ public final class MongoConnectionPoolListenerBuildItem extends MultiBuildItem { + private Supplier connectionPoolListener; public MongoConnectionPoolListenerBuildItem(Supplier connectionPoolListener) { diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/PropertyCodecProviderBuildItem.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/PropertyCodecProviderBuildItem.java index f6b6f239f83f9..0941f1e9e751e 100644 --- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/PropertyCodecProviderBuildItem.java +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/PropertyCodecProviderBuildItem.java @@ -2,8 +2,13 @@ import java.util.List; +import org.bson.codecs.pojo.PropertyCodecProvider; + import io.quarkus.builder.item.SimpleBuildItem; +/** + * Register additional {@link PropertyCodecProvider}s for the MongoDB clients. + */ public final class PropertyCodecProviderBuildItem extends SimpleBuildItem { private List propertyCodecProviderClassNames; diff --git a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MockCommandListener.java b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MockCommandListener.java new file mode 100644 index 0000000000000..5557bfd515a81 --- /dev/null +++ b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MockCommandListener.java @@ -0,0 +1,18 @@ +package io.quarkus.mongodb; + +import java.util.ArrayList; +import java.util.List; + +import com.mongodb.event.CommandListener; +import com.mongodb.event.CommandStartedEvent; + +public class MockCommandListener implements CommandListener { + + public static final List EVENTS = new ArrayList<>(); + + @Override + public void commandStarted(CommandStartedEvent startedEvent) { + EVENTS.add(startedEvent.getCommandName()); + } + +} \ No newline at end of file diff --git a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoCommandListenerTest.java b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoCommandListenerTest.java new file mode 100644 index 0000000000000..cd0edff5a0a3f --- /dev/null +++ b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoCommandListenerTest.java @@ -0,0 +1,46 @@ +package io.quarkus.mongodb; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasSize; + +import javax.inject.Inject; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import com.mongodb.client.MongoClient; + +import io.quarkus.test.QuarkusUnitTest; + +public class MongoCommandListenerTest extends MongoTestBase { + + @Inject + MongoClient client; + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .setArchiveProducer( + () -> ShrinkWrap.create(JavaArchive.class).addClasses(MongoTestBase.class, MockCommandListener.class)) + .withConfigurationResource("default-mongoclient.properties"); + + @AfterEach + void cleanup() { + if (client != null) { + client.close(); + } + } + + @Test + void testClientInitialization() { + assertThat(client.listDatabaseNames().first()).isNotEmpty(); + assertThat(MockCommandListener.EVENTS, hasSize(1)); + assertThat(MockCommandListener.EVENTS, hasItems(equalTo("listDatabases"))); + } + +} diff --git a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientRecorder.java b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientRecorder.java index 100dcc6bef755..cd604c36a1471 100644 --- a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientRecorder.java +++ b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientRecorder.java @@ -22,18 +22,19 @@ public class MongoClientRecorder { public Supplier mongoClientSupportSupplier(List codecProviders, - List propertyCodecProviders, List bsonDiscriminators, + List propertyCodecProviders, List bsonDiscriminators, List commandListeners, List> connectionPoolListenerSuppliers, boolean disableSslSupport) { return new Supplier() { @Override public MongoClientSupport get() { + List connectionPoolListeners = new ArrayList<>(connectionPoolListenerSuppliers.size()); for (Supplier item : connectionPoolListenerSuppliers) { connectionPoolListeners.add(item.get()); } - return new MongoClientSupport(codecProviders, propertyCodecProviders, bsonDiscriminators, + return new MongoClientSupport(codecProviders, propertyCodecProviders, bsonDiscriminators, commandListeners, connectionPoolListeners, disableSslSupport); } }; diff --git a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientSupport.java b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientSupport.java index 43ff4d48cd3a1..ff27d2635c427 100644 --- a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientSupport.java +++ b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientSupport.java @@ -10,14 +10,16 @@ public class MongoClientSupport { private final List propertyCodecProviders; private final List bsonDiscriminators; private final List connectionPoolListeners; + private final List commandListeners; private final boolean disableSslSupport; public MongoClientSupport(List codecProviders, List propertyCodecProviders, List bsonDiscriminators, - List connectionPoolListeners, boolean disableSslSupport) { + List commandListeners, List connectionPoolListeners, boolean disableSslSupport) { this.codecProviders = codecProviders; this.propertyCodecProviders = propertyCodecProviders; this.bsonDiscriminators = bsonDiscriminators; this.connectionPoolListeners = connectionPoolListeners; + this.commandListeners = commandListeners; this.disableSslSupport = disableSslSupport; } @@ -37,6 +39,10 @@ public List getConnectionPoolListeners() { return connectionPoolListeners; } + public List getCommandListeners() { + return commandListeners; + } + public boolean isDisableSslSupport() { return disableSslSupport; } diff --git a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClients.java b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClients.java index 0d4597651728b..68b720924a6f0 100644 --- a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClients.java +++ b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClients.java @@ -45,6 +45,7 @@ import com.mongodb.connection.ServerSettings; import com.mongodb.connection.SocketSettings; import com.mongodb.connection.SslSettings; +import com.mongodb.event.CommandListener; import com.mongodb.event.ConnectionPoolListener; import io.quarkus.mongodb.impl.ReactiveMongoClientImpl; @@ -255,6 +256,8 @@ private MongoClientSettings createMongoConfiguration(MongoClientConfig config) { CodecRegistries.fromProviders(providers)); settings.codecRegistry(registry); + settings.commandListenerList(getCommandListeners(mongoClientSupport.getCommandListeners())); + config.applicationName.ifPresent(settings::applicationName); if (config.credentials != null) { @@ -405,6 +408,21 @@ private List getPropertyCodecProviders(List class return providers; } + private List getCommandListeners(List classNames) { + List listeners = new ArrayList<>(); + for (String name : classNames) { + try { + Class clazz = Class.forName(name, true, Thread.currentThread().getContextClassLoader()); + Constructor clazzConstructor = clazz.getConstructor(); + listeners.add((CommandListener) clazzConstructor.newInstance()); + } catch (Exception e) { + LOGGER.warnf(e, "Unable to load the command listener class %s", name); + } + } + + return listeners; + } + @PreDestroy public void stop() { for (MongoClient client : mongoclients.values()) {