Couchbase e Java EE

O Couchbase é um banco de dados NoSQL que é baseado em duas tecnologias já existentes, o memcache e o CouchDB. Ou seja, ele é um banco de dados não relacional que possui suporte a duas implementações: chave-valor e documento. O objetivo desse post é falar um pouco das vantagens desse banco, instalação com o docker além do seu uso com Java EE.

 

Qual o diferencial do Couchbase para outros bancos dados?

Os pontos fortes do Couchbase:

  • Ele é bastante visual: Isso mesmo, boa parte das configurações que são feitas por ele é a partir uma interface gráfica bem intuitiva a partir do browser. Com essa interface é possível, criar índices, definir tamanho de memória, juntar clusters, criar buckets, número de memória principal que um bucket utilizará dentre outras coisas.

  • Dois bancos em um: Com o Couchbase é possível trabalhar com documento ou chave ou os dois ao mesmo tempo com um único banco.
  • Uma ferramenta de monitoração excelente: Como parte da sua riquíssima inteface gráfica, com ele é possível saber a saúde dos servidores, quantos servidores estão conectados, processamento, memória, logs e muito mais.
  • N1QL: O N1QL, se pronuncia níquel, é uma query language declarativa que estende do SQL, ou seja, com ele é possível realizar consultas ou alterações no banco de dados de uma maneira bem semelhante ao que se faz com o banco relacional, tecnologia bem popular para a maioria dos desenvolvedores Java. Tendo como diferencial, o N1QL é uma query focado em consultas para JSON.

SELECT * FROM databases WHERE category='NoSQL'

 

  • Um motor de busca integrado: Ainda em fase de desenvolvimento. O motor de busca é um recurso muito comum quando se fala em banco de dados distribuídos, principalmente, para evitar as queries com like e coringa, o famoso like ‘%as%’. Com ele é possível criar índice com Character Filter, Tokenizer, Token Filters, Analizer, Mappings, além de atualizar índice, tudo isso, a partir de uma interface gráfica muito intuitiva.
  • Estruturas especiais para a implementação de chave valor: Assim como o redis, o couchbase possui estruturas especiais, assim com o couchbase é possível utilizar Set, List, Queue e também Map.

Mas porque não utilizar simplesmente o cache?

A grande vantagem está nas suas chamadas específicas, imagine que um sistema armazena a lista dos 1000 produtos mais comprados e é necessário adicionar mais um. Com um simples cache, será necessário serializar os mil elementos, adicionar um novo elemento e apenas em seguida retornar para o banco de dados a chave com mil e um elementos. Com a estrutura especial como uma lista, é necessário apenas enviar o elemento que se deseja adicionar, assim, economiza rede e também processamento. O outro ponto é que os bancos de dados chave-valor foram criados para que os dados tenho um tempo de vida maior que um cache.

 

Instalação

A instalação é bastante prática, existe a possibilidade de fazer a instalação manualmente ou uma imagem docker.

Para mais informações:

https://hub.docker.com/r/couchbase/server/

Durante a instalação:

  • Nas configurações habilite a opção Full-Text Resource
  • Quando estiver configurado e com usuário e senha definida crie um bucket, nesse artigo utilizaremos o bucket “heroes”.
  • Siga as instruções no site do couchbase e crie um índice para o bucket anterior, sugestão de nome, heroes-index.

Para o artigo não ficar muito longo a instalação e a configuração do docker e/ou couchbase não fará parte desse artigo, para informações:

Começando com o modelo

Como nosso objetivo é criar um exemplo simples com Java EE e Couchbase, utilizaremos o CDI 2.0 com Java SE e faremos um simples exemplo com heróis. E com vilões:

 

@Entity
public class Hero implements Serializable {

    @Id
    private String id;

    @Column
    private String name;

    @Column
    private String realName;

    @Column
    private Integer age;

    @Column
    private Set<String> powers;

}

@Entity
public class Villain implements Serializable {

    @Id
    private String id;

    @Column
    private String name;

}

 

Uma coisa importante, é que mesmo não sendo JPA, as anotações são fortemente inspiradas nele. O objetivo do JNoSQL foi tentar usar o máximo a nomenclatura do JPA, porém, levando em consideração que o banco em questão é NoSQL.

 

Configuração

Com o servidor funcionando e rodando o próximo passo será a definir a configuração do banco de dados. Para isso será necessário criar um arquivo dentro do META-INF, no caso o jnosql.json. Como a ideia é exibir as duas APIs, será necessário definir a configuração para as duas APIs, para chave-valor e documentos, porém, poderá ser feito num único documento como mostra o código abaixo:

[
   {
      "description":"The couchbase document configuration",
      "name":"document",
      "provider":"org.jnosql.diana.couchbase.document.CouchbaseDocumentConfiguration",
      "settings":{
         "couchbase-host-1":"localhost",
         "couchbase-user":"root",
         "couchbase-password":"123456"
      }
   },
   {
      "description":"The couchbase key-value configuration",
      "name":"key-value",
      "provider":"org.jnosql.diana.couchbase.key.CouchbaseKeyValueConfiguration",
      "settings":{
         "couchbase-host-1":"localhost",
         "couchbase-user":"root",
         "couchbase-password":"123456"
      }
   }
]

 

O arquivo tem configuração com os seguintes parâmetros:

  • name: o nome da unidade de configuração
  • description: uma descrição, essa informação não é utilizada pelo JNoSQL
  • provider: O nome da classe que será invocada para chamar interpretar as configurações e rodasr as configurações do banco.
  • Settings: São informações específicas de cada banco de dados, no caso do couchbase configuramos os hosts clientes, o usuário e a senha para se conectar no banco de dados.

O arquivo configurado o próximo passo é injetar o as configurações dentro do código.

 

@ApplicationScoped
public class CouchbaseProducer {

    private static final String HEROES = "heroes";

    @Inject
    @ConfigurationUnit(name = "document")
    private DocumentCollectionManagerFactory<CouchbaseDocumentCollectionManager> entityManager;

    @Inject
    @ConfigurationUnit(name = "key-value")
    private BucketManagerFactory<BucketManager> bucketManager;


    @Produces
    public DocumentCollectionManager getManager() {
        return entityManager.get(HEROES);
    }

    @Produces
    public CouchbaseDocumentCollectionManager getCouchbaseDocumentCollectionManager() {
        return entityManager.get(HEROES);
    }

    @Produces
    public List<String> getHeroList() {
        return bucketManager.getList(HEROES, String.class);
    }


    @Produces
    public Set<String> getHeroSet() {
        return bucketManager.getSet(HEROES, String.class);
    }

    @Produces
    public BucketManager getBucketManager() {
        return bucketManager.getBucketManager(HEROES);
    }

}

 

A partir da anotação ConfigurationUnit ele retornará uma fábrica responsável pela criação de gerentes de entidades. Seja para chave valor, BucketManagerFactory, seja para documentos, DocumentCollectionManagerFactory. A partir da produção das classes que serão gerentes de entidades o JNoSQL se encarregará de gerenciar todo ciclo de vidas das outras classes que veremos a seguir.

Documentos

Uma vez configurado e os modelos definidos o próximo passo é realizar as operações básicas no banco de dados. Para isso será utilizado a classe DocumentTemplate, as classes to tipo template realizam operações CRUD de maneira simples e intuitiva, é ela que se encarregará de converter as entidades para a camada de comunicação, aka Diana, que por sua vez enviará para o banco de dados.

public class App {


    public static void main(String[] args) {

        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {

            Hero ironMan = Hero.builder().withRealName("Tony Stark").withName("iron_man")
                    .withAge(34).withPowers(Collections.singleton("rich")).build();
            DocumentTemplate template = container.select(DocumentTemplate.class).get();

            template.insert(ironMan);

            DocumentQuery query = select().from("Hero").where(eq(Document.of("_id", "iron_man"))).build();
            List<Hero> heroes = template.select(query);
            System.out.println(heroes);

        }
    }

    private App() {
    }
}

 

Couchbase é um banco que possui recursos particulares muito interessante, por exemplo, é possível utilizar o motor de busca dentro do couchbase além do uso do N1QL. Como olhar recursos específicos é uma das premissas do JNoSQL. O Couchbase tem uma extensão do DocumentTemplate, o CouchbaseTemplate, essa classe é uma especialização do DocumentTemplate que executa recursos específicos do Couchbase, já mencionado anteriormente.

public class App1 {


