Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set a injected CDI CommandListener to the mongodb configuration. #12082

Merged
merged 2 commits into from
Oct 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> bsonDiscriminatorClassNames;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> codecProviderClassNames;
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
gsmet marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add some Javadoc to this class? This is necessary for the All Build Items page


private List<String> commandListenerClassNames;

public CommandListenerBuildItem(List<String> commandListenerClassNames) {
this.commandListenerClassNames = commandListenerClassNames;
}

public List<String> getCommandListenerClassNames() {
return commandListenerClassNames;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<MongoClient> client;
private final RuntimeValue<ReactiveMongoClient> reactive;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -91,12 +92,22 @@ BsonDiscriminatorBuildItem collectBsonDiscriminators(CombinedIndexBuildItem inde
}

@BuildStep
List<ReflectiveClassBuildItem> addCodecsAndDiscriminatorsToNative(CodecProviderBuildItem codecProviders,
PropertyCodecProviderBuildItem propertyCodecProviders, BsonDiscriminatorBuildItem bsonDiscriminators) {
CommandListenerBuildItem collectCommandListeners(CombinedIndexBuildItem indexBuildItem) {
Collection<ClassInfo> commandListenerClasses = indexBuildItem.getIndex()
.getAllKnownImplementors(DotName.createSimple(CommandListener.class.getName()));
List<String> names = commandListenerClasses.stream().map(ci -> ci.name().toString()).collect(Collectors.toList());
return new CommandListenerBuildItem(names);
}

@BuildStep
List<ReflectiveClassBuildItem> addExtensionPointsToNative(CodecProviderBuildItem codecProviders,
PropertyCodecProviderBuildItem propertyCodecProviders, BsonDiscriminatorBuildItem bsonDiscriminators,
CommandListenerBuildItem commandListeners) {
List<String> 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))
Expand Down Expand Up @@ -160,6 +171,7 @@ void build(
CodecProviderBuildItem codecProvider,
PropertyCodecProviderBuildItem propertyCodecProvider,
BsonDiscriminatorBuildItem bsonDiscriminator,
CommandListenerBuildItem commandListener,
List<MongoConnectionPoolListenerBuildItem> connectionPoolListenerProvider,
BuildProducer<MongoConnectionNameBuildItem> mongoConnections,
BuildProducer<SyntheticBeanBuildItem> syntheticBeanBuildItemBuildProducer,
Expand All @@ -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());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@

import io.quarkus.builder.item.MultiBuildItem;

/**
* Register additional {@link ConnectionPoolListener}s.
*/
public final class MongoConnectionPoolListenerBuildItem extends MultiBuildItem {

private Supplier<ConnectionPoolListener> connectionPoolListener;

public MongoConnectionPoolListenerBuildItem(Supplier<ConnectionPoolListener> connectionPoolListener) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> propertyCodecProviderClassNames;
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String> EVENTS = new ArrayList<>();

@Override
public void commandStarted(CommandStartedEvent startedEvent) {
EVENTS.add(startedEvent.getCommandName());
}

}
Original file line number Diff line number Diff line change
@@ -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")));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,19 @@
public class MongoClientRecorder {

public Supplier<MongoClientSupport> mongoClientSupportSupplier(List<String> codecProviders,
List<String> propertyCodecProviders, List<String> bsonDiscriminators,
List<String> propertyCodecProviders, List<String> bsonDiscriminators, List<String> commandListeners,
List<Supplier<ConnectionPoolListener>> connectionPoolListenerSuppliers, boolean disableSslSupport) {

return new Supplier<MongoClientSupport>() {
@Override
public MongoClientSupport get() {

List<ConnectionPoolListener> connectionPoolListeners = new ArrayList<>(connectionPoolListenerSuppliers.size());
for (Supplier<ConnectionPoolListener> item : connectionPoolListenerSuppliers) {
connectionPoolListeners.add(item.get());
}

return new MongoClientSupport(codecProviders, propertyCodecProviders, bsonDiscriminators,
return new MongoClientSupport(codecProviders, propertyCodecProviders, bsonDiscriminators, commandListeners,
connectionPoolListeners, disableSslSupport);
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ public class MongoClientSupport {
private final List<String> propertyCodecProviders;
private final List<String> bsonDiscriminators;
private final List<ConnectionPoolListener> connectionPoolListeners;
private final List<String> commandListeners;
private final boolean disableSslSupport;

public MongoClientSupport(List<String> codecProviders, List<String> propertyCodecProviders, List<String> bsonDiscriminators,
List<ConnectionPoolListener> connectionPoolListeners, boolean disableSslSupport) {
List<String> commandListeners, List<ConnectionPoolListener> connectionPoolListeners, boolean disableSslSupport) {
this.codecProviders = codecProviders;
this.propertyCodecProviders = propertyCodecProviders;
this.bsonDiscriminators = bsonDiscriminators;
this.connectionPoolListeners = connectionPoolListeners;
this.commandListeners = commandListeners;
this.disableSslSupport = disableSslSupport;
}

Expand All @@ -37,6 +39,10 @@ public List<ConnectionPoolListener> getConnectionPoolListeners() {
return connectionPoolListeners;
}

public List<String> getCommandListeners() {
return commandListeners;
}

public boolean isDisableSslSupport() {
return disableSslSupport;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -255,6 +256,8 @@ private MongoClientSettings createMongoConfiguration(MongoClientConfig config) {
CodecRegistries.fromProviders(providers));
settings.codecRegistry(registry);

settings.commandListenerList(getCommandListeners(mongoClientSupport.getCommandListeners()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe call this one commandListeners?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this suggestion.

  • The settings class is from mongodb driver (com.mongodb.MongoClientSettings.Builder)
  • The MongoClientSupport class has all its fields exposed to getter methods
  • The private method getCommandListeners is called after the same naming pattern as the getCodeProviders method.

It could be ... extracting the call to the getter function to a variable called commandListeners (very likely to happen in a future PR). For example:

List<CommandListeners> commandListeners = getCommandListeners(mongoClientSupport.getCommandListeners());
settings.commandListenerList(commandListeners);


config.applicationName.ifPresent(settings::applicationName);

if (config.credentials != null) {
Expand Down Expand Up @@ -405,6 +408,21 @@ private List<PropertyCodecProvider> getPropertyCodecProviders(List<String> class
return providers;
}

private List<CommandListener> getCommandListeners(List<String> classNames) {
List<CommandListener> 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()) {
Expand Down