Skip to main content

New Easy-Cassandra 2.0.0 Beta

Posted by otaviojava on July 23, 2013 at 3:45 PM PDT

The Cassandra's data base is a NOSQL column family's oriented, is a data base made to work of high performance, scalability and fault tolerant. In your new version, it gets some improvements like Cassandra Query Language third version, CQL 3.0 with storage with collections and key complex.

With improvements in Cassandra, there is a one problem: How do I use all potential of the Cassandra without lost focus in my Java Project? The Java's developers worry about your business rules and works in object oriented. With this objective was born the Easy-Cassandra, a Cassandra's ORM, which does do the Java's developers put focus in application and use the all potential of Cassandra easily. In this new version the ORM brought:

* Complex rowkey (a key with tow or more keyrow).
* Map some collections (java.util.List, java.util.Set, java.util.Map).
* find automatically the others clusters which do part of the same cluster.
* Objects may use a different keyspace using schema.
* Custom storage way with CustomData annotation.

All this only using JPA mapping, annotation whose the developers know very well.

  
public interface Persistence {

    boolean insert(Object bean);

    boolean delete(Object bean);

    boolean update(Object bean);

    List findAll(Class bean);

    T findByKey(Object key, Class bean);

    boolean deleteByKey(Object key, Class bean);

    boolean executeUpdate(String query);

}

The base of all persistence now is the org.easycassandra.persistence.Persistence and the org.easycassandra.persistence.cassandra.PersistenceCassandra extends this interface.

  
public interface PersistenceCassandra extends Persistence {

    List findByIndex(Object index, Class bean);

    Long count(Class bean);
}

The class which creates the PersistenceCassandra's implementations is org.easycassandra.persistence.cassandra.EasyCassandraManager, now it is a enum because is more easy and natural to JVM do Singleton this way. Use the getPersistence within this class and pass the host and keyspace default to persistence. To add class whose the frameworks will manager use addFamilyObject and put the class what will represent a column family.

  


public class PersistenceDao {

    private static final String KEY_SPACE = "javabahia";
    private static final String HOST = "localhost";
    private PersistenceCassandra persistence;
    private Class baseClass;
   

    public PersistenceDao(Class baseClass) {
        this.baseClass = baseClass;
        persistence = EasyCassandraManager.INSTANCE.getPersistence(HOST, KEY_SPACE);
        EasyCassandraManager.INSTANCE.addFamilyObject(baseClass, KEY_SPACE);
       
    }

    public boolean insert(T bean) {
        return persistence.insert(bean);
    }

    public boolean remove(T bean) {
        return persistence.delete(bean);
    }

    public boolean removeFromRowKey(K rowKey) {
        return persistence.deleteByKey(rowKey, baseClass);
    }

    public boolean update(T bean) {
        return persistence.update(bean);
    }

    public T retrieve(Object id) {
   
        return   persistence.findByKey(id, baseClass);
    }

    public List listAll() {
        return persistence.findAll(baseClass);
    }

    public List listByIndex(Object index) {
        return persistence.findByIndex(index, baseClass);
    }

    public Long count() {
        return persistence.count(baseClass);
    }

    public boolean executeUpdateCql(String string) {
        return persistence.executeUpdate(string);
    }

}

The mapping of a object is in JPA 2.0.

  
@Entity(name = "person")
public class Person implements Serializable {

    private static final long serialVersionUID = 3L;
   
    @Id
    private Long id;
   
    @Index
    @Column(name = "name")
    private String name;
   
    @Column(name = "born")
    private Integer year;
   
   
    @Enumerated
    private Sex sex;
   
   
    @Embedded
    private Address address;

//getter and setter
}

The annotations:

* @Id to indicates a field is a rowkey, a field to recorevy others fields and this column is unique by row.
* @Enumerated indicates a field is an enum.
* @Embedded indicates there is a object which has another others fields within itself.
* @Index indicates a field is a Cassandra's index, so can recovery a information such a @ID, a rowkey to Cassandra, but not necessarily is unique.
* @Table or @Entity indicates this object is a column family.
* @EmbeddedId indicates this field is a complex object, a object what has another rows which are rowkeys.

  

