Java EE 6 and NoSQL/MongoDB on GlassFish using JPA and EclipseLink 2.4 (TOTD #175)


TOTD #166 explained how to use MongoDB in your Java EE 6 applications. The code in that tip used the APIs exposed by the MongoDB Java driver and so requires you to learn a new API. However if you are building Java EE 6 applications then you are already familiar with Java Persistence API (JPA). Eclipse Link 2.4, scheduled to release as part of Eclipse Juno, provides support for NoSQL databases by mapping a JPA entity to a document. Their wiki provides complete explanation of how the mapping is done.

This Tip Of The Day (TOTD) will show how you can leverage that support in your Java EE 6 applications deployed on GlassFish 3.1.2.

Before we dig into the code, here are the key concepts ...
  • A POJO is mapped to a NoSQL data source using @NoSQL or <no-sql> element in "orm.xml".
  • A subset of JPQL and Criteria query are supported, based upon the underlying data store
  • Connection properties are defined in "persistence.xml"
Now, lets lets take a look at the code ...
  1. Download the latest EclipseLink 2.4 Nightly Bundle. There is a Installer, Source, and Bundle - make sure to download the Bundle link (20120410) and unzip.
  2. Download GlassFish 3.1.2 zip and unzip.
  3. Install the Eclipse Link 2.4 JARs in GlassFish
    • Remove the following JARs from "glassfish/modules":
      org.eclipse.persistence.antlr.jar
      org.eclipse.persistence.asm.jar
      org.eclipse.persistence.core.jar
      org.eclipse.persistence.jpa.jar
      org.eclipse.persistence.jpa.modelgen.jar
      org.eclipse.persistence.moxy.jar
      org.eclipse.persistence.oracle.jar
    • Add the following JARs from Eclipse Link 2.4 nightly build to "glassfish/modules":
      org.eclipse.persistence.antlr_3.2.0.v201107111232.jar
      org.eclipse.persistence.asm_3.3.1.v201107111215.jar
      org.eclipse.persistence.core.jpql_2.4.0.v20120407-r11132.jar
      org.eclipse.persistence.core_2.4.0.v20120407-r11132.jar
      org.eclipse.persistence.jpa.jpql_2.0.0.v20120407-r11132.jar
      org.eclipse.persistence.jpa.modelgen_2.4.0.v20120407-r11132.jar
      org.eclipse.persistence.jpa_2.4.0.v20120407-r11132.jar
      org.eclipse.persistence.moxy_2.4.0.v20120407-r11132.jar
      org.eclipse.persistence.nosql_2.4.0.v20120407-r11132.jar
      org.eclipse.persistence.oracle_2.4.0.v20120407-r11132.jar
  4. Start MongoDB
    1. Download latest MongoDB from here (2.0.4 as of this writing).
    2. Create the default data directory for MongoDB as:
      sudo mkdir -p /data/db/
      sudo chown `id -u` /data/db
      Refer to Quickstart for more details.
    3. Start MongoDB as:
      arungup-mac:mongodb-osx-x86_64-2.0.4 <arungup> ->./bin/mongod
      ./bin/mongod --help for help and startup options
      Mon Apr  9 12:56:02 [initandlisten] MongoDB starting : pid=3124 port=27017 dbpath=/data/db/ 64-bit host=arungup-mac.local
      Mon Apr  9 12:56:02 [initandlisten] db version v2.0.4, pdfile version 4.5
      Mon Apr  9 12:56:02 [initandlisten] git version: 329f3c47fe8136c03392c8f0e548506cb21f8ebf
      Mon Apr  9 12:56:02 [initandlisten] build info: Darwin erh2.10gen.cc 9.8.0 Darwin Kernel Version 9.8.0: Wed Jul 15 16:55:01 PDT 2009; root:xnu-1228.15.4~1/RELEASE_I386 i386 BOOST_LIB_VERSION=1_40
      Mon Apr  9 12:56:02 [initandlisten] options: {}
      Mon Apr  9 12:56:02 [initandlisten] journal dir=/data/db/journal
      Mon Apr  9 12:56:02 [initandlisten] recover : no journal files present, no recovery needed
      Mon Apr  9 12:56:02 [websvr] admin web console waiting for connections on port 28017
      Mon Apr  9 12:56:02 [initandlisten] waiting for connections on port 27017
  5. Check out the JPA/NoSQL sample from SVN repository. The complete source code built in this TOTD can be downloaded here.
  6. Create Java EE 6 web app
    1. Create a Java EE 6 Maven web app as:
      mvn archetype:generate
      -DarchetypeGroupId=org.codehaus.mojo.archetypes
      -DarchetypeArtifactId=webapp-javaee6
      -DgroupId=model -DartifactId=javaee-nosql
      -DarchetypeVersion=1.5 -DinteractiveMode=false
    2. Copy the model files from the checked out workspace to the generated project as:
      cd javaee-nosql
      cp -r ~/code/workspaces/org.eclipse.persistence.example.jpa.nosql.mongo/src/model src/main/java
    3. Copy "persistence.xml"
      mkdir src/main/resources
      cp -r ~/code/workspaces/org.eclipse.persistence.example.jpa.nosql.mongo/src/META-INF ./src/main/resources
    4. Add the following dependencies:
      <dependency>
      <groupId>org.eclipse.persistence</groupId>
      <artifactId>org.eclipse.persistence.jpa</artifactId>
      <version>2.4.0-SNAPSHOT</version>
      <scope>provided</scope>
      </dependency>
      <dependency>
      <groupId>org.eclipse.persistence</groupId>
      <artifactId>org.eclipse.persistence.nosql</artifactId>
      <version>2.4.0-SNAPSHOT</version>
      </dependency>
      <dependency>
      <groupId>org.mongodb</groupId>
      <artifactId>mongo-java-driver</artifactId>
      <version>2.7.3</version>
      </dependency>

      The first one is for the EclipseLink latest APIs, the second one is for EclipseLink/NoSQL support, and the last one is the MongoDB Java driver.

      And the following repository:
      <repositories>
      <repository>
      <id>EclipseLink Repo</id>
      <url>http://www.eclipse.org/downloads/download.php?r=1&amp;nf=1&amp;file=/rt/eclipselink/maven.repo</url>
      <snapshots>
      <enabled>true</enabled>
      </snapshots>
      </repository> 
      </repositories>
    5. Copy the "Test.java" to the generated project:
      mkdir src/main/java/example
      cp -r ~/code/workspaces/org.eclipse.persistence.example.jpa.nosql.mongo/src/example/Test.java ./src/main/java/example/
      This file contains the source code to CRUD the JPA entity to MongoDB. This sample is explained in detail on EclipseLink wiki.
    6. Create a new Servlet in "example" directory as:
      package example;

      import java.io.IOException;
      import java.io.PrintWriter;
      import javax.servlet.ServletException;
      import javax.servlet.annotation.WebServlet;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;

      /**
      * @author Arun Gupta
      */
      @WebServlet(name = "TestServlet", urlPatterns = {"/TestServlet"})
      public class TestServlet extends HttpServlet {

      protected void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
      response.setContentType("text/html;charset=UTF-8");
      PrintWriter out = response.getWriter();
      try {
      out.println("<html>");
      out.println("<head>");
      out.println("<title>Servlet TestServlet</title>");
      out.println("</head>");
      out.println("<body>");
      out.println("<h1>Servlet TestServlet at " + request.getContextPath() + "</h1>");
      try {
      Test.main(null);
      } catch (Exception ex) {
      ex.printStackTrace();
      }
      out.println("</body>");
      out.println("</html>");
      } finally {
      out.close();
      }
      }

      @Override
      protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
      processRequest(request, response);
      }

      @Override
      protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
      processRequest(request, response);
      }
      }
  7. Build the project and deploy it as:

    mvn clean package
    glassfish3/bin/asadmin deploy --force=true target/javaee-nosql-1.0-SNAPSHOT.war
  8. Accessing http://localhost:8080/javaee-nosql/TestServlet shows the following messages in the server.log:

    connecting(EISLogin(
    platform=> MongoPlatform
    user name=> ""
    MongoConnectionSpec()
    ))
    . . .

    Connected:
    User:
    Database: 2.7  Version: 2.7

    . . .

    Executing MappedInteraction()
    spec => null
    properties => {mongo.collection=CUSTOMER, mongo.operation=INSERT}
    input => [DatabaseRecord(
    CUSTOMER._id => 4F848E2BDA0670307E2A8FA4
    CUSTOMER.NAME => AMCE)]

    . . .


    Data access result: [{TOTALCOST=757.0, ORDERLINES=[{DESCRIPTION=table,
    LINENUMBER=1, COST=300.0}, {DESCRIPTION=balls, LINENUMBER=2, COST=5.0},
    {DESCRIPTION=rackets, LINENUMBER=3, COST=15.0}, {DESCRIPTION=net,
    LINENUMBER=4, COST=2.0}, {DESCRIPTION=shipping, LINENUMBER=5,
    COST=80.0}, {DESCRIPTION=handling, LINENUMBER=6, COST=55.0},
    {DESCRIPTION=tax, LINENUMBER=7, COST=300.0}], SHIPPINGADDRESS=
    [{POSTALCODE=L5J1H7, PROVINCE=ON, COUNTRY=Canada, CITY=Ottawa,
    STREET=17 Jane St.}], VERSION=2, _id=4F848E2BDA0670307E2A8FA8,
    DESCRIPTION=Pingpong table, CUSTOMER__id=4F848E2BDA0670307E2A8FA7,
    BILLINGADDRESS=[{POSTALCODE=L5J1H8, PROVINCE=ON, COUNTRY=Canada,
    CITY=Ottawa, STREET=7 Bank St.}]}]

    You'll not see any output in the browser, just the output in the console. But the code can be easily modified to do so.

