About Markus Eisele

Markus is a principal technology consultant working for msg systems ag in Germany. Markus is a software architect, developer and consultant. He also writes for IT magazines. Markus is speaking at different conferences about his favorite topics. He is also part of the Java EE 7 expert group.

Polyglot Persistence: EclipseLink with MongoDB and Derby

Polyglot persistence has been in the news since some time now. Kicked off by the famous Fowler post from end 2011 I see more an more nice ideas coming up. Latest one was a company internal student project in which we used Scala as a backend persisting data into MongoDB, Derby and Solar. I’m not a big fan of Scala and remembered EclipseLink’s growing support for NoSQL databases. Given that I simply had to try this.

Where to start?

The biggest issue are the missing examples. You find quite a bit stuff about how to change the data-containers (either NoSQL or RDBMS) with EclipseLink but you will not find a single one which exactly uses both technologies seamlessly. Thanks to Shaun Smith and Gunnar Wagenkrnecht we have this great JavaOne talk about Polyglot Persistence: EclipseLink JPA for NoSQL, Relational, and Beyond which talks exactly about this. Unfortunately the sources still haven’t been pushed anywhere and I had to rebuild this from the talk.So, credits go to Shaun and Gunnar for this.

The magic solution is called Persistence Unit Composition. You need one persistence unit for every data container. That looks like the following basic example. You have a couple of entities in each PU and a composite PU is the umbrella.


 
Let’s go

You should have MongoDB in place before you’re going to start this little tutorial example. Fire up NetBeans and create two java projects. Lets call them polyglot-persistence-nosql-pu and polyglot-persistence-rational-pu. Put the following entities into the nosql-pu: Customer, Address, Order and OrderLine. (Mostly taken from the
EclipseLink nosql examples) and put a Product entity into the rational-pu.

The single products go into Derby while all the other entities persist into MongoDB. The interesting part is, where OrderLine has a One-to-One relation to a Product:

@OneToOne(cascade = {CascadeType.REMOVE, CascadeType.PERSIST})
private Product product;

This is the point where both worlds come together. More on that later.

Both PUs need to be transaction-type=’RESOURCE_LOCAL’ and need to contain the following line in the persistence.xml:

 <property name='eclipselink.composite-unit.member' value='true'/>

Don’t forget to add the db specific configuration. For MongoDB this is

<property name='eclipselink.nosql.property.mongo.port' value='27017'/>
<property name='eclipselink.nosql.property.mongo.host' value='localhost'/>
<property name='eclipselink.nosql.property.mongo.db' value='mydb'/>

For derby this is something like this:

<property name='javax.persistence.jdbc.url' value='jdbc:derby://localhost:1527/mydb'/>
<property name='javax.persistence.jdbc.password' value='sa'/>
<property name='javax.persistence.jdbc.driver' value='org.apache.derby.jdbc.ClientDriver'/>
<property name='javax.persistence.jdbc.user' value='sa'/>

Now we need something to link those two PUs together. The combined-pu resides in a sample polyglot-persistence-web module and looks like this:

<persistence-unit name='composite-pu' transaction-type='RESOURCE_LOCAL'>
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
     <jar-file>\lib\polyglot-persistence-rational-pu-1.0-SNAPSHOT.jar</jar-file>
     <jar-file>\lib\polyglot-persistence-nosql-pu-1.0-SNAPSHOT.jar</jar-file>
      <properties>
            <property name='eclipselink.composite-unit' value='true'/>
        </properties>
</persistence-unit>
</persistence>

Watch out for the jar-file path. We are going to package this in a war-archive and because of this, the nosql-pu and the rational-pu will go into WEB-INF/lib folder. As you can see, my example is build with maven. Make sure to use the latest EclipseLink dependency. Even GlassFish 3.1.2.2 still ships with a lower version. MongoDB support has been added beginning with 2.4.

 <dependency>
  <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
            <version>2.4.1</version>
        </dependency>

Beside this, you also need to turn GlassFish’s classloaders around:

<class-loader delegate='false'/>

Don’t worry about the details. I put up everything to
github.com/myfear so, you might dig into the complete example later on your own.

Testing it

Let’s make some very brief tests with it. Create a nice little Demo servlet and inject the composite-pu to it. Create an EntityManager from it and get a transaction. Now start creating prodcuts, a customer, the order and the separate order-lines. All plain JPA. No further magic here:

    @PersistenceUnit(unitName = 'composite-pu')
    private EntityManagerFactory emf;

   protected void processRequest() // [...]
     {

        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        // Products go into RDBMS
        Product installation = new Product('installation');
        em.persist(installation);

        Product shipping = new Product('shipping');
        em.persist(shipping);

        Product maschine = new Product('maschine');
        em.persist(maschine);

        // Customer into NoSQL
        Customer customer = new Customer();
        customer.setName('myfear');
        em.persist(customer);
        // Order into NoSQL
        Order order = new Order();
        order.setCustomer(customer);
        order.setDescription('Pinball maschine');

        // Order Lines mapping NoSQL --- RDBMS
        order.addOrderLine(new OrderLine(maschine, 2999));
        order.addOrderLine(new OrderLine(shipping, 59));
        order.addOrderLine(new OrderLine(installation, 129));

        em.persist(order);
        em.getTransaction().commit();
        String orderId = order.getId();
        em.close();

If you put the right logging properties in place you can see, what is happening:

A couple of sequences are assigned to the created Product entities (GeneratedValue). The Customer entity gets persisted into Mongo with a MappedInteraction. Entities map onto collections in MongoDB.

FINE: Executing MappedInteraction()
spec => null
properties => {mongo.collection=CUSTOMER, mongo.operation=INSERT}
input => [DatabaseRecord(
CUSTOMER._id => 5098FF0C3D9F5D2CCB3CFECF
CUSTOMER.NAME => myfear)]

After that you see the products being inserted into Derby and again the MappedInteraction, that perssits the Order into MongoDB. The really cool part is down at the OrderLines:

ORDER.ORDERLINES => [DatabaseRecord(
 LINENUMBER => 1
 COST => 2999.0
 PRODUCT_ID => 3), DatabaseRecord(
 LINENUMBER => 2
 COST => 59.0
 PRODUCT_ID => 2), DatabaseRecord(
 LINENUMBER => 3
 COST => 129.0
 PRODUCT_ID => 1)]

Orderlines has an object which has the product_id which was generated for the related product entities. Further on you can also find the related Order and iterate over the products and get their descriptions:

Order order2 = em.find(Order.class, orderId);
  for (OrderLine orderLine : order2.getOrderLines()) {
            String desc = orderLine.getProduct().getDescription();
            }

The nice little demo looks like this:

Thanks Shaun, thanks Gunnar for this nice little example. Now go to github.com/myfear and get your hands dirty :)
 

Reference: Polyglot Persistence: EclipseLink with MongoDB and Derby from our JCG partner Markus Eisele at the Enterprise Software Development with Java blog.

Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

Leave a Reply


+ six = 8



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books