3 ways you can connect to MongoDB from WildFly – JBoss EAP

In this updated tutorial we will learn some possible ways to use MongoDB NoSQL Database from within an application server like WildFly or JBoss EAP.

1) Using the MongoDB Java Driver

The most common way to connect to MongoDB from Java applications is by means of the MongoDB Java Driver which provides a simple and clean interface to perform CRUD operations and advanced searches on your MongoDB documents. This driver also includes a standalone BSON library that you can use to build high-performance encoders and decoders without requiring an intermediate Map instance. Finally, the MongoDB Java Driver also fully implements the Reactive Streams API for providing interop with other reactive streams within the JVM ecosystem.

Installing the MongoDB Java Driver

You can either install MongoDB Java Driver as a WildFly Module, or package it within your application.

To install the MongoDB Java driver as a Module, download it from here first: https://mongodb.github.io/mongo-java-driver/

Then, you can install it from the Command Line as follows:

module add --name=com.mongodb --dependencies="javax.api" --resources=mongo-java-driver-3.12.7.jar

And reference it within jboss-deployment-structure.xml:

<jboss-deployment-structure>
   <deployment>
      <dependencies>
         <module name="com.mongodb" />
      </dependencies>
   </deployment>
</jboss-deployment-structure>

The other option is to package the MongoDB Java Driver along with your application:

  <dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongo-java-driver</artifactId>
    <version>${mongodb.driver.version}</version>
  </dependency>

Then, include the MongoDB Driver Version in your Maven Properties:

<mongodb.driver.version>3.12.7</mongodb.driver.version>

Coding a sample CRUD REST Application with MongoDB

As a proof of concept, we will now create a REST Application which uses MongoDB Java Driver to perform CRUD Operations. As we will be using CDI to produce MongoDB objects, the core class is MongoDBProducer which can be used to bootstrap the MongoDatabase:

import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoDatabase;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;

@ApplicationScoped
public class MongoDBProducer {

    @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();
    }
}

As we are now able to produce the com.mongodb.client.MongoDatabase, we can inject it into a Service class which performs the actual CRUD operations:

import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import org.bson.conversions.Bson;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;

import static com.mongodb.client.model.Filters.eq;
import static com.mongodb.client.model.Updates.set;

@ApplicationScoped
public class CustomerService {

    @Inject
    MongoDatabase mongoDB;

    public List<Customer> list(){
        List<Customer> list = new ArrayList<>();
        MongoCursor<Document> cursor = getCollection().find().iterator();

        try {
            while (cursor.hasNext()) {
                Document document = cursor.next();
                Customer customer = new Customer();
                customer.setSurname(document.getString("surname"));
                customer.setName(document.getString("name"));
                customer.setId(document.getLong("id"));
                list.add(customer);
            }
        } finally {
            cursor.close();
        }
        return list;
    }

    public void add(Customer customer){
        Document document = new Document()
                .append("name", customer.getName())
                .append("surname", customer.getSurname())
                .append("id", customer.getId());
        getCollection().insertOne(document);
    }

    public void update(Customer customer){
        // update one document

        Bson filter = eq("id", customer.getId());
        Bson updateOperation = set("name", customer.getName());
        getCollection().updateOne(filter, updateOperation);
    }

    public void delete(Customer customer){
        // delete one document

        Bson filter = eq("id", customer.getId());
        getCollection().deleteOne(filter);
    }
    private MongoCollection getCollection(){
        return mongoDB.getCollection("customers");
    }
}

The rest of the application is trivial. We will add a REST Endpoint to perform the CRUD operations:

import javax.inject.Inject;

import javax.ws.rs.*;
import java.util.List;

@Path("/customer")
@Produces("application/json")
@Consumes("application/json")
public class CustomerEndpoint {

    @Inject CustomerService service;

    @GET
    public List<Customer> list() {
        return service.list();
    }

    @POST
    public List<Customer> add(Customer customer) {
        service.add(customer);
        return list();
    }

    @PUT
    public List<Customer> put(Customer customer) {
        service.update(customer);
        return list();
    }

    @DELETE
    public List<Customer> delete(Customer customer) {
        service.delete(customer);
        return list();
    }
}

That’s all. In order to start MongoDB you can download the latest Community version from: https://www.mongodb.com/try/download/community

To simplify things, we will start MongoDB using Docker with just one line:

docker run -ti --rm -p 27017:27017 mongo:4.0

When MongoDB is running, we can simply build and deploy it on WildFly with:

mvn install wildfly:deploy

Now you can test it, for example adding one Document with:

curl -d '{"id":"1", "name":"Frank", "surname":"Smith"}' -H "Content-Type: application/json" -X POST http://localhost:8080/mongoclient-wildfly/rest/customer

We can then retrieve it as follows:

curl http://localhost:8080/mongoclient-wildfly/rest/customer

The full source code for this example is available here: https://github.com/fmarchioni/mastertheboss/tree/master/nosql/mongodb/mongoclient-wildfly