    public static void main(String[] args) {

        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {

            Hero ironMan = Hero.builder().withRealName("Tony Stark").withName("iron_man")
                    .withAge(34).withPowers(Collections.singleton("rich")).build();

            CouchbaseTemplate couchbaseTemplate = container.select(CouchbaseTemplate.class).get();
            couchbaseTemplate.insert(ironMan);

            DocumentQuery query = select().from("Hero").where(eq(Document.of("_id", "iron_man"))).build();
            List<Hero> heroes = couchbaseTemplate.select(query);
            System.out.println(heroes);

            MatchQuery match = SearchQuery.match("rich").field("powers");
            SearchQuery search = new SearchQuery("heroes-index", match);
            List<Hero> searchResult = couchbaseTemplate.search(search);
            System.out.println(searchResult);


        }
    }
    private App1() {
    }
}

Além do template é possível utilizar as classes do tipo Repositório, que por sua vez, são interfaces no qual possui métodos comuns além de ser possível adicionar os seus métodos e o JNoSQL se encarregará de implementá-los.

public interface HeroRepository extends Repository<Hero, String> {

    Optional<Hero> findByName(String name);

    Stream<Hero> findByAgeGreaterThan(Integer age);

    Stream<Hero> findByAgeLessThan(Integer age);

    void deleteByName(String name);

}

Mais uma vez, levando em consideração a diversidade, existe a especialização do repositório para o Couchbase, a interface CouchbaseRepository. Essa interface tem como principal recurso a execução do N1QL.

 

public interface HeroRepository extends CouchbaseRepository<Hero, String> {

    Optional<Hero> findByName(String name);

    Stream<Hero> findByAgeGreaterThan(Integer age);

    Stream<Hero> findByAgeLessThan(Integer age);

    void deleteByName(String name);

    @N1QL("select * from heroes where realName= $realName")
    Optional<Hero> find(@Param("realName") String realName);

}

public class App2 {



    public static void main(String[] args) {

        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            Hero ironMan = Hero.builder().withRealName("Tony Stark").withName("iron_man")
                    .withAge(34).withPowers(Collections.singleton("rich")).build();

            HeroRepository repository = container.select(HeroRepository.class).get();
            repository.save(ironMan);

            System.out.println(repository.findByName("iron_man"));
            System.out.println(repository.find("Tony Stark"));

        }
    }

    private App2() {
    }
}```
<h3>Chave valor</h3>
Utilizando a API de chave-valor é possível utilizar as estruturas especiais, a partir da chave. Nesse caso, será utilizando uma List e um Set de String e assim como no documento, existe a classe template para chave valor.


```java
@ApplicationScoped
public class VillainService {

    @Inject
    private List<String> names;

    @Inject
    private Set<String> powers;

    @Inject
    private KeyValueTemplate template;


    public void addName(String hero) {
        names.add(hero);
    }

    public void addPower(String ids) {
        this.powers.add(ids);
    }

    public void put(Villain villain) {
        template.put(villain);
    }

    public Optional<Villain> get(String name) {
        return template.get(name, Villain.class);
    }

    public List<String> getNames() {
        return names;
    }

    public Set<String> getPowers() {
        return powers;
    }
}


public class App3 {


    public static void main(String[] args) {

        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            Villain lock = new Villain();
            lock.setId("lock");
            lock.setName("Lock");

            VillainService service = container.select(VillainService.class).get();


            service.addName("Doctor Doom");
            service.addName("Magneto");
            service.addName("Red Skull");

            service.addPower("Strong");
            service.addPower("Strong");
            service.addPower("fly");

            service.put(lock);

            System.out.println(service.get("lock"));
            System.out.println("The villain powers");
            service.getPowers().forEach(System.out::println);
            System.out.println("The villain names");
            service.getNames().forEach(System.out::println);

        }
    }

    private App3() {
    }
}

A opção de repositório para chave valor também está disponível, porém, como os recursos de busca num banco chave valor são limitados, o recurso de query method em chave valor não é suportado.

public interface VillainRepository extends Repository<Villain, String> {
}

 

Porém, uma vez com a classe repositória definida é possível utilizá-la como documento ou como chave-valor.

 

@Inject
@Database(DatabaseType.COLUMN)
private VillainRepository villainRepository;

@Inject
@Database(DatabaseType.KEY_VALUE)
private VillainRepository villainRepository;

public class App4 {


    public static void main(String[] args) {

        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            Villain lock = new Villain();
            lock.setId("lock");
            lock.setName("Lock");

            Villain doom = new Villain();
            doom.setId("doom");
            doom.setName("Dc Doom");

            VillainRepository repository = container.select(VillainRepository.class, DatabaseQualifier.ofKeyValue()).get();

            repository.save(lock);
            repository.save(doom);
            System.out.println(repository.findById("lock"));
            System.out.println(repository.findById("doom"));

        }
    }

    private App4() {
    }
}


 

 

Com isso foram apresentados os recurso do Couchbase, um banco de dados NoSQL que suporta dois tipos de bancos NoSQL, chave valor e documentos, além de ter uma incrível e rica interface visual na qual é possível fazer diversos tipos de configurações. Também foi possível demonstrar o uso desses recursos em parceria com o JNoSQL.

 

Demo: https://github.com/JNOSQL/artemis-demo/tree/master/artemis-demo-java-se/couchbase
Couchbase: https://www.couchbase.com/

Anúncios

Brincando com bancos do tipo Grafos com Java

 

 

   Os bancos NoSQL estão cada vez mais populares e em diversos segmentos, dentre os seus tipos definidos está o banco do tipo grafos. O banco de grafos tem uma estrutura consideravelmente diferente se comparado aos bancos relacionais, dentre os maiores cases de uso estão as recomendações em sistemas de redes sociais, por exemplo, facebook e linkedin compras e entretenimento inclusive em setores mais conservadores como o financeiro que está o utilizando com objetivo de evitar fraudes bancárias. O objetivo desse artigo é explorar os conceitos dos grafos e como utilizar de maneira bastante simples com Java.

 

Estrutura do Banco do Grafo

O Banco de grafos é composto, basicamente por três elementos:

  • Property: É o menor elemento dentro do grafo, ele é uma tupla, ou seja, é composta por uma chave e valor em que a chave é o nome e o valor é a informação em si.
  • Vertex: Seria semelhante a uma tabela num banco relacional, ele é composto por uma ou mais propriedades.
  • Edge: é o elemento que representa a relação entre os Vertex, seria um elemento de relação comparado com um banco relacionado, porém, esse elemento também é composto por propriedades. O fato do Edge ter propriedades traz uma nova dimensão.

O sentido do grafo é algo muito importante, afinal, o fato de você conhecer uma pessoa não significa que ela te conheça. Assim, de uma maneira geral podemos pensar da seguinte forma:

  • Out: Vertex → action → Vertex o “out” é o sentido da ação, ou seja, eu conheço o homem de ferro, assim: Me → knows → Iron man.
  • In: Vertex ← passive verb ← o “in” é o sentido oposto, ou seja, da reação essa operação é “automaticamente” salva quando você realizar uma operação de ação, por exemplo, o homem de ferro é conhecido por me, assim: Iron man → is known → me.

Provedores de banco de dados

 

O banco de Grafos são compostos por diversos provedores, sendo o mais popular o Neo4J. Assim temos:

Certamente uns dos grandes problemas no grande número de servidores de grafos está no grande número de APIs, uma vez que cada banco tem a sua própria API, por exemplo, faz com que seja muito difícil aprender cada uma delas, sem falar no problema do lock-in, ou seja, caso você opte por um banco de dados caso faça a mudança você perderá toda a sua camada de persistência, sem falar na curva de aprendizado uma vez que para cada novo banco será necessário aprender uma nova API.

 

TinkerPop criando um padrão para os bancos de grafos

Com o objetivo de evitar os problemas mencionados anteriormente, nasceu o TinkerPop. O TinkerPop é um projeto da Apache Foundation que cria uma API comum para realizar as operações de bancos de dados além das Queries. Com o TinkerPop é muito simples realizar queries e sem se preocupar com o Vendor. Atualmente o TinkerPop suporta mais de 30 bancos de dados do tipo grafo.

 

Exemplos que demonstram a vantagem do Grafos em relação ao banco relacional

 

Imagine uma simples estrutura hierárquica, por exemplo, uma cadeia alimentar uma hierarquia empresarial. Como mostra a figura abaixo:

Com o intuito de realizar a comparação, como você percorreria essa cadeia num banco relacional?

Possivelmente, teria que ter uma nova tabela para fazer essa lógica ou coisa semelhante. Então com o TinkerPop você precisaria executar uma query como essa:

