Play! NoSQL (Building NoSQL applications with Play framework)
Join the DZone community and get the full member experience.
Join For FreeAccessing Databases with Play! Framework
Play Framework is a high velocity web framework for Java and Scala. It’s built to make application development faster and glitch free.
Play! provides a plugin for managing JDBC connection pools. So, if you’re working with relational databases, all you’ve to do is to define database connector dependencies in its build file, specify connection properties in configuration file, and voila! You’re all set to use data sources with a single line of code. You can configure as many databases as you need. This and many other Play! features are what most of the developers would ever wish for.
…and NoSQL?
However, integrating Play! with NoSQL databases is where it all ends. Any mature NoSQL plugin is yet to be developed. Reason is obvious: These databases are varied and currently lack a common API. This means plugin for all these databases need to be written separately.
There have been efforts like PlayORM. Some people have had success with usingMorphia, which nevertheless works with MongoDB only. I haven’t yet tried them but have seen users struggling with using them.
JPA to your rescue
There is a bad news. While Play! provides seamless JPA integration with relational databases, NoSQL support hasn’t arrived yet. Good news is that Kundera - An object-datastore mapping library based on JPA 2.0, can be easily integrated with Play! framework and make it possible to work like charm with databases it currently supports. This article with guide you step-by-step on setting up Play! framework on your machine, create a project and integrate with Kundera to read and write data inCassandra, one of the most popular NoSQL database in town. However, you’re free to use database of your choice (of course from those supported by Kundera). Read on!
Setting up a Play! project
Download Play!
1. Goto http://www.playframework.com/download and download latest Play! release (play-2.1.2.zip at the time of this writing). Unzip in a directory of your choice. We’ll refer to uncompressed folder directory as PLAY_HOME.
2. Add PLAY_HOME folder to you PATH environment variable, so that it’s handy when you run play commands from within your project. If you’re using Bash, you can do this by simply appending m like this to user.home/.bashrc
export PATH=$PATH:/home/impadmin/play-2.1.1
3. …and we are done. (detailed instructions are given here).
Create your project
1. Goto to directory where you want to create your project.
2. Create a new project named play-jpa-kundera (or any fancy name you would like to give it):
3. Run command “play” to enter Play! console.
4. You’re free to use any text editor of your choice for writing source code and modifying configuration files. Eclipse settings files can be generated by running command “eclipse”:
5. execute “run” command from Play! console (server is started in development mode)
At this stage, dependency Jars specified in Build.scala and other Play dependencies are downloaded and copied to classpath.
6. Test your application by hitting localhost:9000 in your favorite browser.
7. Congratulations! Your Play! project “play-jpa-kundera” is ready to use. Import this project in eclipse (if you like) and start playing with it. (A detailed instructions for above steps are available here)
Play! with Kundera
Add Kundera dependencies to project/Build.scala
You need to add Kundera dependency jars (which, by the way are available in a maven repository) to your project. Modify your Build.Scala file under project folder. It should look like this:
import sbt._ import Keys._ import play.Project._ object ApplicationBuild extends Build { val appName = "play-jpa-kundera" val appVersion = "1.0-SNAPSHOT" val appDependencies = Seq( "com.impetus.client" % "kundera-cassandra" % "2.5", javaCore ) val main = play.Project(appName, appVersion, appDependencies).settings( //Kundera Public repositories ebeanEnabled := false, resolvers += "Kundera" at "https://oss.sonatype.org/content/repositories/releases", resolvers += "Riptano" at "http://mvn.riptano.com/content/repositories/public", resolvers += "Kundera missing" at "http://kundera.googlecode.com/svn/maven2/maven-missing-resources", resolvers += "Scale 7" at "https://github.com/s7/mvnrepo/raw/master" ) }
It’s always better to use the most recent release of Kundera.
Caution: javaJdbc app dependency downloads hibernate-entitymanager jar file that interferes with Kundera. Make sure you remove this app dependency which is by default present.
Write persistence.xml
We are now ready to build our persistence code. First step towards that is writing persistence.xml file, which should be put under conf/META-INF folder:
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" version="2.0"> <persistence-unit name="cassandra_pu"> <provider>com.impetus.kundera.KunderaPersistence</provider> <class>model.User</class> <properties> <property name="kundera.nodes" value="localhost"/> <property name="kundera.port" value="9160"/> <property name="kundera.keyspace" value="KunderaExamples"/> <property name="kundera.dialect" value="cassandra"/> <property name="kundera.client.lookup.class" value="com.impetus.client.cassandra.thrift.ThriftClientFactory" /> <property name="kundera.cache.provider.class" value="com.impetus.kundera.cache.ehcache.EhCacheProvider"/> <property name="kundera.cache.config.resource" value="/ehcache-test.xml"/> </properties> </persistence-unit> </persistence>
Here, model.User is entity class that we’re going to write next.
Create User Entity
Create a User entity class under app/model package:
package model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "users", schema = "KunderaExamples@cassandra_pu") public class User { @Id private String userId; @Column(name="first_name") private String firstName; @Column(name="last_name") private String lastName; @Column(name="city") private String city; //Getters/ setters/ constructors go here }
Write UserController
Now, time to write the class where magic actually happens, UserController for persist/find/update/delete operations. Write this class under app/controller package:
package controllers; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import model.User; import play.Play; import play.mvc.Controller; import play.mvc.Result; public class UserController extends Controller { static EntityManagerFactory emf; public static Result persist() { EntityManager em = getEmf().createEntityManager(); User user = new User(); user.setUserId("0001"); user.setFirstName("John"); user.setLastName("Smith"); user.setCity("London"); em.persist(user); em.close(); return ok("User 0001 record persisted for persistence unit cassandra_pu"); } public static Result find() { EntityManager em = getEmf().createEntityManager(); User user = em.find(User.class, "0001"); em.close(); return ok("Found User in database with the following details:" + printUser(user)); } public static Result update() { EntityManager em = getEmf().createEntityManager(); User user = em.find(User.class, "0001"); user.setCity("New York"); em.merge(user); user = em.find(User.class, "0001"); return ok("Record updated:" + printUser(user)); } public static Result delete() { EntityManager em = getEmf().createEntityManager(); User user = em.find(User.class, "0001"); em.remove(user); user = em.find(User.class, "0001"); return ok("Record deleted:" + printUser(user)); } private static EntityManagerFactory getEmf() { if (emf == null) { emf = Persistence.createEntityManagerFactory("cassandra_pu"); } return emf; } private static String printUser(User user) { if (user == null) return "Record not found"; return "\n--------------------------------------------------" + "\nuserId:" + user.getUserId() + "\nfirstName:" + user.getFirstName() + "\nlastName:" + user.getLastName() + "\ncity:" + user.getCity(); } }
Add controller methods to conf/routes file
We’ll add one URL path for each one of CRUD methods in controller. Add them to your conf/routes file, It should look like this:
# Routes # This file defines all application routes (Higher priority routes first) # ~~~~ # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.at(path="/public", file) ################# User Controller############### # Persist Operation GET /persist controllers.UserController.persist() # Find Operation GET /find controllers.UserController.find() # Update Operation GET /update controllers.UserController.update() # Delete Operation GET /delete controllers.UserController.delete()
Make entity classes available at runtime
You can skip this step if you’re running Play! in production mode (by running “play start”). However, If you’re running Play! in development mode, Play! uses its own Classloader that doesn’t read classes from target/scala-2.xx/classes folder. As a result, your User entity won’t be loaded at runtime and Kundera will throw below exception when you try to run application:
com.impetus.kundera.KunderaException: com.impetus.kundera.KunderaException: EntityMetadata should not be null at com.impetus.kundera.persistence.EntityManagerImpl.persist(EntityManagerImpl.java:174)
Start Cassandra Server and create schema/ tables
I am assuming you’ve already Cassandra server (or database server you’re working on) setup and running on your machine. If not, refer to their respective documentation.
Now, create schema and tables for User entity to be written to:
impadmin@impetus-D189a:/usr/local/apache-cassandra-1.1.6/bin$ ./cassandra-cli --host localhost --port 9160 Connected to: "Test Cluster" on localhost/9160 Welcome to the Cassandra CLI. Type 'help;' or '?' for help. Type 'quit;' or 'exit;' to quit. [default@unknown]create keyspace KunderaExamples; [default@unknown]use KunderaExamples; [default@KunderaExamples]create column family users with comparator=UTF8Type and default_validation_class=UTF8Type and key_validation_class=UTF8Type; 81852270-2374-11e1-0000-242d50cf1fdd Waiting for schema agreement... ... schemas agree across the cluster
Test your application
Now, time to fasten your seat-belts! Run below URLs in your web browser one after other:
1. http://localhost:9000/persist
You can test inserted data from Cassandra-cli
3. http://localhost:9000/update
Published at DZone with permission of Amresh Singh, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
Essential Architecture Framework: In the World of Overengineering, Being Essential Is the Answer
-
A React Frontend With Go/Gin/Gorm Backend in One Project
-
From On-Prem to SaaS
-
Cucumber Selenium Tutorial: A Comprehensive Guide With Examples and Best Practices
Comments