2) Using Hibernate OGM to map MongoDB

Hibernate Object/Grid Mapper (OGM) is a framework which provides Java Persistence (JPA) support for NoSQL solutions. It reuses Hibernate ORM’s engine but persists entities into a NoSQL datastore instead of a relational database. This means you will be writing pure JPA code, which will be handled behind the scenes, by the OGM Engine.

Hibernate OGM talks to NoSQL backends via store-specific dialects. The main repository includes the following dialects:

  • Key/Value: Infinispan (embedded and remote)
  • Document: MongoDB
  • Graph: Neo4j (embedded and remote)

In order to use Hibernate OGM to wrap your NoSQL database, you can just add the hibernate-ogm BOM to your project and then the specific store dialect, such as mongodb:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.hibernate.ogm</groupId>
            <artifactId>hibernate-ogm-bom</artifactId>
            <version>5.4.1.Final</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>jakarta.platform</groupId>
        <artifactId>jakarta.jakartaee-api</artifactId>
        <scope>provided</scope>
        <version>${jakartaee.version}</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.ogm</groupId>
        <artifactId>hibernate-ogm-mongodb</artifactId>
    </dependency>
</dependencies>

Then, you can use the persistence.xml file just like any JPA application to point to your MongoDB Database:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="mongo-ogm" transaction-type="JTA">
    <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
    <class>com.sample.model.Property</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
      <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"/>
      <property name="hibernate.ogm.datastore.database" value="wildfly"/>
      <property name="hibernate.ogm.datastore.host" value="localhost"/>
      <property name="hibernate.ogm.datastore.provider" value="MONGODB"/>
      <property name="hibernate.ogm.datastore.create_database" value="true" />
    </properties>
  </persistence-unit>
</persistence>

You can find a full example and learn more about Hibernate OGM and MongoDB on this tutorial: https://www.mastertheboss.com/javaee/mongodb/using-jpa-with-mongodb-and-wildfly

3) Using Teiid Data Virtualization (deprecated)

The first solution that we will show is Teiid Data Virtualization platform.(The enterprise version of Teiid is called JBoss Data Virtualization platform). Teiid leverages different data sources by means of its Translator component which defines the Connections setting to the data source. In our case, edit the /standalone/configuration/standalone-teiid.xml and include under the “resource-adaptor” subsystem the correct configuration for mongodb:

  <resource-adapters>   
   <resource-adapter id="mongodb">   
    <module slot="main" id="org.jboss.teiid.resource-adapter.mongodb"/>   
    <transaction-support>NoTransaction</transaction-support>   
    <connection-definitions>   
     <connection-definition class-name="org.teiid.resource.adapter.mongodb.MongoDBManagedConnectionFactory"   
       jndi-name="java:/mongoDS"   
       enabled="true"   
       use-java-context="true"   
       pool-name="teiid-mongodb-ds">   
      <!-- MongoDB server list (host:port[;host:port...]) -->   
      <config-property name="RemoteServerList">localhost:27017</config-property>   
      <!-- Database Name in the MongoDB -->   
      <config-property name="Database">test</config-property>   
       <!--    
        Uncomment if your DB is password protected   
       <config-property name="Username">user</config-property>   
       <config-property name="Password">password</config-property>   
       -->    
     </connection-definition>   
    </connection-definitions>   
   </resource-adapter>   
  </resource-adapters>  

The above configuration will create a JCA connection pool to the MongoDB. Save it and start Teeid:

JBOSS_HOME/bin/standalone.sh -c standalone-teiid.xml

Now it is time to create VDB. A Virtual Database definition (VDB) is the primary means to define a connection towards a set of data. The following shows a very simple VDB file which refers to the translator-name and connection-jndi-name:

 <vdb name="MongoQuery" version="1">  
   <model name="MongoQuery">  
     <source name="local" translator-name="mongodb" connection-jndi-name="java:/mongoDS"/>  
       <metadata type="DDL"><![CDATA[  
         CREATE FOREIGN TABLE User (  
           user_id integer,  
           Name varchar(25),  
           Surname varchar(25)  
         ) OPTIONS(UPDATABLE 'TRUE');  
       ]]> </metadata>  
   </model>  
 <vdb>  

Save the the mongodb-vdb.xml in the deployments folder of the application server. In order to test our model, we can use a sample client which is available in the teiid examples quickstart. The sampleclient contains a JDBCClient.java example code that shows a developer the basic connection logic that can be used to connect to a Teiid instance running in a JBoss AS server.

To execute a sql query using the simpleclient, use the following format:

mvn install -Dvdb="MongoQuery" -Dsql="INSERT INTO User(user_id, Name, Surname) VALUES (1, 'Franky', 'Garage');"

This will produce a document like below in the MongoDB database:

{  
  _id: ObjectID("f4948509a8fb2f3bd2f983a0"),  
  user_id: 1,  
  Name: "Franky",  
  Surname: "Garage"  
 }  
Found the article helpful? if so please follow us on Socials