g.V().repeat(out("eats")).times(3);//para percorrer a lista três vezes 
g.V().repeat(out("eats")) .until(has("name", "grass"));//para percorrer até achar um Vertez com o nome “grass”.

Simples não?

 

Tá e as minhas entidades?

TinkerPop tem suporte ao Java, com a sua própria API, no entanto, no nosso dia a dia nós trabalhamos com entidades, por exemplo, livros, pessoas dentre outras coisas e para realizar tal comunicação é necessário fazer um parse para cada entidade.

JNoSQL

O JNoSQL é uma ferramenta cujo o objetivo é facilitar a comunicação entre os bancos não relacionais e suas entidades Java, para isso, ele consta com uma API simples, porém, extensível, assim mesmo com uma API padrão é possível extende-la para usar um recurso específico de um banco de dados. O JNoSQL conta com duas sub APIs uma para comunicação, semelhante ao JDBC, e uma para mapeamento, semelhante ao JPA.

JNoSQL e Grafos

 

Para realizar tal integração o JNoSQL utiliza sua camada de mapeamento, aka Artemis, e realiza um parser para o TinkerPop. Assim, para retratar esse grafo no mundo JNoSQL.

1) Realizar o mapeamento das classes Pessoa e livro

@Entity
public class Book {

 

@Id
private Long id;

@Column
private String name;

//getter and setter
}

@Entity
public class Person {

@Id
private Long id;

@Column
private String name;

@Column
private int age;

@Column
private String occupation;

@Column
private Double salary;

//getter and setter
}

 

Injetar a classe GraphTemplate

 

@Inject
private GraphTemplate graph;

//caso você esteja utilizando CDI 2.0 no SE
GraphTemplate graph = container.select(GraphTemplate.class).get();

 

Salvar as entidades

 

Person poliana = Person.builder().withName("Poliana").withAge(25).build();

Book shack = Book.builder().withAge(2007).withName("The Shack").build();

graphTemplate.insert(poliana);
graphTemplate.insert(shack);

 

Criar a relação [Edge]

EdgeEntity<Person, Book> reads = graphTemplate.edge(poliana, "reads", shack);
reads.add("where", "Brazil");

Pronto, você fez sua primeira operação com um grafo.

 

Um caso prático com Grafo {Fazendo queries].

 

Imagine o seguinte cenário:

1) Trabalhamos para uma agência de marketing e queremos fazer uma campanha para um público específico que será:

 

  • Um engenheiro
  • Cujo salário seja maior que 3000
  • Tenha idade entre 20 e 25 anos

Para esse caso, seria simples fazer essa query tanto no banco relacional como no grafo, focando em grafos com o JNoSQL ficará da seguinte forma:

List<Person> developers = graph.getTraversalVertex()
.has("salary", gte(3_000D))
.has("age", between(20, 25))
.has("occupation", "Developer")
.<Person>stream().collect(toList());

 

2) Os amigos desse engenheiro

 

Uma vez definido o nosso target, o nosso engenheiro com características específicas, queremos também trazer seus amigos, afinal, eu mesmo não atendendo os requisitos posso indicar o produto para um amigo que também tenha essas características.

Fazer esse tipo de operação no banco relacional começa a ficar mais difícil, porém, no nosso caso será necessário apenas colocar uma condição, out(“knows”), uma vez que queremos todas as condições e queremos alguém que o engenheiro conheça.

List<Person> result = graph.getTraversalVertex()
.has("salary", gte(3_000D))
.has("age", between(20, 25))
.has("occupation", "Developer")
.out("knows");
3) A pessoa que o engenheiro ama

 

Nesse caso, queremos maior “profundidade” na pessoa que o engenheiro conhece, conhecer não é suficiente, é necessário que ele ama essa pessoa. Imagine que estamos fazendo uma campanha para os dias dos namorados. Nesse caso, utilizaremos um diferente item da query, outE(“knows”), semelhante ao out, porém, ele começa a mapear a relação, o Edge, assim dentro dessa relação eu quero que ele busque uma propriedade, nesse caso, o sentimento de amor.

 

List<Person> love = graph.getTraversalVertex()
.has("salary", gte(3_000D))
.has("age", between(20, 25))
.has("occupation", "Developer")
.outE("knows")
.has("feel", "love")
.bothV()
.<Person>stream()
.distinct()
.collect(toList());

 

 

Os exemplos completos se encontram aqui:

https://github.com/JNOSQL/artemis-demo/tree/master/artemis-demo-java-se

Como essa versão ela ainda está em snapshot é necessário adicionar esse repositório para realizar tests, para mais informações:

https://stackoverflow.com/questions/7715321/how-to-download-snapshot-version-from-maven-snapshot-repository

Com isso, fizemos uma rápida introdução dos bancos do tipo Grafo com Java. Como foi possível demonstrar, mesmo que de maneira bem superficial, é possível realizar diversas buscas que no mundo relacional dariam muito trabalho e demandaria muito tempo de uma maneira bem mais natural.

 

Referências:

Java One 2017 o que vem por ai

 

O JavaOne é um dos maiores e mais importantes evento Java do mundo, ele acontece anualmente no segundo semestre na cidade de São Francisco, Califórnia. É nele que acontece o lançamento das maiores novidades da linguagem e/ou da plataforma. O evento conta com diversas palestras em diversos hotéis na região, o objetivo desse post é fazer sugestão de palestras que você não deveria perder.

 

Grandes Lançamentos:

Estar atento das novidades da plataforma é sempre muito bom para os curiosos e os profissionais. Esse ano em especial, possivelmente, haverá três grandes lançamentos:

Estar atento a essas palestras e ficar por dentro dessas novidades valerá a pena.

JNoSQL

duke-diana.png

O JNoSQL é um dos recentes projetos que eu venho trabalhando nos últimos meses. O JNoSQL é um framework cujo o objetivo é facilitar a integração os bancos não relacionais e o Java EE. A ideia é que ele tenha uma API comum entre esses bancos, porém, levando considerações extenções para comportamentos específicos dos bancos de dados não relacionais.

  • JNoSQL: The Definitive Solution for Java and NoSQL Database [CON4954]
  • Choosing a NoSQL API and Database to Avoid Tombstones and Dragons in Game On! [CON1756]
  • Building a Recommendation Engine with Java EE [CON7608]

 

Palestras dos Outros Brazucas

Assistir palestras dos conterrâneos é sempre muito legal:

  • Build, Test, and Deliver Code Faster with Containers [CON4560]
  • Trust Your Pipeline: Automatically Testing an End-to-End Java Application [CON6121]
  • Secrets of Rock Star Developers (and How to Become One!) [CON7615]
  • Everything You Ever Wanted to Know About Java and Didn’t Know Whom to Ask [CON7613]
  • “Protecting Microservices: Best Practices and Strategies”
  • Java EE 8: Hands-on with the New Features
  • Java Test Automation for REST, Web and Mobile
  • What’s New in Java EE 8? An Overview
  • Trust your Pipeline: Automatically Testing an End-to-end Java Application
  • The Hidden Secret of Java Open Source Projects [CON3754]
  • 5 Pillars of a Successful Java Web Application [CON3755]
  • 12 Factors for Cloud Success [CON5598]
  • Java Test Automation for REST, Web, and Mobile [CON6070]
  • Microservices Data Patterns: CQRS and Event Sourcing [CON7610]
  • Build, Test, and Deliver Code Faster with Containers [CON4560]
  • Trust Your Pipeline: Automatically Testing an End-to-End Java Application [CON6121]
  • Secrets of Rock Star Developers (and How to Become One!) [CON7615]
  • Everything You Ever Wanted to Know About Java and Didn’t Know Whom to Ask [CON7613]
  • Powerful Lessons from Top Java EE Experts [CON7624]

Hackergarten:

Se seu negócio é programar, que tal pôr a mão na massa? O grande barato do é Hackergarten esse! Essa interação é sensacional! Você aprende pondo a mão na prática, ganha networking, e fala diretamente com o responsável pela tecnologia. Pessoalmente, essa é a melhor parte do evento! Afinal, conseguimos falar do Java 9, Java EE, Bean Validation, JSRs, a partir do Adopt a JSR, diretamente com as pessoas que estão na frente do projeto. Isso mesmo, você pode falar diretamente com as pessoas que define a tecnologia que o mundo todo utiliza.

Confira a programação:

https://docs.google.com/spreadsheets/d/1SEVEmYA2r25gtl_w47nFPw-i_s1DPAyHthfeEi1QgLk/edit#gid=0

Networking

 

