How to enable ssl in reactive mongodb client in spring boot? - mongodb

I am currently running into an issue while creating a reactive mongoclient when I provide the URL with ssl=true option.
I am creating configuration class in spring boot where I create Reactive mongoclient using the following option:
MongoClients.create(Connections ring Conn)
Here when I try to connect to a DB with no ssl settings it works, but with ssl enabled option I am getting error saying NettyEventLoop class is not found.
Can anyone suggest what I can do to fix this issue

It seems that the API has changed, so since MongoDB driver v3.8, the method is "applyToSslSettings":
import com.mongodb.Block;
import com.mongodb.connection.SslSettings;
import com.mongodb.connection.SslSettings.Builder;
import com.mongodb.connection.netty.NettyStreamFactoryFactory;
import io.netty.channel.nio.NioEventLoopGroup;
#Configuration
public class Config {
private NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
#Bean
public MongoClientSettingsBuilderCustomizer sslCustomizer() {
Block<SslSettings.Builder> sslSettingsBlock = new Block<SslSettings.Builder>() {
#Override
public void apply(Builder t) {
t.applySettings(SslSettings.builder()
.enabled(true)
.invalidHostNameAllowed(true)
.build());
}
};
return clientSettingsBuilder -> clientSettingsBuilder
.applyToSslSettings(sslSettingsBlock)
.streamFactoryFactory(NettyStreamFactoryFactory.builder()
.eventLoopGroup(eventLoopGroup).build());
}
#PreDestroy
public void shutDownEventLoopGroup() {
eventLoopGroup.shutdownGracefully();
}
}

I was able to overcome this issue by configuring MongoClientSettingsBuilderCustomizer and NioEventLoop Group.
Please find below the code:
private NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
#Bean
public MongoClientSettingsBuilderCustomizer sslCustomizer() {
return clientSettingsBuilder -> clientSettingsBuilder
.sslSettings(SslSettings.builder()
.enabled(true)
.invalidHostNameAllowed(true)
.build())
.streamFactoryFactory(NettyStreamFactoryFactory.builder()
.eventLoopGroup(eventLoopGroup).build());
}

Related

R2DBC cannot create statement for notifications

I am trying to receive asynchronous notifications from postgresql and r2dbc
I use reactivestream and postgres driver but i cannot make statement
I am new to java and reactivestream, i don't to use a framework like spring.
thank you guys
package com.poc.r2dbc_listen;
import io.r2dbc.postgresql.*;
import io.r2dbc.spi.*;
import org.reactivestreams.*;
import reactor.core.publisher.Flux;
public class R2dbc_listen {
public static void main(String[] args) {
PostgresqlConnectionFactory connectionFactory = new PostgresqlConnectionFactory(PostgresqlConnectionConfiguration.builder()
.host("127.0.0.1")
.port(5442)
.username("postgres")
.password("psswd")
.database("database")
.build());
Publisher<? extends Connection> connectionPublisher = connectionFactory.create();
Flux<Notification> listen = connectionPublisher.createStatement("LISTEN mymessage")
.execute()
.flatMap(PostgresqlResult::getRowsUpdated)
.thenMany(receiver.getNotifications());
}
}
It works:
private void listen() {
connection = Mono.from(connectionFactory.create())
.cast(PostgresqlConnection.class)
.block(Duration.ofSeconds(10));
connection.createStatement("LISTEN channel")
.execute()
.flatMap(PostgresqlResult::getRowsUpdated)
.subscribe();
connection.getNotifications()
.delayElements(Duration.ofSeconds(1))
.subscribe(System.out::println);
}

Spring data MongoDB change stream with multiple application instances