Once again, the complete Maven project can be downloaded here.

Do you want to try accessing relational and non-relational (aka NoSQL) databases in the same PU ?

Comments:

This is awesome! Just what I needed for a project at IQSS

Posted by Bob Treacy on May 22, 2012 at 12:09 PM PDT #

Hi Arun, excellent description - many thanks ! There is an intriguing question at the end :

"Do you want to try accessing relational and non-relational (aka NoSQL) databases in the same PU ?"

That is a subject I would be really interested in, are you working on that article? :-)

Many thanks
Janko

Posted by Janko on June 22, 2012 at 06:44 AM PDT #

Janko,

Glad you liked it!

This was on my list of TODOs and I know somebody else within the team was also looking at it. I've already pinged that person and will let you know if he responds back.

Posted by Arun Gupta on June 22, 2012 at 04:30 PM PDT #

This is great Arun. Thanks greatly for this example. I would really like to see an example for JEE6-mongo persistency with Jboss AS7

Posted by guest on June 29, 2012 at 12:47 PM PDT #

This example has motivated me to remove all the manual MongoDB interaction from my project! I have a question about how the EclipseLink dependency is handled. For the purpose of source/version control and installation simplicity, it is better for me to package all the project dependencies in the war. That way, if it is necessary to reproduce a deployment or troubleshoot an installation, there is no question about what jars have been installed in the customer's application server. Is there a way to get glassfish to correctly find and load EclipseLink without adding the jars directly to the glassfish/modules? Thanks!