Sim, conhecer pessoas é sempre muito legal, você pode conhecer seu próximo colega de trabalho, sócio, funcionário dentre outros.  Sem falar que todo dia tem uma festa em um local diferente.

 

[JNoSQL] Começando com Diana API de Colunas

Umas das API que existem no Diana, camada de comunicação do JNoSQL, é a camada de família de colunas. O objetivo desse artigo é falar rapidamente sobre essa API para esse tipo de banco de dados.

No nosso caso será utilizado o Cassandra, assim:

<dependency>
  <groupId>org.jnosql.diana</groupId>
  <artifactId>cassandra-driver</artifactId>
  <version>0.0.1</version>
</dependency>

p.s: Atualmente é necessário adicionar o repositório do JNoSQL para ter acesso as suas dependências:

<repositories>
  <repository>
    <id>jnsoql-repo</id>
    <name>JNoSQL Maven Repository</name>
    <url>https://dl.bintray.com/jnosql/maven/</url>
    <layout>default</layout>
  </repository>
</repositories>


As classes da API de documento seguem a seguinte estrutura:

  • ColumnConfiguration: Classe responsável pela configuração e conexão com o banco de dados, uma vez esse setup varia fortemente em cada banco de dados. Ela costuma ter formato variável
  • ColumnManagerFactory: classe responsável pela criação de uma interface Manager
  • ColumnManager: assim como no JPA, essa classe é a responsável pelo gerenciamento da entidade.
  • ColumnEntity: uma entidade de uma família de colunas
  • Column: Um ColumnEntity é composto por diversas colunas, ele é composto por uma tupla em que a chave é o nome e o valor é a informação propriamente dita. Essa informação poderá ser qualquer valor, variando de cada driver, inclusive uma coluna ou subcoluna.

 

Com o driver do Cassandra é possível realizar o CRUD de maneira simples:

public class App {

    public static final String KEY_SPACE = "newKeySpace";
    public static final String COLUMN_FAMILY = "newColumnFamily";

    public static void main(String[] args) {

        ColumnConfiguration condition = new CassandraConfiguration();

        try(ColumnFamilyManagerFactory managerFactory = condition.get()) {
            ColumnFamilyManager columnEntityManager = managerFactory.get(KEY_SPACE);
            ColumnEntity entity = ColumnEntity.of(COLUMN_FAMILY);
            Column id = Column.of("id", 10L);
            entity.add(id);
            entity.add(Column.of("version", 0.001));
            entity.add(Column.of("name", "Diana"));
            entity.add(Column.of("options", Arrays.asList(1, 2, 3)));

            columnEntityManager.save(entity);

            ColumnQuery query = ColumnQuery.of(COLUMN_FAMILY);
            query.and(ColumnCondition.eq(id));
            Optional<ColumnEntity> result = columnEntityManager.singleResult(query);
            System.out.println(result);

        }


    }
}

Vale salientar que é necessário existir um banco Cassandra instalado e rodando. Com o Cassandra é necessário também informar o IP para que o Diana consiga se conectar. Para isso, é necessário o arquivo diana-cassandra.properties no classpath, além do IP é possível configurar a estrutura inicial utilizando o CQL, Cassandra query language. Assim, ele terá as informações dos bancos que serão conectados. No nosso, exemplo:

cassandra-hoster-1=172.17.0.2
cassandra-threads-number=4
cassandra-initial-query-1=CREATE KEYSPACE IF NOT EXISTS newKeySpace WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 3};
cassandra-initial-query-2=DROP TABLE IF EXISTS newKeySpace.newColumnFamily;
cassandra-initial-query-3=CREATE COLUMNFAMILY IF NOT

Tip: uma maneira simples de instalar o Cassandra é utilizando o docker:
https://hub.docker.com/_/cassandra/

Especializações

O Cassandra possui recurso que irão além da simples API, recursos como nível de consistência e também o CQL.

public class CassandraApp {


    public static final String KEY_SPACE = "newKeySpace";
    public static final String COLUMN_FAMILY = "newColumnFamily";

    public static void main(String[] args) {

        CassandraConfiguration condition = new CassandraConfiguration();

        try(CassandraDocumentEntityManagerFactory managerFactory = condition.get()) {
            CassandraColumnFamilyManager columnEntityManager = managerFactory.get(KEY_SPACE);
            ColumnEntity entity = ColumnEntity.of(COLUMN_FAMILY);
            Column id = Column.of("id", 10L);
            entity.add(id);
            entity.add(Column.of("version", 0.001));
            entity.add(Column.of("name", "Diana"));
            entity.add(Column.of("options", Arrays.asList(1, 2, 3)));

            columnEntityManager.save(entity);

            //common implementation
            ColumnQuery query = ColumnQuery.of(COLUMN_FAMILY);
            query.and(ColumnCondition.eq(id));
            List&ltColumnEntity&gt columnEntities = columnEntityManager.find(query, ConsistencyLevel.LOCAL_QUORUM);

            //cassandra implementation
            columnEntityManager.save(entity, ConsistencyLevel.THREE);
            List&ltColumnEntity&gt entities = columnEntityManager.cql("select * from newKeySpace.newColumnFamily");
            CassandraPrepareStatment cassandraPrepareStatment = columnEntityManager.nativeQueryPrepare("select * from newKeySpace.newColumnFamily where id ?");
            List&ltColumnEntity&gt entityList = cassandraPrepareStatment.bind(10L).executeQuery();
            System.out.println(entities);

        }


    }

}

Com isso concluímos o artigo falando da camada de comunicação do projeto JNoSQL para colunas.

Referências:

[JNoSQL] Começando com Diana API de Documentos

Os bancos documentos, é um dos tipos de bancos não relacionais que armazena e recupera a informação numa estrutura de documentos, semelhante a um documento XML, esse tipo de banco é uma especialização de um banco chave valor.  Umas das API que existem no Diana, camada de comunicação do JNoSQL, é a camada de Documentos. O objetivo desse artigo é falar rapidamente sobre essa API para esse tipo de banco de dados.

 

No nosso caso será utilizado o MongoDB, assim:

<dependency>
    <groupId>org.jnosql.diana</groupId>
    <artifactId>mongodb-driver</artifactId>
    <version>0.0.1</version>
</dependency>

p.s: Atualmente é necessário adicionar o repositório do JNoSQL para ter acesso as suas dependências:

<repositories>
    <repository>
        <id>jnsoql-repo</id>
        <name>JNoSQL Maven Repository</name>
        <url>https://dl.bintray.com/jnosql/maven/</url> 
        <layout>default</layout>
    </repository>
</repositories>

As classes da API de documento seguem a seguinte estrutura:

  • DocumentConfiguration: Classe responsável pela configuração e conexão com o banco de dados, uma vez esse setup varia fortemente em cada banco de dados.
  • DocumentManagerFactory: classe responsável pela criação de uma interface Manager
  • DocumentManager: assim como no JPA, essa classe é a responsável pelo gerenciamento da entidade.
  • DocumentEntity: uma entidade de uma coleção de documentos
  • Document: Um DocumentEntity é composto por diversos documentos, ele é composto por uma tupla em que a chave é o nome e o valor é a informação propriamente dita. Essa informação poderá ser qualquer valor, variando de cada driver, inclusive um outro documento ou subdocumento.

Com o driver do MongoDB é necessário é possível realizar o CRUD de maneira simples:

public class MongoDBApp {

    public static final String DATABASE = "default";
    public static final String DOCUMENT_COLLECTION = "person";

    public static void main(String[] args) {
        String idValue = UUID.randomUUID().toString();
        DocumentConfiguration configuration = new MongoDBDocumentConfiguration();
        try (DocumentCollectionManagerFactory collectionFactory = configuration.get();) {
            DocumentCollectionManager collectionManager = collectionFactory.get(DATABASE);

            DocumentEntity entity = DocumentEntity.of(DOCUMENT_COLLECTION);
            entity.add(Document.of("name", "Daniel Soro"));
            entity.add(Document.of("age", 26));
            entity.add(Document.of("_id", idValue));

            DocumentEntity entitySaved = collectionManager.save(entity);
            Optional<Document> id = entitySaved.find("_id");

            DocumentQuery query = DocumentQuery.of(DOCUMENT_COLLECTION);
            query.and(DocumentCondition.eq(id.get()));
            List<DocumentEntity> documentsFound = collectionManager.find(query);


        }
    }
}

Vale salientar que é necessário existir um banco MongoDB instalado e rodando. Com o MongoDB é necessário também informar o IP para que o Diana consiga se conectar. Para isso, é necessário o arquivo diana-mongodb.properties no classpath. Assim, ele terá as informações dos bancos que serão conectados. No nosso, exemplo:

