Access any version of MongoDB with Open Liberty using CDI
Using MongoDB with Open Liberty previously meant enabling the mongodb-2.0
feature and configuring several elements in server.xml
, but was limited to certain versions of MongoDB. Now, with improvements in CDI and the introduction of MicroProfile Config, you can easily configure access to any version of MongoDB with a CDI producer (for an introduction to using CDI producers, see the Injecting Dependencies into Microservices guide).
A CDI producer for MongoDB
With a CDI producer, you are no longer restricted to MongoDB 2.X versions, and can easily provide a MongoDatabase to your application. This example demonstrates how to create a CDI producer to inject a MongoDatabase:
@ApplicationScoped
public class MongoProducer {
@Produces
public MongoClient createMongo() {
return new MongoClient(new ServerAddress(), new MongoClientOptions.Builder().build());
}
@Produces
public MongoDatabase createDB(MongoClient client) {
return client.getDatabase("testdb");
}
public void close(@Disposes MongoClient toClose) {
toClose.close();
}
}
Here is an example of using the CDI producer to inject a MongoDatabase in a JAX-RS application:
@Inject
MongoDatabase db;
@POST
@Path("/add")
@Consumes(MediaType.APPLICATION_JSON)
public void add(CrewMember crewMember) {
MongoCollection<Document> crew = db.getCollection("Crew");
Document newCrewMember = new Document();
newCrewMember.put("Name",crewMember.getName());
newCrewMember.put("Rank",crewMember.getRank());
newCrewMember.put("CrewID",crewMember.getCrewID());
crew.insertOne(newCrewMember);
}
Enhancing the CDI producer
One of the advantages of using a CDI producer is that it can be tailored to your needs. For improved security, the createMongo
method can be enhanced to include authentication with a user name and an encoded password:
@Produces
public MongoClient createMongo() {
String password = PasswordUtil.passwordDecode(encodedPass);
MongoCredential creds = MongoCredential.createCredential(user, dbName, password.toCharArray());
return new MongoClient(new ServerAddress(), creds, new MongoClientOptions.Builder().build());
}
This requires passwordUtilities-1.0
, available as a Maven dependency:
<dependency>
<groupId>io.openliberty.features</groupId>
<artifactId>passwordUtilities-1.0</artifactId>
<version>18.0.0.4</version>
</dependency>
You also need to enable the feature in server.xml
:
<feature>passwordUtilities-1.0</feature>
You can go further and enable SSL, changing the createMongo
method to look something like this:
@Produces
public MongoClient createMongo() throws SSLException {
String password = PasswordUtil.passwordDecode(encodedPass);
MongoCredential creds = MongoCredential.createCredential(user, dbName, password.toCharArray());
SSLContext sslContext = JSSEHelper.getInstance().getSSLContext("defaultSSLConfig", Collections.emptyMap(), null);
return new MongoClient(new ServerAddress(hostname, port), creds, new MongoClientOptions.Builder()
.sslEnabled(true)
.sslContext(sslContext)
.build());
}
Configure with MicroProfile Config
Now that you have a more advanced CDI producer, it would be nice to add configurability to some of the variables, like the user and password. Using MicroProfile Config makes configuring the MongoDB driver simple. You can add the following to your CDI producer to add configuration:
@Inject
@ConfigProperty(name = "mongo.hostname", defaultValue = "localhost")
String hostname;
@Inject
@ConfigProperty(name = "mongo.port", defaultValue = "27017")
int port;
@Inject
@ConfigProperty(name = "mongo.dbname", defaultValue = "testdb")
String dbName;
@Inject
@ConfigProperty(name = "mongo.user")
String user;
@Inject
@ConfigProperty(name = "mongo.pass.encoded")
String encodedPass;
Now, by placing the following snippet in your microprofile-config.properties
or server.env
file, the values for
user and encodedPass will be pulled into the MongoProducer class:
mongo.user=sampleUser
mongo.pass.encoded={aes}APtt+/vYxxPa0jE1rhmZue9wBm3JGqFK3JR4oJdSDGWM1wLr1ckvqkqKjSB2Voty8g==
No need for a MongoDB feature
Previously, using MongoDB required enabling the mongodb-2.0
feature, which was limited to certain
MongoDB 2.X versions. By using a CDI producer, any version of MongoDB can be used, with no need for a specific MongoDB feature. Even if the MongoDB Java Driver API changes, simple updates to your CDI producer will allow it to continue to work.
You should remove the mongodb-2.0
feature from your server.xml
when using newer versions of MongoDB with a CDI producer.
The MongoDB driver should be bundled in your application. To do this with Maven you can use a dependency:
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>X.X.X</version>
</dependency>
If you have multiple applications accessing MongoDB, instead of bundling the MongoDB driver,
you can configure a shared library in your server.xml
like this:
<library id="MongoLib">
<file name="${shared.resource.dir}/mongo-java-driver-3.8.0.jar" />
</library>
<webApplication location="MongoDBSample1.war">
<classloader commonLibraryRef="MongoLib" />
</webApplication>
<webApplication location="MongoDBSample2.war">
<classloader commonLibraryRef="MongoLib" />
</webApplication>
This illustrates how easy it is to create a CDI producer for MongoDB, configure it with MicroProfile Config, and use it to access a MongoDatabase in your application. The full sample is available on GitHub here: https://github.com/OpenLiberty/sample-mongodb