-
Notifications
You must be signed in to change notification settings - Fork 233
Using Kundera 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.
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.
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 in Cassandra, 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!
Download Play!
-
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.
-
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
- …and we are done. (detailed instructions are given here).
-
Goto to directory where you want to create your project.
-
Create a new project named play-jpa-kundera (or any fancy name you would like to give it):
-
Run command “play” to enter Play! console.
-
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”:
- 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.
-
Test your application by hitting localhost:9000 in your favorite browser.
-
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)
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.kundera.client" % "kundera-cassandra" % "3.6",
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.
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:
<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="cassandra_pu">
<provider>com.impetus.kundera.KunderaPersistence</provider>
<class>model.User</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<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" />
</properties>
</persistence-unit>
</persistence>
Here, model.User is entity class that we’re going to write next.
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
}
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();
}
}
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()
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)
In order to make your entity classes available at run time (in development mode, of course), all you’ve to do is to create jar file out of them and put this jar file into lib folder under project root directory. (create lib folder as it won’t exist by default)
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
Now, time to fasten your seat-belts! Run below URLs in your web browser one after other:
You can test inserted data from Cassandra-cli
-
Datastores Supported
- Releases
-
Architecture
-
Concepts
-
Getting Started in 5 minutes
-
Features
- Object Mapper
- Polyglot Persistence
- Queries Support
- JPQL (JPA Query Language)
- Native Queries
- Batch insert update
- Schema Generation
- Primary Key Auto generation
- Transaction Management
- REST Based Access
- Geospatial Persistence and Queries
- Graph Database Support
-
Composite Keys
-
No hard annotation for schema
-
Support for Mapped superclass
-
Object to NoSQL Data Mapping
-
Cassandra's User Defined Types and Indexes on Collections
-
Support for aggregation
- Scalar Queries over Cassandra
- Connection pooling using Kundera Cassandra
- Configuration
-
Kundera with Couchdb
-
Kundera with Elasticsearch
-
Kundera with HBase
-
Kundera with Kudu
-
Kundera with RethinkDB
-
Kundera with MongoDB
-
Kundera with OracleNoSQL
-
Kundera with Redis
-
Kundera with Spark
-
Extend Kundera
- Sample Codes and Examples
-
Blogs and Articles
-
Tutorials
* Kundera with Openshift
* Kundera with Play Framework
* Kundera with GWT
* Kundera with JBoss
* Kundera with Spring
-
Performance
-
Troubleshooting
-
FAQ
- Production deployments
- Feedback