mongodb-server-host-1=localhost:27017

Tip: uma maneira simples de instalar o mongodb é utilizando o docker: https://hub.docker.com/_/mongo/

Para demonstrar a facilidade de utilizar a API, utilizaremos também um segundo banco de dados, dessa vez, o Couchbase.

Ao utilizar a sua dependência:

<dependency>
    <groupId>org.jnosql.diana</groupId>
    <artifactId>couchbase-driver</artifactId>
    <version>0.0.1</version>
</dependency>

E no código:

public class CouchbaseApp {

    public static final String DATABASE = "default";
    public static final String DOCUMENT_COLLECTION = "person";

    public static void main(String[] args) {
        String idValue = UUID.randomUUID().toString();
        DocumentConfiguration configuration = new CouchbaseDocumentConfiguration();
        try (DocumentCollectionManagerFactory collectionFactory = configuration.get();) {
            DocumentCollectionManager collectionManager = collectionFactory.get(DATABASE);

            DocumentEntity entity = DocumentEntity.of(DOCUMENT_COLLECTION);
            entity.add(Document.of("name", "Daniel Soro"));
            entity.add(Document.of("age", 26));
            entity.add(Document.of("_id", idValue));
            DocumentEntity entitySaved = collectionManager.save(entity);
            Optional<Document> id = entitySaved.find("_id");

            DocumentQuery query = DocumentQuery.of(DOCUMENT_COLLECTION);
            query.and(DocumentCondition.eq(id.get()));
            List<DocumentEntity> documentsFound = collectionManager.find(query);


        }
    }
}

Assim, como no caso do MongoDB, é necessário que o Couchbase seja instalado e configurado é necessário configurar o arquivo diana-couchbase.properties com os Ips dentre outras informações:

couchbase-host-1=localhost
couchbase-user=root
couchbase-password=123456

Tip: Seguindo a mesma dica do MongoDB, uma boa estratégia é utilizar docker: https://hub.docker.com/_/couchbase/

Especializações

Como mencionado, a extensibilidade dos bancos não relacionais é muito importante uma vez que os bancos têm comportamentos específicos. Por exemplo, o Couchbase tem o N1SQL que é uma query específica realizada em cima do JSON que atualmente, apenas o mesmo possui.

public class CouchbaseApp2 {

    public static final String DATABASE = "default";
    public static final String DOCUMENT_COLLECTION = "person";

    public static void main(String[] args) {
        String idValue = UUID.randomUUID().toString();
        CouchbaseDocumentConfiguration configuration = new CouchbaseDocumentConfiguration();
        try (CouhbaseDocumentCollectionManagerFactory collectionFactory = configuration.get();) {
            CouchbaseDocumentCollectionManager collectionManager = collectionFactory.get(DATABASE);

            DocumentEntity entity = DocumentEntity.of(DOCUMENT_COLLECTION);
            entity.add(Document.of("name", "Daniel Soro"));
            entity.add(Document.of("age", 26));
            entity.add(Document.of("_id", idValue));
            DocumentEntity entitySaved = collectionManager.save(entity);
            Optional<Document> id = entitySaved.find("_id");

            JsonObject params = JsonObject.create();
            params.put("id", id.get().get());
            List<DocumentEntity> entities = collectionManager.n1qlQuery("select * from " + DATABASE + " where _id = $id", params);
            System.out.println(entities);
        }
    }
}

Com isso concluímos o artigo falando da camada de comunicação do projeto JNoSQL para documentos, mesmo com a API comum as implementações serão diferentes, por exemplo, a forma de armazenar o valor, json ou bjson, ou a criação automática do campo “_id” ou não, caso ele não tenha sido informado

Referências:

Vamos falar de Padrões NoSQL [Q&A]

duke-diana-min

Com a evolução da tecnologia da persistência, termo como “persistência poliglota” vem se tornando cada vez mais comum para o vocábulo do desenvolvedor. Atualmente, não basta utilizar a linguagem de programação mais apropriada para o problema, mas também utilizar o melhor banco e a melhor forma de persistir tais informações. Uma boa escolha trará certamente uma facilidade na leitura, elasticidade além de performance tanto na leitura quanto na escrita, isso variará de acordo com o objetivo e interesse de cada programa. Com isso, nem todas as aplicações utilizam ou utilizarão as soluções clássicas para persistência, os bancos relacionais. Os bancos NoSQL se tornaram uma solução muito comum para isso. O objetivo desse artigo é esclarecer algumas sobre o mais recente projeto criado, o JNoSQL, dúvidas com relação aos próximos passos dos bancos NoSQL focando na linguagem mais utilizada no mundo, Java, no formato de perguntas e respostas.

Para os detalhes iniciais como definição, já realizei um post sobre isso:

https://otaviojava.wordpress.com/2016/09/10/nosql-java/

O que é o JNoSQL?

O projeto JNoSQL é um projeto que visa a criação de ferramentas para o desenvolvimento de bancos não relacionais, os NoSQL, seu foco será padronizar os bancos NoSQL olhando para sua diversidade, ou seja, criando mecanismo para que o mesmo seja extensivo. Para facilitar o desenvolvimento dessa ferramenta foram criadas duas camadas abaixo do JNoSQL:

A camada de comunicação (aka Diana): Essa camada é responsável por realizar a comunicação entre a aplicação Java e o banco de dados. Essa API será dividida em quatro partes, uma para cada tipo de banco NoSQL. Ele será semelhante ao JDBC do mundo relacional.

A camada de abstração (aka Artemis): semelhante ao ORM ele é responsável por facilitar a abstração para o desenvolvedor Java, ela será orientada a anotações e realizará integrações com outras tecnologias como, por exemplo, o bean validation. O seu coração será o CDI.

