Using JPA with MongoDB and WildFly

User Rating: 5 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Active
 

These days I'm finishing writing a book about MongoDB and Java. Writing books is my way of learning new things and, in fact, I have learnt pretty at lot cool things about Java and MongoDB. One of these, is the raw power of Hibernate OGM which is a framework that lets you use the power of JPA and Hibernate API with a NoSQL database like MongoDB. To make it fun, we will deploy the JPA MongoDB application on WildFly 8.

First of all some basics. What is Hibernate OGM ? 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 supports a Wide range of backends like MongoDB or Neo4j and has got rich query capabilities such as:

  • Pure JP-QL queries (convert into a native backend query)
  • datastore specific native queries
  • full-text queries, using Hibernate Search as indexing engine

The home of the project is at: http://hibernate.org/ogm/

Building your first Hibernate OGM project.

We will be using a standard Maven webapp-javaee7 project. Most interesting for us is the list of dependencies we need in our project. Let's start with importing the BOMs for the application server and for Hibernate OGM:

<dependencyManagement>
	<dependencies>		
	  
		<dependency>
			<groupId>org.wildfly.bom</groupId>
			<artifactId>jboss-javaee-7.0-with-all</artifactId>
			<version>8.2.0</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>

		<dependency>
			<groupId>org.hibernate.ogm</groupId>
			<artifactId>hibernate-ogm-bom</artifactId>
			<type>pom</type>
			<version>4.2.0.Beta1</version>
			<scope>import</scope>
		</dependency>
	
	</dependencies>
</dependencyManagement>

Done with the BOM, we will add now the libraries needed to run our project:

<dependencies>

	<dependency>
		<groupId>org.hibernate.ogm</groupId>
		<artifactId>hibernate-ogm-mongodb</artifactId>
	</dependency>

	<dependency>
		<groupId>javax.enterprise</groupId>
		<artifactId>cdi-api</artifactId>
		<scope>provided</scope>

	</dependency>

	<dependency>
		<groupId>org.jboss.spec.javax.faces</groupId>
		<artifactId>jboss-jsf-api_2.2_spec</artifactId>
		<scope>provided</scope>

	</dependency>

	<dependency>
		<groupId>org.jboss.spec.javax.ejb</groupId>
		<artifactId>jboss-ejb-api_3.2_spec</artifactId>
		<scope>provided</scope>

	</dependency>

	<dependency>
		<groupId>org.jboss.spec.javax.annotation</groupId>
		<artifactId>jboss-annotations-api_1.2_spec</artifactId>
		<scope>provided</scope>

	</dependency>

</dependencies>

The most interesting for us is the hibernate-ogm-mongodb which handles the interaction with MongoDB. Optionally, you can include the Maven's WildFly plugin:

<build>
	<finalName>${project.artifactId}</finalName>
	<plugins>
		<plugin>
			<groupId>org.wildfly.plugins</groupId>
			<artifactId>wildfly-maven-plugin</artifactId>
			<version>1.0.2.Final</version>
		</plugin>
	</plugins>
</build>

Configuring the database persistence with Hibernate OGM

The main difference compared with a RDBMs approach, is that we won't specify a datasource reference in the persistence.xml file but just a set of properties that will be used to connecto to the MongoDB datastore: 

<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="demomongo"/>
      <property name="hibernate.ogm.datastore.host" value="localhost"/>
      <property name="hibernate.ogm.datastore.provider" value="MONGODB"/>
      <!-- Just in case your DB needs user/name password
            <property name="hibernate.ogm.datastore.username" value="db_user" />
            <property name="hibernate.ogm.datastore.password" value="top_secret!" />
       -->
    </properties>
  </persistence-unit>
</persistence> 