@Entity(name="linux")
public class LinuxDistribuition {

    @EmbeddedId
    private IdLinux id;
   
    @Column
    private String guy;
   
    @Column
    private String version;
   
    @Column(name="descriptions")
    private String descriptions;
//getter and setter
}

public class IdLinux {
   
   
    @Column
    private String name;
   
    @Column
    private String kernelVersion;
//getter and setter
}

Also there are new annotations to work with Collections:

* SetData informs the field is java.util.Set, it is necessary inform a class of the collection within a classData.
* ListData informs the field is java.util.List, you should inform a class of the collections within classData.
* MapData inform the field is java.util.Map, you should inform the key and value of the map's collection with classkey and classValue respectively.

  
@Entity(name="resumebook")
public class Book {

    @Id
    @Column(name="booksname")
    private String name;
   
    @MapData(classKey=Long.class,classValue=String.class)
    private Map chapterResume;
//getter and setter
}


@Entity(name="shopping")
public class ShoppingList {

    @Id
    private String name;
   
    @Column(name="day")
    private Date day;
   
    @ListData(classData=String.class)
    @Column(name="frutis")
    private List fruits;
   
    @Column(name="storeName")
    private String storeName;
//getter and setter
}

@Entity(name="contact")
public class Contact implements Serializable {

    @Id
    @Column(name="id")
    private String name;
   
   
    @Column(name="emails")
    @SetData(classData=String.class)
    private Set emails;
//getter and setter
}

After map a object and the DAO done, using generics the only thing what changes is the constructor, because we defined the class of the bean and of the key when the persistence dao is created.

  

public class BookDAOTest {

private PersistenceDao persistence=new PersistenceDao(Book.class);
   
   
    @Test
        public void insertTest() {
        Book book = getBook();
        Assert.assertTrue(persistence.insert(book));
    }


    private Book getBook() {
        Book book = new Book();
        book.setName("Cassandra Guide ");
        Map resumeChapter=new HashMap();
        resumeChapter.put(1l, "this chapter describes new resources in cassandra and improvements with CQL");
        resumeChapter.put(2l, "Understanding the architecture");
        resumeChapter.put(3l, "Installing DataStax Community");
        resumeChapter.put(4l, "Upgrading Cassandra");
        resumeChapter.put(5l, "Initializing a cluster");
        resumeChapter.put(6l, "Security");
        resumeChapter.put(7l, "Database design");
        resumeChapter.put(8l, "Using the database");
        resumeChapter.put(9l, "Database internals");
        resumeChapter.put(10l, "Configuration");
        resumeChapter.put(11l, "Operations");
        resumeChapter.put(12l, "Backing up and restoring data");
        resumeChapter.put(13l, "Cassandra tools");
        resumeChapter.put(14l, "Troubleshooting");
        resumeChapter.put(14l, "Troubleshooting");
        resumeChapter.put(15l, "References");
        book.setChapterResume(resumeChapter);
        return book;
    }
   
   
    @Test
    public void retrieveTest() {
        Book book=persistence.retrieve(getBook().getName());
        Assert.assertNotNull(book);
    
    }
   
    @Test
    public void removeTest() {
        persistence.remove(getBook());
        Assert.assertNull(persistence.retrieve(getBook().getName()));
        persistence.insert(getBook());
    }
   
}


public class ContactsDAOTest {
private PersistenceDao persistence=new PersistenceDao(Contact.class);
   
   
    @Test
        public void insertTest() {
        Contact contacts = getContact();
        Assert.assertTrue(persistence.insert(contacts));
    }