Essa divisão tem algumas vantagens:

  • Divisão de problemas (Assim, os bancos de dados darão atenção apenas a camada de comunicação enquanto desenvolvedores de framework darão atenção numa camada superior.
  • Facilidade na implementação, uma vez um novo banco de dados interessado em implementar a API do JNoSQL será necessário apenas implementar a API de comunicação não se preocupando com as outras camadas.
  • Facilidade em componentização, com essa estratégia será possível trocar um dos dois componentes sem que necessariamente exista impacto no outro lado.

Vamos padronizar?

Sim, a ideia é que o resultado do trabalho dentro do JNoSQL seja o foco de padronização. Inicialmente, apenas a camada de comunicação será levada como uma JSR. Esse é um dos motivos que esse projeto tem como parcerias diversos provedores de banco de dados, por exemplo, Cassandra, Hazelcast, OrientDB, couchbase, ArangoDB, MongoDB, HBase além da participação da comunidade (SouJava, LondoJC, ThinkerPOP, dentre outros).

É possível padronizar 100%?

Mesmo os bancos relacionais que já estão a décadas no mercado, não é possível padronizar todo o processo. O mesmo acontece com os bancos NoSQL, inicialmente serão padronizadas as entidades, as hierarquias e algumas ações. Existirão quatro tipos de API, detalhado anteriormente. Mesmo com bancos de dados do mesmo tipo, por exemplo família de coluna com Cassandra e o hbase, existem comportamentos diferentes, por exemplo o nível de consistência e o Cassandra Query Language que existem apenas no Cassandra, para isso a API deverá fornecer a extensibilidade para que seja possível realizar tal operação, no entanto, mesmo com esses comportamentos diferentes o Cassandra continuará lidando as mesmas entidades que o Hbase (Família de Colunas, Colunas, chave da família de coluna, etc.). Por exemplo:

//both implementations (Hbase and Cassandra)
ColumnFamilyEntity entity = …/
entityManager.save(entity);
//just on Cassandra
cassandraEntityManager.save(entity, ConsistencyLevel.ALL);
List entities = entityManager.cql(¨select * from entity¨);

Existirão casos também na qual a API retornará uma exceção de operação não suportada, caso o banco de dados não suporte algumas operações.

Quais métodos serão padronizados?

Nessa primeira versão o foco será padronizar apenas os modelos além de métodos de operação básicas, são eles:

  • Inserir de maneira síncrona, assíncrona, assíncrona com calback além do uso de TTL
  • Atualizar de maneira síncrona, assíncrona, assíncrona com calback além do uso de TTL
  • Deletar de maneira síncrona, assíncrona, assíncrona com calback além do uso de TTL
  • Realizar queries de maneira síncrona e assíncrona

Ou seja, inicialmente as APIs conseguirão realizar as operações de CRUD.

A única exceção será a API de grafos, na verdade, o modelo de grafos já existe uma padronização já conhecida: o ThinkerPOP. A ideia é que a API contenha as partes mais estáveis desse projeto e sua implementação de referência seja uma simples adapter entre os projetos, em outras palavras, todos os bancos que suportam o ThinkerPOP, automaticamente suportarão o Diana.

Mesmo sem padronizar tudo ainda vale a pena?

Nós acreditamos, que sim! Será necessário realizar o primeiro passo e o JNoSQL realizará esse passo. Utilizaremos a estratégia incremental, ou seja, serão dados pequenos passos e pequenos releases para que recebemos rápidos feedbacks sobre a API.

O que acontece com um banco de dados que suporta dois tipos de bancos de dados?

Ele terá que implementar uma API para cada banco de dados que ele suporte. A ideia também é que existe um TCK, que terá como objetivo verificar se a banco de dados suporta ou não corretamente essa API.

Qual é o seu atual status?

O projeto foi recentemente aceito para Eclipse Foundation e estamos recebendo alguns feedbacks sobre a API. Também foi realizada uma apresentação do projeto para o JCP no F2F em Londres: https://goo.gl/2pKwrd

Como faço para ajudar?

Atualmente existem diversas maneiras de ajudar o projeto:

  • Documentação
  • Revisar a documentação já existente
  • Feedback na API
  • Encontrar bugs na implementação
  • Implementar novos drivers
  • Criar exemplos
  • Ajudar na tradução do material para o seu idioma
  • Realizar a palestra sobre esse projeto no seu JUG.

Quais referências estou utilizando?

Estamos utilizando como base diversos projetos existentes, inclusive, além da nomeclatura. Sempre que possível utilizaremos a mesma nomenclatura já existente em outras especificações para facilitar o aprendizado dos desenvolvedores Java.

MicroProfile 1.0

micro-profile-logo

O termo microsserviço, no mundo do desenvolvimento de software, se tornou um termo muito popular. Assim, diversos artigos e diversas ferramentas vem surgindo relacionado a esse tópico. No mundo Java, o Spring vem discutindo sobre esse tópico principalmente após a versão 4.0 e o Spring Boot. Porém, essa é a única solução existente? A resposta é não, recentemente foi lançado uma nova ferramenta no mundo Java, o MicroProfile, e esse foi um dos tópicos mais comentados no JavaOne 2016.

Existem diversos termos e pontos de vista em relação ao o que significa microsserviço. Segundo o Henrique Lobo o microsserviço é: mais uma solução para o problema do alto acoplamento em aplicações corporativas. A diferença é que desta vez estamos atacando aplicações monolíticas.

Ou seja, de uma maneira geral o microsserviço é o oposto de uma arquitetura monolítica, que visualiza a aplicação como um único componente. Uma vez que o componente é a menor unidade dentro do software que pode ser substituída de forma independente. A arquitetura monolítica trabalha numa aplicação com um único componente, ou seja, em termo de escalabilidade caso seja necessário crescer a aplicação, é necessário criar uma instância de todo o componente. Porém, sua arquitetura é mais simples, um grande desafio do microsserviço é separar a aplicação em uma menor unidade, uma separação errônea significa um grande desastre na vida de uma aplicação.

Uma vez conseguindo separar um software em menor componentes ou serviços (o serviço seria um tipo de componente especial que realiza a comunicação utilizando mecanismo remoto como webservice). O microsserviço tem algumas vantagens:

  • Consegue entregar novos recursos mais rapidamente, uma vez que apenas o componente que foi alterado precisará ser atualizado.
  • Com componentes menores, os times também podem ser, seguindo o estilo e a metodologia ágil.
  • A escalabilidade se torna mais simples, no caso, caso o serviço A precise escalar, é necessário apensar que tenha mais uma instância desse recurso A.

Uma vez definido, rapidamente, os conceitos ao redor de aplicações de microsserviços, aplicações monolíticas, componentes, etc. O próximo passo desse post é falar um pouco sobre a iniciativa do MicroProfile.


Q&A MicroProfile

O que é Microprofile?

O Microprofile é uma iniciativa formada por alguns fornecedores Java EE (Red Hat, Payara, Tomitribe, IBM) e Java User Groups (SouJava e London Java Community) cujo o principal objetivo é trazer inovações do microsserviços ao redor ou próximo do mundo Java EE. Atualmente, os servidores, com o comportamento lazy, e as tecnologias elas estão prontas para aplicações de microsserviços, porém, a ideia é tornar a experiência ainda melhor.

microprofile-logos

O seu propósito é bastante simples:

  • Ser um ambiente simples para iterar, testar, inovar e principalmente falhar rapidamente.
  • Após testes, experiência chegar em um comum acordo entre todos.
  • Uma vez, nesse comum acordo e um código estável o próximo passo, e o último, é o processo de padronização.

micro-profile-process

E o Java EE?

O Java EE continua sendo uma série de especificações ou guarda-chuva de especificações bem definidas cujo o foco principal são aplicações focadas ao mundo Web. O Java EE em sua sexta versão trouxe um grande número de novidades, principalmente com o CDI, e sua versão atual, a sétima versão, trouxe ainda mais novidades e melhorias nos recursos existentes.

A próxima versão está sendo trabalhada sob a JSR 366 no qual o líder da especificação é a Oracle.

microprofile-java-ee-road-map

MicroProfile é Java EE?

Não, apesar do envolvimento de diversos fornecedores do mundo Java EE o MicroProfile não é e não tem nada relacionado com o mundo Java EE. Como foi dito previamente, a Oracle é a líder da especificação do Java EE e detentora da sua propriedade intelectual, assim apenas ela pode definir o que é Java EE ou não. Da mesma forma que o CDI a Red Hat é líder da especificação. O fato do MicroProfile utilizar algumas especificações do mundo Java EE não o remete a um proflie do Java EE, do contrário, uma vez que o Spring suporte algumas especificações ele também o seria.

JCP e MicroProfile?

Apesar da exaustiva tentativa de comprar o JCP com todos e qualquer movimento Java, são movimentos totalmente diferentes. O JCP é focado em padrão e o MicroProfile a ideia é que seja um local para inovação. Inovação é o primeiro passo para um padrão, é necessário testar, experimentar e caso seja um sucesso padronizar. Afinal, como padronizar algo que não existe ainda? Faria sentido padronizar a internet na idade média?

Essa resposta também é válida para os framworks do Spring, o JCP não tem nenhuma posição contra o Spring, afinal, eles são muito importantes dando esse primeiro passo, a inovação. Inclusive vários membros do mundo Spring participaram e participam das JSRs, especificação Java, é o caso da JSR 330 que teve a participação do Rod Johnson, conhecido mundialmente como o pai do Spring.

Uma informação importante é que boa parte das instituições que começaram o MicroProfile faz parte do Comitê executivo do JCP.

A ideia do MicroProfile é ser um subset do Java EE?

Não. Como foi dito previamente, o Java EE é uma umbrela de especificação, ou seja, algo estável e fora do mundo de inovação. Além do problema de apenas a Oracle como Spec Leader definir o que é Java EE ou não. Por exemplo, umas das ideias é que nas próximas versões do MicroProfile o Jcache, JSR 107, fazer parte do MicroProfile e essa especificação não está presente no full profile do Java EE 7 e nem se tem previsão de se adicionar essa especificação na próxima versão do Java EE.

JCP + Microprofile

Uma vez bem detalhado os papéis de cada organização/iniciativa, uma para padrão e outro para inovação. Ambos tem algo em comum: O feedback contínuo da comunidade.

O último passo do processo do Microprofile é definir padrões e nesse passo será um trabalho em conjunto com o JCP. Vale lembrar que o padrão traz algumas vantagens:

  • A escolha do fornecedor e/ou escolha da implementação
  • Portabilidade da aplicação
  • Retrocompatibilidade
  • Uma vez estável, reduz o risco do projeto

MicroProfile 1.0

Lançado na proximidade do JavaOne 2016 a versão 1.0 do microprofile vem com três recursos:

  • JAX-RS: Java API for RESTful Web Services (JAX-RS) uma API especificada que traz suporte para a criação de serviços REST.
  • CDI: Contexts and Dependency Injection ferramente especificada para injeção de dependência com contexto.
  • JSON-P: Uma API especificada para realizar parse, gerar, transformar e buscar JSON.

Próximos passos

roadmap-microprofile

Uma vez lançada a sua primeira versão os próximos passos estão em mover para uma fundação e o trabalho para a versão 1.1 do MicroProfile. A ideia original é que seja lançado uma versão a cada seis meses. O backlog para as próximas versões está vasto.

  • Container API
  • Microservic-y annotations (Ex: @CircuitBreaker)
  • Testing
  • Distributed Logging
  • Distributed Tracing
  • OAuth2/OpenID Connect
  • Microservice Security
  • Service Discovery
  • Health Check
  • Configuration
  • Metrics/Monitoring
  • WebSockets
  • JSON-B
  • Bean Validation
  • JPA
  • JTA
  • Concurrency Utilities for Java EE
  • Messaging / Eventing
  • Asynchronous/Reactive Support / Patterns
  • Integration with Reactive / Eventing systems
  • Big Data/NoSQL strong & weak consistency support
  • NetFlix OSS Integration
  • JCache
  • JDK 8 Lambda+Streams
  • EJB Lite
  • Servlets
  • HTTP/2
  • Startup Time
  • Disk Space
  • Memory
  • Uber-jar
  • Java 9 Modularity

JCP é lento em relação ao MicroProfile

Tal comparação não faz sentido algum! Como foi explicado, previamente, são organizações de propósito totalmente diferente. Comparar o JCP só faz sentido se for para outro órgão de padronização como o W3C com o HTML 5, começou o seu trabalho em 2004 e até o presente momento nenhum navegador dá suporte total ao Html 5.

Show me the Code

Dentro do organization do github do microprofile existe alguns exemplos de código o mais recente foi o exemplo utilizado no JavaOne, o microprofile-conference. Porém, também será criado uma simples aplicação demo utilizando microprofile, cujo a implementação será o tomee e maven.

Essa aplicação será realmente simples:

Será um serviço de votos, basicamente, dado uma pergunta a API permitirá uma resposta com sim ou não, sim será algo bem simples já que o principal objetivo é criar um simples serviço.

O primeiro passo é a criação do contador de voto, basicamente ele terá um contador para sim e outro para não, esse recurso terá único para toda aplicação, ou seja, um escopo de aplicação.

@ApplicationScoped
public class VoteCounter {

private final AtomicInteger yes = new AtomicInteger();

private final AtomicInteger no = new AtomicInteger();

public void voteYes() {
yes.incrementAndGet();
}

public void voteNo() {
no.incrementAndGet();
}

public Map<String, Integer> getResult() {
Map<String, Integer> votes = new HashMap<>();
votes.put("yes", yes.get());
votes.put("no", no.get());
return votes;
}
}

Após criar o contador o próximo passo é criar a API para exibir esse recurso.

@ApplicationScoped
@Path("votes")
@Produces(MediaType.APPLICATION_JSON)
public class VoteResource {

@Inject
private VoteCounter voteCounter;

@GET
@Path("question")
public String getQuestion() {
return "Did you like the post?";
}

@POST
@Path("/yes")
public void voteYes() {
voteCounter.voteYes();
}

@POST
@Path("/no")
public void voteNo() {
voteCounter.voteNo();
}

@GET
public Map<String, Integer> getResult() {
return voteCounter.getResult();
}
}

Após feito o código, o próximo passo são os códigos de configuração. Com o JAXRS, definir o caminho que serve como base de todos os URI.

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/resource")
public class ApplicationConfiguration extends Application {
}

Também tem as configurações do web descriptor e do beans.xml para o CDI. Até o momento nada diferente tanto em código quanto em configuração que o desenvolvedor Java EE conhece.

Olhando para o arquivo de configuração do maven, o pom.xml, além de definir a API do Java EE 7 como provida é adicionado um plugin para o tomee:

  • O parâmetro tomeeClassifier define o profile do tomee que será selecionado. Os tipos disponíveis são: webprofile, plus, plusme
  • O parâmetro context define o nome do contexto.

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.soujava</groupId>
    <artifactId>microprofile-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>microprofile-demo</name>

    <url>https://soujava.org.br/</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.ee.version>7.0</java.ee.version>
        <java.se.version>1.8</java.se.version>
        <version.tomee>7.0.1</version.tomee>
        <version.jackson>2.8.2</version.jackson>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>${java.ee.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${version.jackson}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-json-provider</artifactId>
            <version>${version.jackson}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.se.version}</source>
                    <target>${java.se.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.0.0</version>
            </plugin>
            <plugin>
                <groupId>org.apache.tomee.maven</groupId>
                <artifactId>tomee-maven-plugin</artifactId>
                <version>${version.tomee}</version>
                <configuration>
                    <tomeeClassifier>webprofile</tomeeClassifier>
                    <context>${project.artifactId}</context>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

 

Feito isso basta empacotar e em seguida executar o exemplo com os seguintes comandos:

  • mvn clean package tomee:exec -DskipTests
  • java -jar target/microprofile-demo-1.0-SNAPSHOT-exec.jar

Com isso temos os seguintes recursos:

 

Assim, concluímos o material sobre essa novidade para o mundo dos frameworks para microsserviços.

Referências:

O que é arquitetura baseada em micro serviços?

http://www.itexto.net/devkico/?p=1755

Microservices for Java Developers: A Hands-On Introduction to Frameworks and Containers.: http://developers.redhat.com/promotions/microservices-for-java-developers/
Arquitetura de microserviços ou monolítica?

http://blog.caelum.com.br/arquitetura-de-microservicos-ou-monolitica/

Microservices

http://martinfowler.com/articles/microservices.html

Java EE 7 spec:

https://java.net/downloads/javaee-spec/WebProfile.pdf

MicroProfile Site:

http://microprofile.io/

Código exemplo:

https://github.com/soujava/microprofile-demo

Vamos de falar de padrões para o NoSQL em Java

duke-diana

JNoSQL Project

Os bancos NoSQL são bancos de dados que realizam operação de inserção e recuperação de dados utilizando outro modelo que não seja o relacional. Esses tipos de bancos se caracterizam pela velocidade e alta taxa de escalabilidade e vem sendo utilizado com maior frequência em diversos tipos de aplicações, inclusive, aplicações para as instituições financeiras. Como consequência, cresce também o número de vendors ou distribuidores para esse tipo de banco de dados.

Os bancos de dados NOSQL são definidos basicamente pelo seu modelo de armazenamento que são cinco:

Chave-valor: Possui uma estrutura muito semelhante à do java.util.Map, onde podemos armazenar uma chave e seu valor. Normalmente esse valor pode ser qualquer informação.

  • AmazonDynamo
  • AmazonS3
  • Redis
  • Scalaris
  • Voldemort

Orientado a documentos: Este modelo permite armazenar qualquer documento, sem ter a necessidade de definir previamente sua estrutura. O documento e composto por inúmeros campos, com tipos de dados diversos, inclusive um campo pode conter um outro documento, possui uma estrutura semelhante a um arquivo XML.

  • AmazonSimpleDb
  • ApacheCouchdb
  • MongoDb
  • Riak

Família de colunas: Esse modelo se tornou popular através do paper BigTable do Google, com o objetivo de montar um sistema de armazenamento de dados distribuído, projetado para ter um alto grau de escalabilidade e de volume de dados.

  • Hbase
  • Cassandra
  • Scylla
  • Clouddata
  • SimpleDb
  • DynamoDB

Grafos: é uma estrutura de dados que conecta um conjunto de vértices através de um conjunto de arestas. Os bancos de dados de grafo modernos suportam estruturas de grafo multi-relacionais, onde existem tipos diferentes vértices (representando pessoas, lugares, itens) e diferentes tipos de arestas.

  • Neo4j
  • InfoGrid
  • Sones
  • HyperGraphDB

Muli-model database: Alguns bancos de dados possuem a comum característica de ter suporte de um ou mais modelos apresentados anteriormente.

  • OrientDB
  • Couchbase

Comparando com as aplicações Java que utilizam bancos relacionais. É uma boa prática ter uma camada que é responsável por realizar a comunicação entre o banco de dados e o modelo, o bom e velho Data Acess Object ou DAO. Essa camada contém toda a API de comunicação com o banco de dados, olhando no mundo relacional, existem diversos vendors desse tipo de banco de dados, porém, com o padrão JPA o desenvolvedor Java tem algumas vantagens:

  • Não existe lock-in vendor, ou seja, com o padrão a mudança acontece de maneira bem simples e transparente, apenas é necessário trocar o driver.

  • Não é necessário aprender uma nova API para um novo banco de dados uma vez que a API é comum entre todos os bancos de dados.

  • Impacto praticamente zero em realizar a mudança de banco de dados, em alguns momentos é necessário utilizar um recurso específico de um banco de dados.

Nos bancos de dados NOSQL como não existe nenhum padrão pré estabelecido atualmente, assim os desenvolvedores Java enfrentam os seguintes problemas:

  • Lock-in verdor

  • Para um novo banco de dados é necessário aprender uma nova API.

  • Para qualquer mudança de banco de dados o impacto é altíssimo, se perde praticamente toda a camada DAO uma vez que a API muda completamente. Isso acontece mesmo que a mudança seja para o mesmo tipo de banco NOSQL, família de coluna para família de coluna.

Com esse problema, existe um grande esforço ao criar uma API comuns entre esses bancos de dados. É o caso do Spring Data, Hibernate ORM e o TopLink. Como a API JPA já é uma camada muito conhecida entre os desenvolvedores Java, ele é comumente utilizada para facilitar o mapeamento, porém, o seu foco é para os bancos relacionais, assim ele não é suficiente para cobrir todos os casos desses bancos, por exemplo, muitos bancos NOSQL não tem transação ou com essa API não é possível realizar a inserção de forma assíncrona. Assim, infelizmente apesar de o JPA ser uma boa Api ela não contempla todos os comportamentos existentes nos bancos não relacionais. A melhor analogia para esse caso é: Não se pode controlar um avião com os mesmos controles, uma API, de um carro.

A solução para esse caso seria finalmente criar uma especificação que visa cobrir os quatro tipos de bancos de dados citados. A ideia é que essa nova especificação possua sua API bem semelhante ao JPA, uma vez que o desenvolvedor java já está acostumado com o mesmo, além de adicionar novos recursos na API (Suporte a inserção e recuperação de forma assíncrona) e exceções (por exemplo, quando o banco de dados não suportar determinado recurso).

Além da API, a ideia é que exista também a integração com as outras especificações Java, é o caso do bean validation e CDI. Assim, será possível validar os modelos, realizar a injeção de controle de persistência além de criar ciclo de vida de persistência a partir de eventos.

Os bancos não relacionais ou NoSQL são uma tendência e muitos novos vendors existirão, porém, com a criação de uma nova API o desenvolvedor Java não precisará se preocupar em criar uma API e/ou perder toda uma camada quando isso acontecer.

O motivo de se criar uma API é que as já existentes como JPA e JDO não cobrem todo o comportamento esperado para os bancos não relacionais, por exemplo, inserção assíncrona, recuperação assíncrona. Porém, o objetivo é que essa nova API seja o mais próximo semântica mente com as já existentes.

Muitos bancos não relacionais vem surgindo no mundo do desenvolvimento de software, além do seu uso no mundo Java, por exemplo, na última pesquisa sobre Java EE o número de aplicações que usavam essa tecnologia para armazenamento chegava a quase 50%. Permitir a criação do padrão facilitará a visa do desenvolvedor Java, uma vez que não será necessário aprender uma nova API ou a facilitar em realizar a mudança do banco de dados sem ser necessário aprender uma nova API. Porém, assim como nos bancos relacionais, utilizar recursos específicos dos bancos de dados não trará suporte para API, mas o que acontece nas aplicações normais é que boa parte do código é padronizável, ou seja, mesmo que o custo da migração não seja zero, será um número bem menor comparado o atualmente.

Referências:

 

Moneta 1.2 e nova JSR [Próximos passos]

Uma vez entregue a versão 1.1, que dentre diversas coisas corrige diversos bugs, o próximo passo será a modularização da money-api, tanto na sua API como na implementação. Atualmente lidamos com os seguintes pacotes:

  • javax.money – local aonde fica o core da API
  • javax.money.convert – Responsável por realizar a converção de valores, cotação
  • javax.money.format – Responsável pela formatação do Currency e MonetaryAmount
  • javax.money.spi – Service Provider Interface

Com essa nova proposta a ideia é tornar alguns pacotes opcionais:

  • javax.money : obrigatório
  • javax.money.convert: opcional
  • javax.money.format: opcional
  • javax.money.spi: opcional

Do lado da implementação, seguiríamos um passo semelhante, porém, dentro do módulo do convert ele será subdivido em cada implementação, ou seja, um módulo para convert IMF e um para convert ECB.

  • Módulo obrigatório
  • Módulo formatação
  • Módulo SPI
  • Módulo de convert IMF
  • Módulo de convert ECB

Lançamento do Moneta 1.1

 

A implementação de referência da JSR 354, money-api. Lança uma nova versão. O moneta, o nome da implementação de referência do money-api, vem algumas novidades além da correção de mais de vinte bugs. Dentre eles podemos destacar:

Além das correções foram adicionados novos métodos construtores para as implementações do MonetaryAmount.

  • zero(CurrencyUnit currency) – retorna um valor monetário igual a zero com a moeda informada.
  • ofMinor(CurrencyUnit currency, long amountMinor) – retorna o valor monetário a partir da moeda informada e do valor em centavos, por exemplo, o ofMinor(USD, 1234) retorna uma instância USD 12,34.
  • ofMinor(CurrencyUnit currency, long amountMinor, int factionDigits) – retorna o valor monetário a partir da moeda informada e do valor em centavos, por exemplo, o ofMinor(USD, 1234, 2) retorna uma instância USD 12,34. Diferente do método de criação anterior, utiliza o número de dígitos informado ao invés do número de dígitos da moeda.

 

MonetaryAmount money = Money.zero(dollar);
MonetaryAmount oneDollar = Money.ofMinor(dollar, 12_34);

MonetaryAmount money = FastMoney.zero(dollar);
MonetaryAmount oneDollar = FastMoney.ofMinor(dollar, 12_34);

MonetaryAmount money = RoundedMoney.zero(dollar);
MonetaryAmount oneDollar = RoundedMoney.ofMinor(dollar, 12_34);

Outro ponto é que a classe MonetaryUtil foi depreciada, o maior motivo é a duplicidade do nome, afinal, o termo util cabe qualquer coisa. Ao invés disso, foram criadas duas classes utilitárias:
A classe MonetaryOperators : utilitária da interface MonetaryOperator, nele contém diversas implementações interessantes que fazem a vida do desenvolvedor mais fácil, como por exemplo,

MonetaryAmount amount = ////USD 12.23
amount.with(MonetaryOperators.majorPart());//USD 12
amount.with(MonetaryOperators.minorPart());//USD 0.23
amount.with(MonetaryOperators.percent(10));//USD 1.223

MonetaryQueries: utilitária da interface MonetaryQuery, nele contém diversas implementações interessantes e que facilita a extração de informações do montante financeiro.

MonetaryAmount amount = //USD 12.32
amount.query(MonetaryQueries.convertMinorPart());//1232
amount.query(MonetaryQueries.extractMajorPart());//12
amount.query(MonetaryQueries.extractMinorPart());//32

Outra novidade está relacionado a cotação, agora é possível realizar buscas de cotação no IMF.

CurrencyUnit dollar = Monetary.getCurrency("USD");
CurrencyUnit real = Monetary.getCurrency("BRL");

MonetaryAmount money = FastMoney.of(10, dollar);
MonetaryAmount money2 = FastMoney.of(10, real);

LocalDate localDate = Year.of(2009).atMonth(Month.JANUARY).atDay(9);
ExchangeRateProvider provider = MonetaryConversions.getExchangeRateProvider(ExchangeRateType.IMF_HIST);
ConversionQuery query = ConversionQueryBuilder.of().setTermCurrency(dollar).set(localDate).build();

CurrencyConversion currencyConversion = provider.getCurrencyConversion(query);
MonetaryAmount result = currencyConversion.apply(money2);
MonetaryAmount monetaryAmount = money.add(result);

Também foi adicionado um novo recurso para formatar o MonetaryAmount.

MonetaryAmountFormat defaultFormat = MonetaryAmountDecimalFormatBuilder.newInstance().build();
MonetaryAmountFormat patternFormat = MonetaryAmountDecimalFormatBuilder.of("¤ ###,###.00").build();
MonetaryAmountFormat localeFormat = MonetaryAmountDecimalFormatBuilder.of(Locale.US).build();

CurrencyUnit currency = Monetary.getCurrency("BRL");
MonetaryAmount money = Money.of(12, currency);
String format = defaultFormat.format(money);//$12.00
MonetaryAmount moneyParsed = Money.parse(format, defaultFormat);//or using defafult.parse(format);

Com isso foi discutido sobre a nova versão do moneta, a versão 1.1. Nessa versão além de ter realizado diversas correções, foram adicionados novos recursos para formatação, cotação e deixar API cada vez mais fácil. Com essa versão finalizada, os esforços já foram iniciados para a próxima versão que o maior benefício é a modularização do moneta.