We have added the Property class that will be mapped as an Entity. In the properties, the hibernate.ogm.datastore.database specifies the database to be used (you don't need to create it first.) and hibernate.ogm.datastore.provider specifies the database provider to be used, in our case MONGODB. 

And now the application classes. Here is the EJB that is in charge to handle the persistence:

package com.sample.ejb;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import com.sample.model.Property;
import javax.ejb.Stateless;

@Stateless

public class PropertyManager {

    @PersistenceContext(unitName = "mongo-ogm")
    private EntityManager em;

    
    public void save(Property p) {
        em.persist(p);

    }

    public List<Property> queryCache() {
        Query query = em.createQuery("FROM Property p");

        List<Property> list = query.getResultList();
        return list;
    }

}

In the above example we are using JPA-QL to execute searches. At the time of writing there are some limitations when using the JPA-QL as a limited number of constructs are available namely, you are allowed to execute:

• Basic comparisons using "<", "#", "=", ">=" and ">"

• IS NULL and  IS NOT NULL

• The boolean operators  AND ,  OR ,  NOT

• LIKE ,  IN and  BETWEEN

• ORDER BY

if you prefer, you can use instead native queries in your searches, specifying directly the mongodb dialect in your code. Here is an example:

 public List<Property> queryCache() {

	String query1 = "db.Property.find({'value': 'value1'})";
	Query query = em.createNativeQuery(query1, Property.class);

	List<Property> list = query.getResultList();
	return list;
}

And here is the Property class which is an ordinary Entity which is delegating to the underlying datatabase the creation of the id:

package com.sample.model;

 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;

@Entity
public class Property {

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String id;

    private String key;

    private String value;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

}

 We need some glue between our EJB and the view. Here is the Controller class which is a simple CDI bean:

package com.sample.bean;

import com.sample.ejb.PropertyManager;
import com.sample.model.Property;

import java.util.List;
import javax.annotation.PostConstruct;
import javax.enterprise.inject.Model;

import javax.inject.Inject;

@Model
public class Controller {

    List<Property> propertyList;

    private String key;
    private String value;

    @PostConstruct
    public void readDB() {
        propertyList = ejb.queryCache();

    }
    @Inject
    PropertyManager ejb;

    public void save() {
        Property p = new Property();
        p.setKey(key);
        p.setValue(value);
        ejb.save(p);
        propertyList.add(p);
        key = "";
        value = "";
    }

    public List<Property> getPropertyList() {
        return propertyList;
    }

    public void setPropertyList(List<Property> propertyList) {
        this.propertyList = propertyList;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

}

 Finally, the simple index.xhtml page displaying a form for entering the fields and a datatable:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:c="http://java.sun.com/jsp/jstl/core">
    <h:head>
        <style type="text/css">  
            @import url("css/store.css");
        </style>
    </h:head>
    <h:body>

        <h:form id="jsfexample">
            <h:panelGrid columns="2" styleClass="tablestyle"> 
                <h:outputText value="Hibernate OGM example on WildFly" />
                <br/>
                <h:outputText value="Enter key:" />
                <h:inputText value="#{controller.key}" />

                <h:outputText value="Enter value:" />
                <h:inputText value="#{controller.value}" />

                <h:commandButton actionListener="#{controller.save}"
                                 value="Save key/value" />
            

                <h:messages />


            </h:panelGrid>

            <h:outputText value="No data yet!" rendered="#{empty controller.propertyList}" />
            <br/>

            <h:dataTable value="#{controller.propertyList}" var="item" styleClass="tablestyle" rendered="#{not empty controller.propertyList}">
                <h:column>
                    <f:facet name="header">Key</f:facet>
                    <h:outputText value="#{item.key}" />
                </h:column>
                <h:column>
                    <f:facet name="header">Value</f:facet>
                    <h:outputText value="#{item.value}" />
                </h:column>
            </h:dataTable>
        </h:form>
    </h:body>
</html>

 To compile and deploy the application:

mvn clean install wildfly:deploy

 Here's the application in action with some nice css addicted:

hibernate ogm mongodb

You can check out the full source code of this application here:

https://github.com/fmarchioni/mastertheboss/tree/master/hibernateogm-mongo

Have fun with MongoDB and JPA!

Follow us on Twitter