Posted by Bob on July 18, 2012 at 04:46 AM PDT #

Hi,Arun
I am just begin doing mongodb. My project needs to be connect Mongodb with JPA,Eclipselink2.4, and run on glassfish.Beside I need to use JSF framework also.
Now I just write about db and it come cross an question.
When it run, it has this problem:
Config: connecting(EISLogin(
platform=> MongoPlatform
user name=> ""
MongoConnectionSpec()
))
Grave: java.lang.NoClassDefFoundError: com/mongodb/ServerAddress

I don't konw why, can you give me some advice?Thanks!

Posted by Yue on August 22, 2012 at 01:47 AM PDT #

Hi,Arun
I am just begin doing mongodb. My project needs to be connect Mongodb with JPA,Eclipselink2.4, and run on glassfish.Beside I need to use JSF framework also.
Now I just write about db and it come cross an question.
When it run, it has this problem:
Config: connecting(EISLogin(
platform=> MongoPlatform
user name=> ""
MongoConnectionSpec()
))
Grave: java.lang.NoClassDefFoundError: com/mongodb/ServerAddress

I don't konw why, can you give me some advice?Thanks!

Posted by guest on August 22, 2012 at 02:17 AM PDT #

Want to handle your registered users in MongoDB?
You might want to check out my Camofish module for Glassfish and MongoDB.
More information here: http://4thex.com/products/camofish/camofish.xhtml

Posted by guest on September 02, 2012 at 07:54 AM PDT #

Before starting an important project with those technologies, you have to know that there is many limitations which makes the solution unusable in a professional way.
EclipseLink nosql won't transform MongoDB to a relational DB. That's evident but you it means that you can't do JPQL like this :
TypedQuery<AttachmentRequest> q = em.createQuery("Select ar from AttachmentRequest ar join ar.emitterAccount em where em.id=:emitterId", AttachmentRequest.class);

Cf. http://www.eclipse.org/forums/index.php/t/453373/

Other important point to notice is that nativeQuery are very limitated. You can only do findOne request. Find, aggregation does not work.
Cf. http://www.eclipse.org/forums/index.php/m/1009524/#msg_1009524

All this limitations makes the use of this technologies very frustating and inefficient.

JM

Posted by jmcollin92 on February 15, 2013 at 01:37 AM PST #

Hi Arun,

referring to my previous comment regarding relational and non-relational databases in the same PU, this has slipped a little off my radar but is back on now.
Was wondering if have given this subject more thought or even have practical experience you could share.

Many thanks
Janko

Posted by Janko on July 16, 2013 at 05:52 AM PDT #

Post a Comment:
Comments are closed for this entry.
About

profile image
Arun Gupta is a technology enthusiast, a passionate runner, author, and a community guy who works for Oracle Corp.


Java EE 7 Samples

Stay Connected

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today