I have a springboot with   springdata  mongodb application where I am connecting to mongo change stream to save the changes to a audit collection.  My application is running multiple instances (2 instances) and will be scaled up to n number instances when the load increased.   When records are created in the original collection (“my collection”), the listeners will be triggered in all running instances and creates duplicate records.  Following is my setup
build.gradle
…
// spring data mingodb version 3.1.5
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
…
Listener config
#Configuration
#Slf4j
public class MongoChangeStreamListenerConfig {
#Bean
MessageListenerContainer changeStreamListenerContainer(
MongoTemplate template,
PartyConsentAuditListener consentAuditListener,
ErrorHandler errorHandler) {
MessageListenerContainer messageListenerContainer =
new MongoStreamListenerContainer(template, errorHandler);
ChangeStreamRequest<PartyConsentEntity> request =
ChangeStreamRequest.builder(consentAuditListener)
.collection("my-collection")
.filter(newAggregation(match(where("operationType").in("insert", "update", "replace"))))
.fullDocumentLookup(FullDocument.UPDATE_LOOKUP)
.build();
messageListenerContainer.register(request, MyEntity.class, errorHandler);
log.info("mongo stream listener is registered");
return messageListenerContainer;
}
#Bean
ErrorHandler getLoggingErrorHandler() {
return new ErrorHandler() {
#Override
public void handleError(Throwable throwable) {
log.error("error in creating audit records {}", throwable);
}
};
}
}
Listener container
public class MongoStreamListenerContainer extends DefaultMessageListenerContainer {
public MongoStreamListenerContainer(MongoTemplate template, ErrorHandler errorHandler) {
super(template, Executors.newFixedThreadPool(15), errorHandler);
}
#Override
public boolean isAutoStartup() {
return true;
}
}
ChangeListener
#Component
#Slf4j
#RequiredArgsConstructor
/**
* This class will listen to mongodb change stream and process changes. The onMessage will triggered
* when a record added, updated or replaced in the mongo db.
*/
public class MyEntityAuditListener
implements MessageListener<ChangeStreamDocument<Document>, MyEntity> {
#Override
public void onMessage(Message<ChangeStreamDocument<Document>, MyEntity > message) {
var update = message.getBody();
log.info("db change event received");
if (update != null) {
log.info("creating audit entries for id {}", update.getId());
// This will execute in all the instances and creating duplicating records
}
}
}
Is there a way to control the execution on one instance at a given time and share the load between nodes?. It would be really nice to know if there is a config from spring data mongodb to control the flow.
Also, I have checked the following post in stack overflow and I am not sure how to use this with spring data.
Mongo Change Streams running multiple times (kind of): Node app running multiple instances
Any help or tip to resolve this issue is highly appreciated. Thank you very much in advance.

How can I know Mongodb query runs on which node?

When connecting to a MongoDB replication cluster, I want to know which node the query runs on.
I tried to use explain() in mongo shell, but the Java driver doesn't seem to support this command.
How can I achieve this using MongoDB Java Driver?
You can try utilizing Command Monitoring from MongoDB Java Driver;
public class CustomCommandListener implements CommandListener {
#Override
public void commandStarted(final CommandStartedEvent event) {
System.out.println(String.format("Sent command '%s:%s' with id %s to database" +
" '%s' on connection '%s' to server '%s'",
event.getCommandName(),
event.getCommand().get(event.getCommandName()),
event.getRequestId(),
event.getDatabaseName(),
event.getConnectionDescription().getConnectionId(),
event.getConnectionDescription().getServerAddress()));
}
#Override
public void commandSucceeded(CommandSucceededEvent event) {
//ignore
}
#Override
public void commandFailed(CommandFailedEvent event) {
//ignore
}
}
There are also CommandSucceededEvent and CommandFailedEvent, but regardless of its result, you can get some details with the CommandStartedEvent as above.
Then pass this custom listener into your MongoClient settings;
ClusterSettings clusterSettings = ClusterSettings.builder().hosts(hostList).build();
MongoClientSettings settings = MongoClientSettings.builder()
.addCommandListener(new CustomCommandListener())
.clusterSettings(clusterSettings)
// other settings
.build();
MongoClient client = MongoClients.create(settings);
More on MongoDB Java Driver docs

REST API script taking longer time to execute

I am new to API automation. When trying to execute the basic script in selenium I am getting the below error. Can some one please help me with it.
package GetRequest;
import static io.restassured.RestAssured.given;
import io.restassured.RestAssured;
public class trying {
public static void main(String[] args) {
// base url
RestAssured.baseURI="https://maps.googleapis.com";
given().
param("location","-33.8670522,151.1957362").
param("radius","1500").
param("Key","AIzaSyBBuJ-3wBy1VKGUMtNqO8PpAHWGESIItAo").
when().
get("/maps/api/place/nearbysearch/json").
then().
assertThat().statusCode(200);
}
}
What is the port you are connecting at ? Have you specified that somewhere ? Are you using proxy ?
Why not try something like?
#BeforeClass
public void setProxy()
{
System.setProperty("http.proxyHost", YOUR_PROXY_HOST_HERE);
System.setProperty("http.proxyPort", YOUR_PROXY_PORT_HERE);
}

LoggingFeature is not working

I am using jersey rest api (JAX-RS) of 2.25.1 version. I tried to use LoggingFeature class at server side and as well as client side.
Client side code:
public static void getOperation() {
ClientConfig config = new ClientConfig();
config.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_CLIENT, LoggingFeature.Verbosity.PAYLOAD_ANY);
config.register(new LoggingFeature(logger, LoggingFeature.Verbosity.PAYLOAD_ANY));
Client client = ClientBuilder.newClient(config);
client.register(ClientEmpReqFilter.class);
client.register(ClientEmpResFilter.class);
WebTarget target = client.target("http://localhost:8080").path("restappln/rest/entity");
String str = target.request(MediaType.APPLICATION_JSON).get(String.class);
System.out.println(str);
}
and Server-side code is :
#ApplicationPath("/rest")
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("<package name>");
register(LoggingFeature.class);
}
}
I am not able to get logging. I am passing instance of java.util.Logger to the contructor of client config.
config.register(new LoggingFeature(logger, LoggingFeature.Verbosity.PAYLOAD_ANY));