Skip to content

Twitter Example

Amresh edited this page Jul 11, 2013 · 2 revisions

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.

Data Model

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.

Cassandra Data Model

Cassandra Data Model

HBase Data Model

HBase Data Model

MongoDB Data Model

MongoDB Data Model

Entities

In this example, we'll use below entities:

  1. User - Top level entity for users of twitter like application
  2. Preference - User's website preference
  3. ExternalLink(s) - Web links added by user.

Apart from these, we'll use these embedded objects (POJOs) within User entity.

  1. Personal Detail - User's personal details.
  2. 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.

User

   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
    }

PersonalDetail

    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
    }

Tweet

    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
    }

Preference

    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
    }

ExternalLink

    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
    }

Configuration

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>

Twitter Service

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;
            }             

	}

And finally...using Twitter Service

	//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);       
	        
	    }
	}

Home

Clone this wiki locally