    private Contact getContact() {
        Contact contacts = new Contact();
        contacts.setName("Shrek ");
        contacts.setCyte("far far away");
        contacts.setEmails(new HashSet());
        contacts.getEmails().add("shreck@shrek.org");
        contacts.getEmails().add("shreck@farfaraway.far");
        return contacts;
    }
   
   
    @Test
    public void retrieveTest() {
     Contact contact=persistence.retrieve(getContact().getName());
     Assert.assertNotNull(contact);
    
    }
    @Test
    public void removeTest() {
        persistence.remove(getContact());
        Assert.assertNull(persistence.retrieve(getContact().getName()));  
    }
   
}



public class ShoppingListDAOTest {

    private PersistenceDao persistence=new PersistenceDao(ShoppingList.class);
   
   
    @Test
    public void insertTest() {
       
        Assert.assertTrue(persistence.insert(getPolianaShoppingList()));
    }
    private ShoppingList getPolianaShoppingList() {
        ShoppingList shopping=new ShoppingList();
        shopping.setDay(new Date());
        shopping.setName("Poliana");
        shopping.setFruits(new LinkedList());
        shopping.getFruits().add("Orange");
        shopping.getFruits().add("beans");
        shopping.getFruits().add("rice");
        return shopping;
    }
   
    @Test
    public void retrieveTest() {
     ShoppingList list=persistence.retrieve(getPolianaShoppingList().getName());
     Assert.assertNotNull(list);
    }
    @Test
    public void removeTest() {
        ShoppingList list=persistence.retrieve(getPolianaShoppingList().getName());
        persistence.remove(list);
        list=persistence.retrieve(getPolianaShoppingList().getName());
        Assert.assertNull(list);
    }
   
}

Other two improvements are define a keyspace different of the default, for this use the Table's annotations with schema parameter.

  
@Table(name="drink",schema="schemaA")
public class Drink implements Serializable {

@Id
    private Long id;
   
    @Index
    @Column(name = "name")
    private String name;
   
    @Column(name = "flavor")
    private String flavor;

Another resource is beyond the default objects (Long, Integer, Boolean, Date. Float, etc.) you also can do a different way to storage an information with CustomData annotation. By default it will serialize the object and put in Cassandra for this the object should implements the java.io.Serializable, but you may do another custom create a class whose implements org.easycassandra.persistence.cassandra.Customizable and pass itself in classCustmo, parameter of CustomData annotation.

  
@Entity(name="product")
public class ProductShopping {

    @Id
    private String name;
   
    @CustomData(classCustmo=ProductsCustomData.class)
    private Products products;
//getter and setter
}


}

public class Products implements Serializable {

private static final long serialVersionUID = 1L;

private String nome;

private Double value;

private String country;
//getter and setter
}


public class ProductsCustomData implements Customizable{

public ByteBuffer read(Object object) {
Products products=(Products)object;
StringBuilder result=new StringBuilder();
result.append(products.getNome()).append("|");
result.append(products.getValue()).append("|");
result.append(products.getCountry());
return ByteBuffer.wrap(result.toString().getBytes());

}

public Object write(ByteBuffer byteBuffer) {
    byte[] result = new byte[byteBuffer.remaining()];
        byteBuffer.get(result);
String values[]=new String(result).split("\\|");

Products products= new Products();
products.setNome(values[0]);
products.setValue(Double.valueOf(values[1]));
products.setCountry(values[1]);
return products;
}
}



public class ProcutShoppingDAO {
    private PersistenceDao dao = new PersistenceDao(ProductShopping.class);
   
    @Test
    public void insertTest(){
        ProductShopping shopping=new ProductShopping();
        shopping.setName("notebook");
        Products products=new Products();
        products.setNome("Dell Ubuntu");
        products.setCountry("Brazil");
        products.setValue(1000d);
        shopping.setProducts(products);
        Assert.assertTrue(dao.insert(shopping));
       
    }
   
    @Test
    public void retrieveTest(){
        ProductShopping shopping=dao.retrieve("notebook");
        Assert.assertNotNull(shopping);
       
    }
}

The new version of Easy-cassandra still in beta phase, so there is a probability find some bugs and errors. The project need your help to get better do part.

Link: https://github.com/otaviojava/Easy-Cassandra