-
Notifications
You must be signed in to change notification settings - Fork 0
Twitter Example
In order to demonstrate Kundera's power, we'll make a twitter like application for persisting users and their tweets in our favorite data-stores.
Beauty of Kundera is that it persists same entity class differently as required by underline persistence store. So, in our example the same entity (with same set of annotations) will be used to persist in different data-models supported by column family (Cassandra/ HBase) or document data-store(MongoDB). Shown below are the Cassanda, HBase and MongoDB data models used in the example.
In this example, we'll use below entities:
- User - Top level entity for users of twitter like application
- Preference - User's website preference
- ExternalLink(s) - Web links added by user.
Apart from these, we'll use these embedded objects (POJOs) within User entity.
- Personal Detail - User's personal details.
- Tweet(s) - List of messages tweeted by user.
Embedded objects are persisted co-located with underlying entity by Kundera (just like relational databases wherein JPA specifies that attributes of Embedded objects are persisted as column in the entity it is embedded) Entities added as relationships are persisted as separate column family/ document. Kundera maintains this relationship internally by adding additional foreign key column in the parent/ child entity depending upon type of relationship.
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "USER", schema = "KunderaExamples@twissandra")
public class User
{
@Id
@Column(name="USER_ID")
private String userId;
// Embedded object, will persist co-located
@Embedded
private PersonalDetail personalDetail;
// Element collection, will persist co-located
@ElementCollection
@CollectionTable(name = "tweeted")
private List<Tweet> tweets;
// One to many, will be persisted separately
@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
@JoinColumn(name="FRIEND_ID")
private List<User> friends; // List of users whom I follow
// One to many, will be persisted separately
@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
@JoinColumn(name="FOLLOWER_ID")
private List<User> followers; // List of users who are following me
// One-to-one, will be persisted separately
@OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
@JoinColumn(name="PREFERENCE_ID")
private Preference preference;
// One to many, will be persisted separately
@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
@JoinColumn(name="USER_ID")
private Set<ExternalLink> externalLinks;
public User()
{
}
public User(String userId, String name, String password, String relationshipStatus)
{
PersonalDetail pd = new PersonalDetail(name, password, relationshipStatus);
setUserId(userId);
setPersonalDetail(pd);
}
//Getters and setters omitted
}
import javax.persistence.Column;
import javax.persistence.Embeddable;
@Embeddable
public class PersonalDetail
{
@Column(name = "personal_detail_id")
private String personalDetailId;
@Column(name = "name")
private String name;
@Column(name = "password")
private String password;
@Column(name = "rel_status")
private String relationshipStatus;
public PersonalDetail()
{
}
public PersonalDetail(String name, String password, String relationshipStatus)
{
setPersonalDetailId(ExampleUtils.getUniqueId());
setName(name);
setPassword(password);
setRelationshipStatus(relationshipStatus);
}
//Getters and setters omitted
}
import javax.persistence.Column;
import javax.persistence.Embeddable;
@Embeddable
public class Tweet
{
@Column(name = "tweet_id")
private String tweetId;
@Column(name = "tweet_body")
private String body;
@Column(name = "tweeted_from")
private String device;
public Tweet()
{
}
public Tweet(String body, String device)
{
this.tweetId = ExampleUtils.getUniqueId();
this.body = body;
this.device = device;
}
//Getters and setters omitted
}
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "PREFERENCE", schema = "KunderaExamples@twissandra")
public class Preference
{
@Id
@Column(name="PREFERENCE_ID")
String preferenceId;
@Column(name = "WEBSITE_THEME")
String websiteTheme;
@Column(name = "PRIVACY_LEVEL")
String privacyLevel; // 1, 2, 3
public Preference()
{
}
public Preference(String theme, String privacyLevel)
{
this.preferenceId = ExampleUtils.getUniqueId();
this.websiteTheme = theme;
this.privacyLevel = privacyLevel;
}
//Getters and setters omitted
}
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "EXTERNAL_LINK", schema = "KunderaExamples@twissandra")
public class ExternalLink
{
@Id
@Column(name="EXT_LINK_ID")
private String extLinkId;
@Column(name = "LINK_TYPE")
private String linkType;
@Column(name = "LINK_ADDRESS")
private String linkAddress;
public ExternalLink()
{
}
public ExternalLink(String type, String address)
{
this.extLinkId = ExampleUtils.getUniqueId();
this.linkType = type;
this.linkAddress = address;
}
//Getters and setters omitted
}
persistence.xml is the only file where you are required to put all your settings. It should be put into META-INF folder under your classpath. In this example, we have put 3 persistence units named - twissandra, twibase and twingo for Cassandra, Hbase and MongoDB respectively. In our code example(to be explained next), you can use one of these persistence units and store/ retrieve your entities into your data-store interchangeably.
<persistence 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="twissandra">
<provider>com.impetus.kundera.KunderaPersistence</provider>
<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.pelops.PelopsClientFactory" />
<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-unit name="twibase">
<provider>com.impetus.kundera.KunderaPersistence</provider>
<properties>
<property name="kundera.nodes" value="localhost"/>
<property name="kundera.port" value="9165"/>
<property name="kundera.keyspace" value="KunderaExamples"/>
<property name="kundera.dialect" value="hbase"/>
<property name="kundera.client.lookup.class" value="com.impetus.client.hbase.HBaseClientFactory" />
<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-unit name="twingo">
<provider>com.impetus.kundera.KunderaPersistence</provider>
<properties>
<property name="kundera.nodes" value="localhost"/>
<property name="kundera.port" value="27017"/>
<property name="kundera.keyspace" value="KunderaExamples"/>
<property name="kundera.dialect" value="mongodb"/>
<property name="kundera.client.lookup.class" value="com.impetus.client.mongodb.MongoDBClientFactory" />
<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>
This service provides methods for reading and writing user details and their tweets.
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
//Other imports omitted
public class TwitterService
{
private EntityManager em;
private EntityManagerFactory emf;
public TwitterService(String persistenceUnitName)
{
if (emf == null)
{
try
{
emf = createEntityManagerFactory(persistenceUnitName);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
private EntityManager getEntityManager(String persistenceUnitName)
{
Configuration conf = new Configuration();
return conf.getEntityManager(persistenceUnitName);
}
public void close()
{
if(emf != null) {
emf.close();
}
}
public void addUser(User user)
{
em = emf.createEntityManager();
em.persist(user);
em.close();
}
public List<User> getAllUsers() {
em = emf.createEntityManager();
Query q = em.createQuery("select u from User u");
List<User> users = q.getResultList();
em.close();
return users;
}
public List<Tweet> getAllTweets(String userId)
{
em = emf.createEntityManager();
Query q = em.createQuery("select u from User u where u.userId =:userId");
q.setParameter("userId", userId);
List<User> users = q.getResultList();
em.close();
if (users == null || users.isEmpty())
{
return null;
}
else
{
return users.get(0).getTweets();
}
}
public List<Tweet> findTweetByBody(String tweetBody)
{
em = emf.createEntityManager();
Query q = em.createQuery("select u.body from User u where u.body like :body");
q.setParameter("body", tweetBody);
List<Tweet> tweets = q.getResultList();
em.close();
return tweets;
}
public List<Tweet> findTweetByDevice(String deviceName)
{
em = emf.createEntityManager();
Query q = em.createQuery("select u.device from User u where u.device like :device");
q.setParameter("device", deviceName);
List<Tweet> tweets = q.getResultList();
em.close();
return tweets;
}
}
//Imports here
public class TwitterExample
{
public static void main(String[] args)
{
TwitterService service = new TwitterService("twissandra");
//Add two users
User user1 = new User(userId1, "Amresh", "password1", "married");
user1.setPreference(new Preference("Motif", "2"));
user1.addExternalLink(new ExternalLink("Facebook", "http://facebook.com/coolnerd"));
user1.addExternalLink(new ExternalLink("LinkedIn", "http://linkedin.com/in/devilmate"));
user1.addTweet(new Tweet("Here is my first tweet", "Web"));
user1.addTweet(new Tweet("Second Tweet from me", "Mobile"));
User user2 = new User(userId2, "Saurabh", "password2", "single");
user2.setPreference(new Preference("High Contrast", "3"));
user2.addExternalLink(new ExternalLink("GooglePlus", "http://plus.google.com/inviteme"));
user2.addExternalLink(new ExternalLink("Yahoo", "http://yahoo.com/profiles/itsmeamry"));
user2.addTweet(new Tweet("Saurabh tweets for the first time", "Phone"));
user2.addTweet(new Tweet("Another tweet from Saurabh", "text"));
service.addUser(user1);
service.addUser(user2);
//Print all users
List<User> users = service.getAllUsers();
System.out.println(users);
//Print all tweets from user 1
List<Tweet> tweetsUser1 = service.getAllTweets("0001");
System.out.println(tweetsUser1);
//Search tweets by body
List<Tweet> user1Tweet = service.findTweetByBody("first tweet");
List<Tweet> user2Tweet = service.findTweetByBody("first one from me");
System.out.println(user1Tweet);
System.out.println(user2Tweet);
//Search tweets by device
List<Tweet> webTweets = service.findTweetByDevice("Web");
List<Tweet> mobileTweets = service.findTweetByDevice("Mobile");
System.out.println(webTweets);
System.out.println(mobileTweets);
}
}
-
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] (https://github.com/impetus-opensource/Kundera/wiki/Kundera-with--Couchdb)
- [Kundera with Elasticsearch] (https://github.com/impetus-opensource/Kundera/wiki/Kundera-with-Elasticsearch)
- [Kundera with HBase] (https://github.com/impetus-opensource/Kundera/wiki/Kundera-with-HBase)
- [Kundera with Kudu] (https://github.com/impetus-opensource/Kundera/wiki/Kundera-with-Kudu)
- [Kundera with MongoDB] (https://github.com/impetus-opensource/Kundera/wiki/Kundera-with-MongoDB)
- [Kundera with OracleNoSQL] (https://github.com/impetus-opensource/Kundera/wiki/Kundera-OracleNoSQL)
- [Kundera with Redis] (https://github.com/impetus-opensource/Kundera/wiki/Kundera-over-Redis)
- [Kundera with Spark] (https://github.com/impetus-opensource/Kundera/wiki/Kundera-with-Spark)
-
Extend Kundera
- Sample Codes and Examples
- [Blogs and Articles] (https://github.com/impetus-opensource/Kundera/wiki/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