Nova versão do Easy-Cassandra 2.0.0

Veja nesse artigo que a nova versão do banco Cassandra trouxe como principal diferencial o uso de coleções (list, map, set). Conheça um pouco mais sobre o seu uso junto com o framework Easy-Cassandra

O Cassandra, o banco de dados não relacional orientados à família de colunas, é um banco feito para trabalhos de alta performance, alta escalabilidade horizontal além de ser tolerante a falhas. Uma das grandes vantagens de sua arquitetura de escalabilidade horizontal é que se pode fazer com que cresça o número de nós a partir de uma alta demanda e diminuir em períodos de pouco processamento, ideal para a plataforma nas nuvens tão comumente discutido. Em sua nova versão trouxe o novo Cassandra Query Language, CQL, a versão 3.0, que dentre suas melhorias está no trabalho de coleções, chaves compostas.

Com tantas melhorias o único problema é a maneira de tirar proveito de maneira eficiente desses novos recursos, afinal o foco do desenvolvedor Java deve ser solução em OO e sobre tudo no objetivo da aplicação, regras de negócio, a ponto de que esse parser entre banco e negócio seja o menor possível. Com esse objetivo surgiu o Easy-Cassandra, seu foco é facilitar o desenvolver Java utilizar esses recurso sem em nenhum momento desfocar no objetivo e no negócio da aplicação. Nessa nova versão o framework ORM trouce as seguintes melhorias:

Nessa nova versão houve algumas quebras de retrocompatibilidades, isso deve ao uso do java Driver e de suas consultas totalmente focadas no CQL 3. Essa pequena quebra está apenas no modo em que é criado a classe ponte entre o cassandra e o seu objeto java já que as anotações de mapeamento continuam tendo como base as anotações do JPA 2.0.

Como a ideia no futuro é que exista o banco MongoDB, foi criada a interface org.easycassandra.persistence.Persistence, assim os novos bancos de dados e o Cassandra terão esse contrato, assim será possível, trocando apenas a implementação, mudando o banco de dados não relacional.

Listagem 1: Interface org.easycassandra.persistence.Persistence

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); } A interface do cassandra org.easycassandra.persistence.cassandra.PersistenceCassandra, como todos os novos bancos compatíveis herda do Persistence e adiciona alguns pequenos recursos.

Listagem 2: Interface do Cassandra herdando de Persistence

public interface PersistenceCassandra extends Persistence { List findByIndex(Object index, Class bean); Long count(Class bean); }

A classe responsável por gerar a implementação continua sendo a org.easycassandra.persistence.cassandra.EasyCassandraManager, mas ela se tornou um enum, sim isso mesmo um enum!, já que o objetivo é que ele seja único nada mais natural que o singleton natural cedido pela própria JVM. Só é necessário passar o host e o keyspace, caso não existe ele se responsabilizará por você. Para adicionar objetos mapeados no Cassandra basta usar o método addFamilyObject passando o .class, assim como no caso do keyspace, caso ele não existe ele se responsabilizará em criar ou alterar a column family, para o seu objeto.

Como base nisso o DAO base poderia ficar da seguinte maneira:

Listagem 3: Dao base

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

Uma outra estratégia seria a mudança de interface para a persistence, assim esse DAO seria para todos os bancos de dados nosql que o framework for sendo compatível. Uma vez pronto o nosso projeto base, vamos falar um pouco sobre o mapeamento dos objetos. Os desenvolvedores java que conhecem o JPA já estarão familiarizado como o modelo de mapeamento.

Listagem 4: Mapeamento

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

Assim os campos são:

Listagem 5: Classe Linux Distribution

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

Além desses campos essa nova versão trouxe novas anotações para se poder trabalhar com listas dentro do cassandra que são:

Exemplos do uso dessa interação abaixo:

Listagem 6: Exemplo de interações

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

Uma vez mapeado e com o DAO pronto o seu uso se torna muito fácil, já que as buscas são semelhantes a única diferença está no objeto mapeado e o retorno.

Listagem 7: DAO Mapeado

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); } } Outro recuso importante é que foi solicitado pela comunidade, abraços ao pessoal da Bern na Suiça, é a possibilidade de usar outro keyspace diferente do definido no persistence. Para isso basta usar o schema na anotação @Table como mostra o exemplo abaixo:

Listagem 8: Usando o schema

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

A nova versão do Easy-Cassandra, 2.0.0, ainda está em fase beta, assim é necessário realizar mais testes, mas com isso tem noção do que vem está por vir. Uma das coisas legais do framework é pioneirismos do projeto, até então ele é o primeiro ORM do cassandra que utiliza os recursos do 100% CQL 3.0. Isso graças ao grande trabalho por parte da comunidade.

Nesse link você pode conferir o projeto no GitHub: https://github.com/otaviojava/Easy-Cassandra

Artigos relacionados