animesh kumar

Running water never grows stale. Keep flowing!

I have a paper heart

with 4 comments

[tweetmeme source=”anismiles” only_single=false http://www.URL.com%5D

I have a paper heart
too easy to rip off my chest
fold, twist and turn
into
city, house or nest.

Around me, I’ve made collections
of ceramic vows, muddy tears
china-stone celebrations
all cornered into
dirty crumpled affections.

You and I glued into a story
tragic like always, but fairy
inking the ends together
with dull colors of cherry
scary!

Written by Animesh

September 20, 2010 at 7:38 pm

Posted in Poetry

A dull night

with one comment

[tweetmeme source=”anismiles” only_single=false http://www.URL.com%5D

It’s a dull night, tonight
nothing, but a struggling candle by your banshee
catches my sight.
It’s far away, I know, but it’s the only light.

I hope you don’t misunderstand me
when I walk across your house, and call thee
I know you’re held’ up,
customs and rituals often kill love.

I know, but this one path
sprawled from where I stand
to the hopes of you holding my trembling hand.

Written by Animesh

September 14, 2010 at 4:42 pm

Posted in Poetry

I wish

leave a comment »

[tweetmeme source=”anismiles” only_single=false http://www.URL.com%5D

I wish I had the grit
to write poetry with splendid wit
words engulfed in words
silence entwined with surds
I wish I could name
the feeling that
hung on her every breath
fill in the hush
gaping from her droopy eyelids…

Ah but
she calls me from every direction
and I stray far too often.

Written by Animesh

September 14, 2010 at 3:01 pm

Posted in Poetry

Tagged with ,

stuck and lost

with 3 comments

[tweetmeme source=”anismiles” only_single=false http://www.URL.com%5D

Stuck between what works and what might
Resolved to crumble at the whim of dice
‘Know all I need to know
just don’t have the will to go
Am I done here?
Or they got more sand to throw
They say, it’s hard to steer into the wild-
life ain’t no cake slice.
Who likes it sweet anyway?

In my coffer, I keep flowers and thorns
‘Make my story with quills and scorns
Who cares who is hero and who not
every man is a dead man,
everything’s to rot.
I’m holding on to my truth, my lies,
dreams of dreams, fancy disguise.

Written by Animesh

September 3, 2010 at 12:49 pm

Posted in Poetry

Tagged with , ,

I need poetry

with 3 comments

[tweetmeme source=”anismiles” only_single=false http://www.URL.com%5D

Alone
distraught, lost
I fumble for words,
shallow vowels, grubby surds.
I think I need poetry.

Little abstractions, some nausea,
a fling – if you say so,
a minor fight,
bedtime story…
or may be, just some sad poetry.

Tiny mutations, and
the world turns gray, plants flower anti-flowers,
people die, and wake up in dreams,
in one huge dream – Nolan’s dream,
and nobody utters no words
and burn in word-less purgatory.

Times change,
every hour, if you insist it’s slow,
anybody can be anybody, everybody!
And nobody’s got no tales
tall or short – whatever.

I am who I am –
word groper, literary loner,
un-trailed like snowman’s feet
in heat
asking for few words, and skill
to blaze them into poetry!

Written by Animesh

August 10, 2010 at 6:33 pm

Posted in Poetry

Tagged with , , , ,

Postgres Enum with Hibernate

with 8 comments

[tweetmeme source=”anismiles” only_single=false http://www.URL.com%5D

In a running project, we had to map Postgres Enum onto Java Enum using Hibernate. It turned out to be more tricky than we had assumed initially. So, I thought a little tutorial here might save your time if you are stuck in the similar situation.

I am taking an example of Person-Gender mapping where Gender is of enum type.

  1. First, create proper Enums and Tables in Postgres database. Here is the script.
    create type genderType as enum (
    	'MALE', 'FEMALE'
    );
    
    create table person (
    	personid serial NOT NULL,
    	gender genderType not null
    );
    
  2. Then, you need to define you Enum class.
    package com.impetus.ilabs.entity;
    
    public enum GenderType {
        MALE, FEMALE;
    }
    
  3. Now, define your Entity class like this,
    package com.impetus.ilabs.entity;
    
    import java.io.Serializable;
    
    public class Person implements Serializable {
    
    	private Integer personId;
    	
    	private GenderType gender;
    
    	public Integer getPersonId() {
    		return personId;
    	}
    
    	public void setPersonId(Integer personId) {
    		this.personId = personId;
    	}
    
    	public GenderType getGender() {
    		return gender;
    	}
    
    	public void setGender(GenderType gender) {
    		this.gender = gender;
    	}
    
    	@Override
    	public String toString() {
    		StringBuilder builder = new StringBuilder();
    		builder.append("Person [gender=");
    		builder.append(gender);
    		builder.append(", personId=");
    		builder.append(personId);
    		builder.append("]");
    		return builder.toString();
    	}
    }
    
  4. This is the magical part. You need to implement a custom UserType that can understand Enum objects. Here is an implementation of PGEnumUserType.
    package com.impetus.ilabs;
    
    import java.io.Serializable;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Types;
    import java.util.Properties;
    
    import org.hibernate.HibernateException;
    import org.hibernate.usertype.EnhancedUserType;
    import org.hibernate.usertype.ParameterizedType;
    import org.postgresql.util.PGobject;
    
    // This implementation works only with Postgres
    public class PGEnumUserType implements EnhancedUserType, ParameterizedType {
    	// Enum  class under observation
    	private Class<Enum> enumClass;
    
    	public void setParameterValues(Properties parameters) {
    		String enumClassName = parameters.getProperty("enumClassName");
    		try {
    			enumClass = (Class<Enum>) Class.forName(enumClassName);
    		} catch (ClassNotFoundException cnfe) {
    			throw new HibernateException("Enum class not found", cnfe);
    		}
    	}
    
    	public Object assemble(Serializable cached, Object owner)
    			throws HibernateException {
    		return cached;
    	}
    
    	public Object deepCopy(Object value) throws HibernateException {
    		return value;
    	}
    
    	public Serializable disassemble(Object value) throws HibernateException {
    		return (Enum) value;
    	}
    
    	public boolean equals(Object x, Object y) throws HibernateException {
    		return x == y;
    	}
    
    	public int hashCode(Object x) throws HibernateException {
    		return x.hashCode();
    	}
    
    	public boolean isMutable() {
    		return false;
    	}
    
    	public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
    			throws HibernateException, SQLException {
    		Object object = rs.getObject(names[0]);
    		if (rs.wasNull()) {
    			return null;
    		}
    
    		// Notice how Object is mapped to PGobject. This makes this implementation Postgres specific
    		if (object instanceof PGobject) {
    			PGobject pg = (PGobject) object;
    			return Enum.valueOf(enumClass, pg.getValue());
    		}
    		return null;
    	}
    
    	public void nullSafeSet(PreparedStatement st, Object value, int index)
    			throws HibernateException, SQLException {
    		if (value == null) {
    			st.setNull(index, Types.VARCHAR); 
    			// UPDATE: To support NULL insertion, change to: st.setNull(index, 1111);
    		} else {
    			// Notice 1111 which java.sql.Type for Postgres Enum
    			st.setObject(index, ((Enum)value), 1111);
    		}
    	}
    
    	public Object replace(Object original, Object target, Object owner)
    			throws HibernateException {
    		return original;
    	}
    
    	public Class returnedClass() {
    		return enumClass;
    	}
    
    	public int[] sqlTypes() {
    		return new int[] { Types.VARCHAR }; 
    		// UPDATE: To support NULL insertion, change to: return new int[] { 1111 };
    	}
    
    	public Object fromXMLString(String xmlValue) {
    		return Enum.valueOf(enumClass, xmlValue);
    	}
    
    	public String objectToSQLString(Object value) {
    		return '\'' + ((Enum) value).name() + '\'';
    	}
    
    	public String toXMLString(Object value) {
    		return ((Enum) value).name();
    	}
    }
    
  5. Okay, so the tricky part is over. Now, you need to write Hibernate Mapping xml for Person class.
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    
    <hibernate-mapping>
    	<class name="com.impetus.ilabs.entity.Person" table="person">
    		<id name="personId" type="java.lang.Integer"
    			column="personid">
    			<generator class="native"></generator>
    		</id>
    
    		<property name="gender">
    			<type name="com.impetus.ilabs.PGEnumUserType">
    				<param name="enumClassName">com.impetus.ilabs.entity.GenderType</param>
    			</type>
    		</property>
    	</class>
    </hibernate-mapping>
    
  6. Done! I am including a sample usage class, but you don’t worry about this part, you are good with whatever DAO implementation you might have.
    package com.impetus.ilabs;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    
    import com.impetus.ilabs.entity.GenderType;
    import com.impetus.ilabs.entity.Person;
    
    public class App {
    	
    	private static final SessionFactory sessionFactory = buildSessionFactory();
    
    	private static SessionFactory buildSessionFactory() {
    		try {
    			return new Configuration().configure().buildSessionFactory();
    		} catch (Throwable ex) {
    			throw new ExceptionInInitializerError(ex);
    		}
    	}
    	
    	private static void save (Person person) {
    		Session session = sessionFactory.openSession();
    		session.beginTransaction();
    			
    		// create object
    		session.save(person);
    		session.getTransaction().commit();
    	}
    
    	private static void load (int id) {
    		Session session = sessionFactory.openSession();
    		session.beginTransaction();
    			
    		System.out.println (session.load(Person.class, id));
    		session.getTransaction().commit();
    	}
    
    	public static void main(String[] args) {
    		// create object
    		Person person = new Person();
    		person.setGender(GenderType.MALE);
    		save(person);
    		
    		// load object
    		load(person.getPersonId());
    	}
    }
    

Enjoy! By the way, the whole thing that is described above is also available as maven project to download.

Written by Animesh

August 4, 2010 at 3:48 pm

Posted in Technology

Tagged with , , , ,

JUnit Primer

leave a comment »

[tweetmeme source=”anismiles” only_single=false http://www.URL.com%5D

I recently gave a presentation on JUnit and thought it might be useful to other people as well. So, I’m sharing the PPT here.

Written by Animesh

August 2, 2010 at 2:20 pm

Posted in Technology

Tagged with , ,

Discovering Java Annotations

with 15 comments

[tweetmeme source=”anismiles” only_single=false http://www.URL.com%5D

DZone link of this artilce: http://www.dzone.com/links/r/discovering_java_annotations.html

Annotations these days are proving to be widely popular. Many Annotation based frameworks (Spring, JPA, Tapestry to name few) are seeing the light of the day, and even small scale projects are using Annotation based meta-programming for better separation of concern. Annotations are wonderful and it’s sure to stay here.

However, in order to use this, we must be able to locate classes annotated with Annotations that concerns us. How do you do it?

First, you find resources where we can look for annotated classes. You can look into “java.class.path” system property (also known as CLASSPATH), or use Classloader or ServletContexts to have a list of Resources. Now, you scan through each resource and check for Annotations that concern you.

The easiest way to scan through a resource is to load it through a Classloader and use Java Reflection Api to look for a specified annotation. However, this approach will only help you to find Annotations that are visible at runtime, and loading each resource into memory will unnecessarily consume Java Memory. Otherwise, you can use ASM or Javassist byte processing libraries. These libraries process class bytes and see even runtime annotations. And since they don’t load your resources into Memory, they have a low footprint.

Well, to help you here, we have written a small library Annovention using Javassist. The idea behind Annovention is to help you quickly locate annotated classes, fields or methods. Once you have the pertinent classes you can run your domain logic or do whatever fancies you.

Download Annovention here: http://code.google.com/p/annovention/

How it works?

Annovention works on subscribe-and-listen pattern.

  1. You create annotation discovery listeners.
    1. Annovetion supports Class, Field and Method level annotation discovery and each of these listeners must implement ClassAnnotationDiscoveryListener, FieldAnnotationDiscoveryListener or MethodAnnotationDiscoveryListener interfaces respectively.
    2. Each listener has a method supportedAnnotations() that returns an Array of Annotation names. For example, to listen to @Entity and @EntityListeners annotations, the array will be:
      new String[] {Entity.class.getName(), EntityListeners.class.getName()}
      
    3. Each listener has a method discovered() that is called each time a relevant annotation is located with Class-name, Field-name, Method-name and discovered Annotation-name.
    4. Please note that your listeners are receiving only names of classes, fields and methods. You must use Java Reflection to instantiate them. Remember Class.forName()?
  2. Now, there is a Discoverer class that does all the discoveries. It needs Resources and Listeners. Annovention comes with an implementation of ClasspathDiscoverer. This uses “java.class.path” system property and builds an array of resources to scan. You need to register your Listeners to Discoverer class in order to get notified.

Sample Use

public class SampleAnnotationDiscoverer {

	public static void main (String args []) {
		// Get a classpath discoverer instance
		Discoverer discoverer = new ClasspathDiscoverer();

		// Register class annotation listener
		discoverer.addAnnotationListener(new MyClassAnnotationListener());
		// Register field annotation listener
		discoverer.addAnnotationListener(new MyFieldAnnotationListener());
		// Register method annotation listener
		discoverer.addAnnotationListener(new MyMethodAnnotationListener());

		// Fire it
		discoverer.discover();
	}

	/** Dummy ClassAnnotation listener */
	static class MyClassAnnotationListener implements ClassAnnotationDiscoveryListener {
		private static Log log =
			LogFactory.getLog(MyClassAnnotationListener.class);

		@Override
		public void discovered(String clazz, String annotation) {
			log.info("Discovered Class(" + clazz + ") " +
					"with Annotation(" + annotation + ")");
		}

		@Override
		public String[] supportedAnnotations() {
			// Listens for @Entity and @EntityListeners annotations.
			return new String[] {
					Entity.class.getName(),
					EntityListeners.class.getName()};
		}
	}

	/** Dummy FieldAnnotation listener */
	static class MyFieldAnnotationListener implements FieldAnnotationDiscoveryListener {
		private static Log log =
			LogFactory.getLog(MyFieldAnnotationListener.class);

		@Override
		public void discovered(String clazz, String field, String annotation) {
			log.info("Discovered Field(" + clazz + "." + field + ") " +
					"with Annotation(" + annotation + ")");
		}

		@Override
		public String[] supportedAnnotations() {
			// Listens for @Id and @Column annotations.
			return new String[] {
					Id.class.getName(),
					Column.class.getName()};
		}
	}

	/** Dummy FieldAnnotation listener */
	static class MyMethodAnnotationListener implements MethodAnnotationDiscoveryListener {

		private static Log log =
			LogFactory.getLog(MyMethodAnnotationListener.class);

		@Override
		public void discovered(String clazz, String method, String annotation) {
			log.info("Discovered Method(" + clazz + "." + method + ") " +
					"with Annotation(" + annotation + ")");
		}

		@Override
		public String[] supportedAnnotations() {
			// Listens for @PrePersist, @PreRemove and @PostPersist annotations.
			return new String[] {
					PrePersist.class.getName(),
					PostPersist.class.getName(),
					PreRemove.class.getName()};
		}
	}
}

How to extend?

You just have to play with Discoverer and Filter classes. The general flow is:

  1. Discoverer invokes findResources() method which returns an array of URLs and then
  2. It iterates through each URL and apply filter, and
  3. Then scan the resource for annotations and
  4. If a valid annotation is found, corresponding listeners are intimated.

You can write your own Filter implementation or use FilterImpl class that comes with Annovention. Then, extend Discoverer class and implement findResources() method in whatever way you see fit. Then just invoke discover() method. Easy?

Written by Animesh

July 26, 2010 at 6:08 pm

Posted in Technology

Tagged with , ,

Kundera: now JPA 1.0 Compatible

with 82 comments

[tweetmeme source=”anismiles” only_single=false http://www.URL.com%5D

If you are new to Kundera, you should read Kundera: knight in the shining armor! to get a brief idea about it.

Kundera has reached a major milestone lately, so I thought to sum up the developments here. First and foremost, Kundera is now JPA 1.0 compatible, thought it doesn’t support relationships yet, it does support easy JPA style @Entity declarations and Linear JPA Queries. 🙂 Didn’t you always want to search over Cassandra?

To begin with let’s see what the changes are.

  1. Kundera do not have @CassandraEntity annotation anymore. It now expects JPA @Entity.
  2. Kundera specific @Id has been replaced with JPA @Id.
  3. Kundera specific @Column has been replaced with JPA @Column.
  4. @ColumnFamily, @SuperColumnFamily and @SuperColumn are still there, and are expected to be there for a long time to come, because JPA doesn’t have any of these ideas.
  5. @Index is introduced to control indexing of an entity bean. You can safely ignore it and let Kundera do the defaults for you.

I would recommend you to read about Entity annotation rules discussed in the earlier post. Apart from the points mentioned above, everything remains the same:  https://anismiles.wordpress.com/2010/06/30/kundera-knight-in-the-shining-armor/#general-rules

How to define an entity class?

@Entity						// makes it an entity class
@ColumnFamily("Authors")	// assign ColumnFamily type and name
public class Author {

	@Id	// row identifier
	String username;

	@Column(name = "email")	// override column-name
	String emailAddress;

	@Column
	String country;

	@Column(name = "registeredSince")
	Date registered;

	String name;

	public Author() { // must have a default constructor
	}

	// getters, setters etc.
}

There is an important deviation from JPA specification here.

  1. Unlike JPA you must explicitly annotate fields/properties you want to persist. Any field/property that is not @Column annotated will be ignored by Kundera.
  2. In short, the paradigm is reversed here. JPA assumes everything persist-able unless explicitly defined @Transient. Kundera expects everything transient unless explicitly defined @Column.

How to instantiate EntityManager?

Kundera expects some properties to be provided with before you can bootstrap it.

# kundera.properties
# Cassandra nodes to with Kundera will connect
kundera.nodes=localhost

#Cassandra port
kundera.port=9160

#Cassandra keyspace which Kundera will use
kundera.keyspace=Blog

#Whether or not EntityManager can have sessions, that is L1 cache.
sessionless=false

#Cassandra client implementation. It must implement com.impetus.kundera.CassandraClient
kundera.client=com.impetus.kundera.client.PelopsClient

You can define these properties in a java Map object, or in JPA persistence.xml or in a property file “kundera.properties” kept in the classpath.

  1. Instantiating with persistence.xml > Just replace the provider with com.impetus.kundera.ejb.KunderaPersistence which extends JPA PersistenceProvider. And either provide Kundera specific properties in the xml file or keep “kundera.properties” in the classpath.
  2. Instantiating in standard J2SE environment, with explicit Map object.
    Map map = new HashMap();
    map.put("kundera.nodes", "localhost");
    map.put("kundera.port", "9160");
    map.put("kundera.keyspace", "Blog");
    map.put("sessionless", "false");
    map.put("kundera.client", "com.impetus.kundera.client.PelopsClient");
    
    EntityManagerFactory factory = new EntityManagerFactoryImpl("test", map);
    EntityManager manager = factory.createEntityManager();
    
  3. Instantiating in standard J2SE environment, with “Kundera.properties” file. Pass null to EntityManagerFactoryImpl and it will automatically look for the property file.
    EntityManagerFactory factory = new EntityManagerFactoryImpl("test", null);
    EntityManager manager = factory.createEntityManager();
    

Entity Operations

Once you have EntityManager object you are good to go, applying all your JPA skills. For example, if you want to find an Entity object by key,

	try {
		Author author = manager.find(Author.class, "smile.animesh");
	} catch (PersistenceException pe) {
		pe.printStackTrace();
	}

Similarly, there are other JPA methods for various operations: merge, remove etc.

JPA Query

Note: Kundera uses Lucene to index your Entities. Beneath Lucene, Kundera uses Lucandra to store the indexes in Cassandra itself. One fun implication of using Lucene is that apart from regular JPA queries, you can also run Lucene queries. 😉

Here are some indexing fundamentals:

  1. By default, all entities are indexed along with with all @Column properties.
  2. If you do not want to index an entity, annotate it like, @Index (index=false)
  3. If you do not want to index a @column property of an entity, annotate it like, @Index (index=false)

That’s it. Here is an example of JPA query:

	// write a JPA Query
	String jpaQuery = "SELECT a from Author a";

	// create Query object
	Query query = manager.createQuery(jpaQuery);

	// get results
	List<Author> list = query.getResultList();
	for (Author a : list) {
		System.out.println(a.getUsername());
	}

Kundera also supports multiple “where” clauses with “AND”, “OR”, “=” and “like” operations.

	// find all Autors with email like anismiles
	String jpaQuery_for_emails_like = "SELECT a from Author a WHERE a.emailAddress like anismiles";

	// find all Authors with email like anismiles or username like anim
	String jpaQuery_for_email_or_name = "SELECT a from Author a WHERE a.emailAddress like anismiles OR a.username like anim";

I think this will enable you to play around with Kundera. I will be writing up more on how Kundera indexes various entities and how you can execute Lucene Queries in subsequent posts.

Kundera’s next milestones will be:

  1. Implementation of JPA listeners, @PrePersist @PostPersist etc.
  2. Implementation of Relationships, @OneToMany, @ManyToMany etc.
  3. Implementation of Transactional support, @Transactional

Written by Animesh

July 14, 2010 at 9:51 am

Posted in Technology

Tagged with , , , , ,

Kundera: knight in the shining armor!

with 37 comments

[tweetmeme source=”anismiles” only_single=false http://www.URL.com%5D

The idea behind Kundera is to make working with Cassandra drop-dead simple, and fun. Kundera does not reinvent the wheel by making another client library; rather it leverages the existing libraries, and builds – on top of them – a wrap-around API to developers do away with the unnecessary boiler plate codes, and program  a neater, cleaner code that reduces code-complexity and improves quality. And above all, improves productivity.

Download Kundera here: http://code.google.com/p/kundera/

Note: Kundera is now JPA 1.0 compatible, and there are some ensuing changes. You should read about it here: https://anismiles.wordpress.com/2010/07/14/kundera-now-jpa-1-0-compatible/

Objectives:

  • To completely remove unnecessary details, such as Column lists, SuperColumn lists, byte arrays, Data encoding etc.
  • To be able to work directly with Domain models just with the help of annotations
  • To eliminate “code plumbing”, so as to keep the flow of data processing clear and obvious
  • To completely separate out Cassandra and its obvious concerns from application-level logics for robust application development
  • To include the latest Cassandra developments without breaking anything, anywhere in the business layer

Cassandra Data Models

At the very basic level, Cassandra has Column and SuperColumn to hold your data. Column is a tuple with a name, value and a timestamp; while SuperColumn is Column of Columns. Columns are stored in a ColumnFamily, and SuperColumns in SuperColumnFamily. The most important thing to note is that Cassandra is not your old relational database, it is a flat system. No joins, No foreign keys, nothing. Everything you store here is 100% de-normalized.

Read more details here: https://anismiles.wordpress.com/2010/05/18/cassandra-data-model/

Using Kundera

Kundera defines a range of annotations to describe your Entity objects. Kundera is now JPA1.0 compatible. It builds a range of various Annotations, on top of JPA annotations, to suit its needs. Here are the basic rules:

General Rules

  • Entity classes must have a default no-argument constructor.
  • Entity classes must be annotated with @CassandraEntity @Entity (@CassandraEntity annotation is dropped in favor of JPA @Entity)
  • Entity classes for ColumnFamily must be annotated with @ColumnFamily(“column-family-name”)
  • Entity classes for SuperColumnFamily must be annotated with @SuperColumnFamily(“super-column-family-name”)
  • Each entity must have a field annotation with @Id
    • @Id field must of String type. (Since you can define sorting strategies in Cassandra’s storage-conf file, keeping @Id of String type makes life simpler, you will see later)
    • There must be 1 and only 1 @Id per entity.

Note: Kundera works only at property level for now, so all method level annotations are ignored. Idea: keep life simple. 🙂

ColumnFamily Rules

  1. You must define the name of the column family in @ColumnFamily, like @ColumnFamily (“Authors”) Kundera will link this entity class with “Authors” column family.
  2. Entities annotated with @ColumnFamily are scanned for properties for @Colum annotations.
  3. Each such field will qualify to become a Cassandra Column with
    1. Name: name of the property.
    2. Value: value of the property
  4. By default the name of the column will be the name of the property. However, you fancy changing the name, you can override it like, @Column (name=”fancy-name”)
    @Column (name="email")          // override column-name
    String emailAddress;
    
  5. Properties of type Integer, String, Long and Date are inherently supported, rest all will be serialized before they get saved, and de-serialized while getting read. Serialization has some inherent limitations; that is why Kundera discourages you to use custom objects as Cassandra Column properties. However, you are free to do as you want. Just read the serialization tweaks before insanity reins over you, 😉
  6. Kundera also supports Collection and Map properties. However there are few things you must take care of:
    • You must initialize any Collection or Map properties, like
      List<String> list = new ArrayList<String>();
      Set<String> set = new HashSet<String>();
      Map<String, String> map = new HashMap<String, String>();
      
    • Type parameters follow the same rule, described in #5.
    • If you don’t explicitly define the type parameter, elements will be serialized/de-serialized before saving and retrieving.
    • There is no guarantee that the Collection element order will be maintained.
    • Collection and Map both will create as many columns as the number of elements it has.
    • Collection will break into Columns  like,
      1. Name~0: Element at index 0
      2. Name~1: Element at index 1 and so on.

      Name follows rule #4.

    • Map will break into Columns like,
      1. Name~key1: Element at key1
      2. Name~key2: Element at key2 and so on.
    • Again, name follows rule #4.

SuperColumnFamily Rules

  1. You must define the name of the super column family in @SuperColumnFamily, like @SuperColumnFamily (“Posts”) Kundera will link this entity class with “Posts” column family.
  2. Entities annotated with @SuperColumnFamily are scanned for properties for 2 annotations:
    1. @Column and
    2. @SuperColumn
  3. Only properties annotated with both annotations are picked up, and each such property qualifies to become a Column and fall under SuperColumn.
  4. You can define the name of the column like you did for ColumnFamily.
  5. However, you must define the name of the SuperColumn a particular Column must fall under like, @SuperColumn(column = “super-column-name”)
    @Column
    @SuperColumn(column = "post")  // column 'title' will fall under super-column 'post'
    String title;
    
  6. Rest of the things are same as above.

Up and running in 5 minutes

Let’s learn by example. We will create a simple Blog application. We will have Posts, Tags and Authors.

Cassandra data model for “Authors” might be like,

ColumnFamily: Authors = {
    “Eric Long”:{		// row 1
        “email”:{
            name:“email”,
            value:“eric (at) long.com”
        },
        “country”:{
            name:“country”,
            value:“United Kingdom”
        },
        “registeredSince”:{
            name:“registeredSince”,
            value:“01/01/2002”
        }
    },
    ...
}

And data model for “Posts” might be like,

SuperColumnFamily: Posts = {
	“cats-are-funny-animals”:{		// row 1
		“post” :{		// super-column
			“title”:{
				“Cats are funny animals”
			},
			“body”:{
				“Bla bla bla… long story…”
			}
			“author”:{
				“Ronald Mathies”
			}
			“created”:{
				“01/02/2010"
			}
		},
		“tags” :{
			“0”:{
				“cats”
			}
			“1”:{
				“animals”
			}
		}
	},
	// row 2
}

Create a new Cassandra Keyspace: “Blog”

<Keyspace Name="Blog">
<!—family definitions-->

<!-- Necessary for Cassandra -->
<ReplicaPlacementStrategy>org.apache.cassandra.locator.RackUnawareStrategy</ReplicaPlacementStrategy>
<ReplicationFactor>1</ReplicationFactor>
<EndPointSnitch>org.apache.cassandra.locator.EndPointSnitch</EndPointSnitch>
</Keyspace>

Create 2 column families: SuperColumnFamily for “Posts” and ColumnFamily for “Authors”

<Keyspace Name="Blog">
<!—family definitions-->
<ColumnFamily CompareWith="UTF8Type" Name="Authors"/>
<ColumnFamily ColumnType="Super" CompareWith="UTF8Type" CompareSubcolumnsWith="UTF8Type" Name="Posts"/>

<!-- Necessary for Cassandra -->
<ReplicaPlacementStrategy>org.apache.cassandra.locator.RackUnawareStrategy</ReplicaPlacementStrategy>
<ReplicationFactor>1</ReplicationFactor>
<EndPointSnitch>org.apache.cassandra.locator.EndPointSnitch</EndPointSnitch>
</Keyspace>

Create entity classes

Author.java

@Entity			// makes it an entity class
@ColumnFamily ("Authors")	// assign ColumnFamily type and name
public class Author {

    @Id						// row identifier
    String username;

    @Column (name="email")	// override column-name
    String emailAddress;

    @Column
    String country;

    @Column (name="registeredSince")
    Date registered;

    String name;

    public Author () {		// must have a default constructor
    }

    ... // getters/setters etc.
}

Post.java

@Entity					// makes it an entity class
@SuperColumnFamily("Posts")			// assign column-family type and name
public class Post {

	@Id								// row identifier
	String permalink;

	@Column
	@SuperColumn(column = "post")	// column 'title' will be stored under super-column 'post'
	String title;

	@Column
	@SuperColumn(column = "post")
	String body;

	@Column
	@SuperColumn(column = "post")
	String author;

	@Column
	@SuperColumn(column = "post")
	Date created;

	@Column
	@SuperColumn(column = "tags")	// column 'tag' will be stored under super-column 'tags'
	List<String> tags = new ArrayList<String>();

	public Post () {		// must have a default constructor
	}

       ... // getters/setters etc.
}

Note the annotations, match them against the rules described above. Please see how “tags” property has been initialized. This becomes very important because Kundera uses Java Reflection to read and populate the entity classes. Anyways, once we have entity classes in place…

Instantiate EnityManager

Kundera now works as a JPA provider, and here is how you can instantiate EntityManager. https://anismiles.wordpress.com/2010/07/14/kundera-now-jpa-1-0-compatible/#entity-manager

EntityManager manager = new EntityManagerImpl();
manager.setClient(new PelopsClient());
manager.getClient().setKeySpace("Blog");

And that’s about it. You are ready to rock-and-roll like a football. Sorry, I just got swayed with FIFA fever. 😉

Supported Operations

Kundera supports JPA EntityManager based operations, along with JPA queries. Read more here: https://anismiles.wordpress.com/2010/07/14/kundera-now-jpa-1-0-compatible/#entity-operations


Save entities

Post post = ... // new post object
try {
manager.save(post);
} catch (IllegalEntityException e) { e.printStackTrace(); }
catch (EntityNotFoundException e) { e.printStackTrace(); }

If the entity is already saved in Cassandra database, it will be updated, else a new entity will be saved.
Load entity

try {
Post post = manager.load(Post.class, key); // key is the identifier, for our case, "permalink"
} catch (IllegalEntityException e) { e.printStackTrace(); }
catch (EntityNotFoundException e) { e.printStackTrace(); }

Load multiple entities

try {
List posts = manager.load(Post.class, key1, key2, key3...); // key is the identifier, "permalink"
} catch (IllegalEntityException e) { e.printStackTrace(); }
catch (EntityNotFoundException e) { e.printStackTrace(); }

Delete entity

try {
manager.delete(Post.class, key); // key is the identifier, "permalink"
} catch (IllegalEntityException e) { e.printStackTrace(); }
catch (EntityNotFoundException e) { e.printStackTrace(); }


Wow! Was it fun? Was it easy? I’m sure it was. Keep an eye on Kundera, we will be rolling out sooner-than-you-imagine more features like,

  1. Transaction support
  2. More fine-grained methods for better control
  3. Lazy-Loading/Selective-Loading of entity properties and many more.

Written by Animesh

June 30, 2010 at 7:12 pm

Posted in Technology

Tagged with , , , ,

Design a site like this with WordPress.com
Get started