Intermediário

Dockerizando o ambiente de desenvolvimento! – Parte 3

Olá pessoal!

Continuando nossa jornada no mundo “Dockerizado“, vamos ver como gerar a imagem que construímos na parte 2 e como listar nossas imagens Docker. Essa é uma parte muito importante, uma vez que veremos se o código que programamos no Dockerfile está correto. Além disso, poderemos definir também o nome da nossa imagem, e sua versão.

O modo mais fácil de gerar uma imagem Docker é entrar no diretório que contém o Dockerfile, e executar o seguinte comando:

docker build .

No entanto, desse modo, sua imagem terá um “nome” aleatório. O mais legal, é definir como será chamada a sua imagem. Isso pode ser feito acrescentando o parâmetro -t. Com ele, você pode definir um nome e uma tag para identificar a sua imagem. Esse comando tem a seguinte sintaxe:

docker build -t <usuario>/<repositorio>:<tag> .

Por exemplo, no caso da imagem do ambiente de desenvolvimento criada pelo Vai de Grails!, o comando utilizado foi assim:

docker build -t vaidegrails/ambiente-grails-basico:3.1.9 .

Nesse caso vaidegrails é o nome do usuário utilizado no Docker Hub, ambiente-grails-basico é o nome do nosso repositório (como se fosse um repositório no GitHub), e 3.1.9 é nossa tag. Note que a tag pode ter o formato que você quiser. Por exemplo, poderia ser v2.

Vamos utilizar como exemplo o Dockerfile mostrado no post anterior. Copie-o e coloque em um diretório qualquer. Entre no diretório e execute o comando:

docker build -t eu/meu-ambiente-grails:1.0.0

Ao executar esse comando, vão aparecer linhas como as seguintes:

Sending build context to Docker daemon 2.048 kB
Step 1 : FROM ubuntu:14.04
14.04: Pulling from library/ubuntu
862a3e9af0ae: Pull complete
6498e51874bf: Pull complete
159ebdd1959b: Pull complete
0fdbedd3771a: Pull complete
7a1f7116d1e3: Pull complete

Serão listados todos os steps (definidos no Dockerfile) que serão executados para a geração da sua imagem. No final, será mostrada a mensagem Successfully built, indicando que sua imagem foi criada com sucesso. Após a geração da sua imagem, você pode confirmar que ela foi criada usando esse comando:

docker images

REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
eu/meu-ambiente-grails   latest              46b0ee272f11        3 months ago        911.7 MB

Esse comando mostra todas as imagens que você tem disponíveis no seu Docker. Podemos reparar que agora a imagem que acabamos de criar encontra-se entre as disponíveis. Também está disponível a imagem ubuntu14.04 que definimos como base para a nossa imagem no Dockerfile. O comando docker images mostra o repository (nome de usuário mais o repositório), tag, id da imagem, quando ela foi criada e o tamanho em disco que cada imagem ocupa.

Agora finalmente poderemos utilizar nossa imagem. Para isso, basta rodar:

docker run -i -t eu/meu-ambiente-grails:1.0.0 /bin/bash

Esse comando, além de rodar nossa imagem (eu/meu-ambiente-grails:1.0.0), define que deve ser criado um pseudo terminal (-t) e que ele deve estar conectado a sua entrada stdin (-i). Por fim, definimos que vamos rodar o programa /bin/bash. Com isso, teremos acesso a um terminal Linux completo, onde poderemos utilizar todos os comandos Linux que estamos acostumados, como ls, cd, mkdir, etc.

Como instalamos o Grails na nossa imagem, poderemos utilizar os comandos do Grails, como:

grails create-app novaApp

No entanto tem um problema, se sairmos da nossa imagem, digitando exit, e colocarmos ela para rodar novamente, veremos que a aplicação que criamos não existe mais. Isso ocorre porque as imagens Docker não são persistentes, ou seja, ao rodarmos ela novamente, tudo estará como definimos na imagem, e todas as alterações realizadas serão descartadas. Além disso, ao rodarmos a aplicação Grails, não conseguiremos acessar pelo browser nossa aplicação.

Mas calma aí, então quer dizer que eu falei de Docker para ajudar a criar um ambiente de desenvolvimento durante 3 posts, e ele tem todas essas limitações? Sim e não. Explico: sim, o Docker tem essas limitações se utilizarmos do modo simples como utilizamos. E não, não precisamos conviver com essas restrições. O Docker tem mecanismos para superarmos esses problemas.

No próximo post verificaremos como manter salvas as aplicações que criamos e como acessá-las diretamente do nosso navegador, tornando ele uma ótima opção para mantermos nosso ambiente de desenvolvimento! Até lá pessoal!

Intermediário

Dockerizando o ambiente de desenvolvimento! – Parte 2

Olá pessoal,

No post passado  nós vimos como instalar o Docker e rodamos uma imagem de exemplo, denominada hello-world (muito original… :D). Até então, não ficou muito claro qual o objetivo de instalarmos o Docker no nosso ambiente de desenvolvimento. No post de hoje, vamos começar a ver algumas das vantagens dessa abordagem, uma vez que vamos definir como será nosso ambiente de desenvolvimento Grails definindo uma imagem do Docker.

No entanto, para isso é necessário primeiro entender alguns conceitos do Docker. Tudo se inicia pela definição de uma imagem, utilizando um Dockerfile, que nada mais é que uma série de passos que devemos executar para que uma máquina fique com as características que desejamos. Fazendo uma analogia muito manjada, o Dockerfile pode ser entendido como a receita de um bolo. A receita não é um bolo, mas contém os passos necessários para a preparação de um tipo específico de bolo.

Um Dockerfile se resume a uma série de instruções, acompanhadas de seus argumentos, no seguinte formato:

INSTRUCTION arguments

Uma convenção adotada é que a instrução deve aparecer sempre com letras maiúsculas, apesar de não ser necessário. Obrigatoriamente, a primeira instrução que deve aparecer  em um Dockerfile é a instrução FROM. Essa instrução define qual é a imagem base que estamos utilizando na nossa “receita”. Uma imagem base não se baseia em nenhuma outra imagem, ou seja, não tem imagens pai. Normalmente essas imagens definem algum sistema operacional, como por exemplo Ubuntu ou CentOS.

Vamos começar então a criar nosso próprio Dockerfile. Assumindo que você esteja em um ambiente Linux, crie primeiro um diretório para armazenar o Dockerfile:

mkdir ambiente-grails-basico

Entre nele, e crie um arquivo Dockerfile com os seguintes comandos:

cd ambiente-grails-basico

touch Dockerfile

Edite o seu Dockerfile com o editor de texto da sua preferência e adicione a seguinte linha:

FROM ubuntu:14.04

Como vimos, essa linha define que nossa imagem base é a versão 14.04 do Ubuntu. Abaixo dessa linha, você pode (e deve :D) definir quem é o responsável por manter essa imagem, utilizando a instrução MAINTAINER, que tem o seguinte formato:

MAINTAINER Seu nome <seu e-mail>

No caso do Vai de Grails! fica assim:

Vai de Grails! <contato@vaidegrails.com>

Agora podemos começar a instalar os programas que queremos na nossa imagem. Como estamos utilizando uma versão do Ubuntu, podemos utilizar o apt-get install, do mesmo modo que fazemos em nossa máquina. É importante dizer, que como não definimos qual usuário estamos utilizando, por padrão estaremos utilizando um usuário ROOT, por tanto não precisamos adicionar o sudo na frente do apt-get install.

Para rodar o apt-get install, ou qualquer outro comando, temos que utilizar a instrução RUN. Vamos instalar inicialmente os seguintes programas:

  • curl – Utilizado para poder baixar o SDKMAN
  • git – Para versionamento de código
  • gitg – Visualização gráfica do repositório git
  • nano – Editor de texto leve
  • software-properties-common – Certificados CA utilizados para instalar o SDKMAN
  • unzip – Utilizado pelo SDKMAN para descompactar arquivos zipados

Essa instalação pode ser realizada com o comando a seguir:

RUN apt-get update \
&& apt-get install -y \
curl \
git \
gitg \
nano \
software-properties-common \
unzip \
&& rm -rf /var/lib/apt/lists/*

Observe que podemos utilizar o caracter ‘\‘ no fim da linha, pois desse modo podemos colocar cada programa que será instalado em uma linha, o que facilita a leitura do Dockerfile, e é uma boa prática estimulada pela equipe do Docker.

O símbolo ‘&&‘ é utilizado quando vamos executar outro comando na sequencia. É importante ressaltar que sempre quando formos utilizar o apt-get install, devemos realizar o apt-get update e separá-los com o ‘&&‘. Se não fizermos eles no mesmo comando RUN, o apt-get install não considerará os repositórios atualizados. Essa é uma característica do Docker.

Por último, sempre é bom remover o conteúdo do diretório /var/lib/apt/lists, uma vez que queremos deixar nossa imagem o mais enxuta possível. O conteúdo desse diretório sempre é recriado quando utilizamos o apt-get update. Para removê-lo utilizamos o comando rm -rf.

Outro componente necessário para configurarmos o ambiente de desenvolvimento Grails é o OpenJDK. A versão 8, com a qual o Grails 3 é compatível, será instalada. Vamos instalá-la adicionando o repositório ppa:openjdk-r/ppa. A adição do repositório e a instalação do OpenJDK é realizada com o seguinte comando:

RUN add-apt-repository ppa:openjdk-r/ppa -y \
&& apt-get update \
&& apt-get install -y openjdk-8-jdk \
&& rm -rf /var/lib/apt/lists/*

Nesse momento, já temos todos os programas necessários para instalarmos o SDKMAN. No entanto, antes de instalarmos esse fácil utilitário, vamos definir um novo usuário Linux. Esse usuário terá como login o nome developer. Para criá-lo, vamos utilizar também o comando RUN e o comando useradd para definir que nosso usuário não terá password (-p “”) e utilizará o bash (-ms /bin/bash):

### Criação do usuário developer ###
RUN useradd -p "" -ms /bin/bash developer

Com o usuário criado, vamos definir a variável de ambiente HOME como sendo o diretório do usuário developer:

ENV HOME /home/developer

E informar ao Docker que ele deve utilizar o usuário developer para executar os próximos comandos:

USER developer

Também é importante definir que o diretório atual de trabalho é o diretório do nosso novo usuário. Essa é uma boa prática também de arquivos Dockerfile, ao invés de utilizar o comando linux cd para definir o diretório atual:

WORKDIR $HOME

Observe que utilizamos a variável HOME que setamos anteriormente. Esse uso é feito por meio da sintaxe $<NOME_DA_VARIÁVEL>, tal como fazemos no Linux.

Podemos agora instalar o SDKMAN seguindo o esse post, obviamente que adaptando para o formato esperado pelo Docker:

RUN curl -s get.sdkman.io | bash
RUN /bin/bash -c "source $HOME/.sdkman/bin/sdkman-init.sh \
&& sdk install grails 3.1.9"

Então primeiro utilizamos o curl para baixar o SDKMAN, e depois rodamos o source para inicializar as variáveis de ambiente utilizadas pelo SDKMAN. Por último, instalamos a versão do Grails, no caso do exemplo, a versão 3.1.9 (a mais atual disponível na data desta postagem).

O último passo que executaremos será expor a porta 8080 do nosso container, que é a porta padrão onde rodam as aplicações do Grails.

# Expoe as portas utilizadas para desenvolvimento
# Porta do Backend
EXPOSE 8080

Com isso, conseguiremos rodar uma aplicação Grails no container, e acessar da nossa máquina. Mas antes disso, teremos que dar um build nele, para gerar a imagem que vai ser utilizada pelo Docker. Esse passo veremos no próximo post dessa série. O projeto no Github, com o Dockerfile criado nesse post pode ser encontrado aqui.

Nos próximos posts veremos como construir essa imagem e como rodá-la em nossos computadores. Qualquer dúvida, ou sugestão, fiquem a vontade para mandar aqui.

Abraços e até a próxima!

“Fazei todas as coisas sem murmurações nem críticas, a fim de serdes irrepreensíveis e inocentes, filhos de Deus íntegros, no meio de uma sociedades depravada e maliciosa, onde brilhais como luzeiros no mundo.”

Filipenses 2:14-15

 

Intermediário

Dockerizando o ambiente de desenvolvimento! – Parte 1

Olá pessoal,

Cada vez mais temos ouvido falar no Docker. Ele é bastante interessante, pois conseguimos criar uma “receita de bolo”, especificando como queremos configurar uma determinada máquina. O Docker cria um container em nossa própria máquina, e esse container será configurado igual especificamos na receita.

Você deve estar pensando, nossa, qual a vantagem disso? Vamos imaginar por exemplo num ambiente de desenvolvimento, onde cada desenvolvedor utiliza uma versão do Linux. Um usa Ubuntu, outro Fedora, outro usa Slackware… Como garantir que todos vão utilizar a mesma versão do Grails e do banco de dados por exemplo?

Um modo seria criar essa receita de bolo, e compartilhá-la entre os desenvolvedores. Sendo assim, todos conseguiriam usar um container igual, independente da sua versão do Linux. É isso o que vamos abordar nessa pequena série. Hoje vamos ver como instalar o Docker. Nas próximas partes veremos como criar uma receita para termos o Grails e o PostgreSQL instalados no container, assim como comandos para gerenciarmos as imagens e containers disponíveis em nosso sistema.

Sendo assim, vamos começar vendo como preparar o ambiente para instalar o Docker no seu Ubuntu ou Mint. Se você utiliza o Mint (como eu), pode rodar o seguinte comando para descobrir em qual versão do Ubuntu seu Mint é baseado:

$ grep "PRETTY_NAME" /etc/os-release | awk '{ print $2 }'

Um exemplo de resposta é:

14.04.4

Nesse caso, sua versão é a 14.04 (Ubuntu Trusty). Portanto, considere essa como sua “versão do Ubuntu”). O resto do tutorial é igual tanto para Mint quanto para Ubuntu.

Preparando o ambiente

Voltando então ao que interessa, vamos começar a instalação do Docker na nossa máquina. O primeiro passo é descobrir a versão do seu kernel Linux. A versão do Kernel deve ser no mínimo 3.10.0. Para isso vamos utilizar o comando uname -r. No exemplo de resposta abaixo, a resposta foi 3.2.0-52-generic:

$ uname -r
3.2.0-52-generic

Ou seja, como a versão 3.2.0 é menor do que a 3.10.0, eu não conseguiria rodar o Docker. Seria necessário atualizar o kernel. Caso você já tenha uma versão igual ou maior a 3.10.0, por exemplo 3.13.0-37-generic, você pode ir par ao próximo passo, que é atualizar o índice de pacotes do APT e instalar o módulo para ele utilizar o protocolo HTTPS, e ter os certificados CA instalados:

$ sudo apt-get update
$ sudo apt-get install apt-transport-https ca-certificates

Podemos então instalar uma nova chave GPG que será utilizada para acessar o repositório do Docker:

sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

É necessário então criar (caso não exista) o arquivo /etc/apt/sources.list.d/docker.list e se ele já existir, deve-se retirar todo o seu conteúdo e adicionar somente a linha abaixo, alterando a parte em negrito de acordo com a versão do seu Ubuntu:

deb https://apt.dockerproject.org/repo versao_do_ubuntu main

Abaixo temos uma listagem com as versões do Ubuntu, e qual o valor da variável versao_do_ubuntu respectiva:

Versão do Ubuntu Variável versao_do_ubuntu
Ubuntu Precise 12.04 ubuntu-precise
Ubuntu Trusty 14.04 ubuntu-trusty
Ubuntu Wily 15.10 ubuntu-wily
Ubuntu Xenial 16.04 ubuntu-xenial

Portanto se sua versão for a Ubuntu Trusty 14.04, a linha que você vai ter no arquivo /etc/apt/sources.list.d/docker.list será:

deb https://apt.dockerproject.org/repo ubuntu-trusty main

Salve seu arquivo e depois atualize novamente o índice do APT:

$ sudo apt-get update

Remova o repositório antigo do Docker (caso exista):

$ sudo apt-get purge lxc-docker

Verifique que o apt está buscando o docker no repositório coreto:

$ apt-cache policy docker-engine

Aqui o resultado foi o seguinte:

docker-engine:
  Instalado: (nenhum)
  Candidato: 1.11.2-0~precise
  Tabela de versão:
     1.11.2-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.11.1-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.11.0-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.10.3-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.10.2-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.10.1-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.10.0-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.9.1-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.9.0-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.8.3-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.8.2-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.8.1-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.8.0-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.7.1-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.6.2-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.6.1-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.6.0-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages
     1.5.0-0~precise 0
        500 https://apt.dockerproject.org/repo/ ubuntu-precise/main amd64 Packages

Mais uma vez vamos atualizar o índice do APT:

$ sudo apt-get update

Agora os próximos passos vão depender da versão do seu Ubuntu:

Versões Ubuntu Xenial 16.04 e Ubuntu Wily 15.10

Basta instalar o o pacote linux-image-extra:

$ sudo apt-get install linux-image-extra-$(uname -r)

Versão Ubuntu Trusty 14.04

Instale o linux-image-extra e o apparmor

$ sudo apt-get install linux-image-extra-$(uname -r) apparmor

Versão Ubuntu Precise 12.04

Instale o linux-image-extra, o apparmor, o linux-image-generic-lts-trusty, o linux-headers-generic-lts-trusty, o xserver-xorg-lts-trusty e o libgl1-mesa-glx-lts-trusty

$ sudo apt-get install linux-image-extra-$(uname -r) apparmor linux-headers-generic-lts-trusty xserver-xorg-lts-trusty libgl1-mesa-glx-lts-trusty

O xserver-xorg-lts-trusty e o libgl1-mesa-glx-lts-trusty são opcionais, somente necessários se você estiver em uma máquina com ambiente gráfico.

Faça o reboot do sistema:

$ sudo reboot

Instalando (finalmente) o Docker

Agora que tudo já foi preparado, vamos atualizar o índice de pacotes do APT:

$ sudo apt-get update

Instale o Docker (aaewwww \o/)

$ sudo apt-get install docker-engine

Inicialize o daemon do Docker:

$ sudo service docker start

E finalmente mande rodar o Hello World do Docker para verificar se tudo está funcionando adequadamente:

$ sudo docker run hello-world

A saída desse comando será mais ou menos a seguinte:


Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world

a9d36faac0fe: Pull complete
Digest: sha256:e52be8ffeeb1f374f440893189cd32f44cb166650e7ab185fa7735b7dc48d619
Status: Downloaded newer image for hello-world:latest

Hello from Docker.
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker Hub account:
https://hub.docker.com

For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/

Pronto, o Docker está instalado corretamente! Acompanhem o Vai de Grails! para as próximas partes da série. Qualquer dúvida ou comentário, postem aqui!

Obrigado e até a próxima pessoal!

Iniciante

Mostrando os comandos SQL do Hibernate

Pessoal,

Hoje vou apresentar uma dica fácil de fazer, mas muito útil. Vamos apresentar no log da nossa aplicação os comandos SQL executados pelo Hibernate. Desse modo, é possível ver os creates, selects, updates, deletes e outras consultas que estão sendo executadas pela nossa aplicação e analisar se estão de acordo com o esperado.

Para isso, vamos criar um projeto novo sobre futebol:

grails create-app Futebol

Vamos também adicionar uma nova classe chamada Campeonato:

grails create-domain-class com.vaidegrails.futebol.Campeonato

E vamos alterar a classe para que fique assim:

package com.vaidegrails.futebol

class Campeonato {

    String nome
    static constraints = {
    }
}

Vamos também alterar nosso BootStrap.groovy para manipular o banco de dados, assim conseguiremos ver o que o Hibernate está fazendo:

import com.vaidegrails.futebol.Campeonato

class BootStrap {

    def init = { servletContext ->
        10.times { i->
            Campeonato campeonato = new Campeonato(nome: "Campeonato $i").save(flush: true)
        }

        def todosCampeonatos = Campeonato.all
        def campeonato3 = Campeonato.findByNome("Campeonato 3")
        def campeonato5 = Campeonato.findByNome("Campeonato 5")
        campeonato3.delete(flush: true)
        campeonato5.nome = "Campeonato 3"
        campeonato5.save(flush: true)
    }
    def destroy = {
    }
}

Nesse trecho de código, primeiro utilizamos o código 10.times, o qual significa que vamos repetir 10 vezes o código que está dentro da clousure (delimitada pelas chaves). Essa síntaxe do Groovy é muito legal, pois fica bem legível e semântico o código. Definimos a variável i, que é o índice do looping. E então criamos um campeonato usando essa variável i. Então teremos 10 campeonatos salvos na base, desde o Campeonato 0, até o Campeonato 9.

Após salvar os campeonatos, vamos obter do banco todos os campeonatos cadastrados (Campeonato.all). Também vamos buscar pelo nome (Campeonato.findByNome) os campeonatos 3 e 5.

Por fim, vamos remover do banco de dados o campeonato 3 (campeonato3.delete) e alterar o nome do Campeonato 5 para Campeonato 3, e salvar essa atualização (campeonato5.save).

Se executarmos o código nesse momento, não veremos o log do Hibernate. Para conseguirmos ver o log, vamos alterar a seção datasource do arquivo application.yml para que fique assim:

dataSource:
    pooled: true
    jmxExport: true
    driverClassName: org.h2.Driver
    username: sa
    password:
    logSql: true

Observe em negrito o logSql: true. É essa a configuração responsável por exibir o log. Ao rodarmos novamente a aplicação, conseguiremos ver a seguinte saída no console:

Hibernate: insert into campeonato (id, version, nome) values (null, ?, ?)
Hibernate: insert into campeonato (id, version, nome) values (null, ?, ?)
Hibernate: insert into campeonato (id, version, nome) values (null, ?, ?)
Hibernate: insert into campeonato (id, version, nome) values (null, ?, ?)
Hibernate: insert into campeonato (id, version, nome) values (null, ?, ?)
Hibernate: insert into campeonato (id, version, nome) values (null, ?, ?)
Hibernate: insert into campeonato (id, version, nome) values (null, ?, ?)
Hibernate: insert into campeonato (id, version, nome) values (null, ?, ?)
Hibernate: insert into campeonato (id, version, nome) values (null, ?, ?)
Hibernate: insert into campeonato (id, version, nome) values (null, ?, ?)
Hibernate: select this_.id as id1_0_0_, this_.version as version2_0_0_, this_.nome as nome3_0_0_ from campeonato this_
Hibernate: select this_.id as id1_0_0_, this_.version as version2_0_0_, this_.nome as nome3_0_0_ from campeonato this_ where this_.nome=? limit ?
Hibernate: select this_.id as id1_0_0_, this_.version as version2_0_0_, this_.nome as nome3_0_0_ from campeonato this_ where this_.nome=? limit ?
Hibernate: delete from campeonato where id=? and version=?
Hibernate: update campeonato set version=?, nome=? where id=? and version=?

Nas 10 primeiras linhas, vemos os inserts dos campeonatos. É importante ressaltar que os sinais de interrogação representam parâmetros passados pelo nosso código em Grails, nesse caso, o version e o nome.

Depois dos inserts, temos um select na tabela campeonato retornando todos os registros. Na sequencia, dois selects passando como parâmetro o nome, para retornar os campeonatos 3 e 5. As duas últimas linhas são referentes a remoção do Campeonato 3 e a atualização do campeonato 5, definindo um novo version e um novo nome.

Esses casos que apresentei são bem simples, mas pode ser muito interessante mostrar as consultas realizadas em casos mais complexos, onde existem joins, por exemplo.

Outra questão importante, é que ao configurar o logSql na seção datasource, igual fizemos, todos os ambientes de desenvolvimento (development, test e production). Isso não é desejável. Para mostrar o log somente em development, basta colocar o logSql: true dentro da seção environments -> development -> datasource, ou seja, o arquivo application.yml deve ficar assim:

environments:
    development:
        dataSource:
            dbCreate: create-drop
            url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
            logSql: true

E claro, retirar do datasource (caso você tenha colocado lá no início). Espero que tenham gostado! Qualquer dúvida, ou sugestão, postem comentários. Até a próxima.

Iniciante

Como instalar o Grails?

Pessoal,

Anteriormente eu havia mostrado um jeito de configurar um ambiente de desenvolvimento Grails. Muita coisa mudou de lá pra cá. Novas versões do Grails surgiram, o gvm mudou e passou a se chamar sdkman, entre outras.

O que não mudou foi a facilidade de instalar o Grails. Existem dois modos muito simples de instalá-lo na sua máquina. O primeiro é utilizando o sdkman (http://sdkman.io):

curl -s “https://get.sdkman.io” | bash
source “$HOME/.sdkman/bin/sdkman-init.sh
sdk install grails 3.1.6

O segundo é o Jenv (http://jenv.io/):

curl -L -s get.jenv.io | bash jenv install grails
source /home/bruno/.jenv/bin/jenv-init.sh
jenv install grails 3.1.4

O sdkman tem a versão mais recente do Grails (3.1.6), o Jenv por enquanto está um pouco atrasado (3.1.4), mas os dois são muito práticos e úteis, e permitem instalar diversos outros frameworks. Vale a pena dar uma olhada!

Se você não passar a versão ao dar os comandos sdk e jenv, ele instala a versão mais recente disponível. Agora não tem mais desculpa para não “ir de Grails”😀.

Após a instalação basta digitar Grails no terminal e ser feliz. Caso você utilize o IntelliJ Idea (recomendo), configure ele para usar o Grails a partir de um dos diretórios abaixo (use o primero se utilizou o sdkman para instalar e o segundo se usou o Jenv):

/home/nome_do_seu_usuario/.sdkman/candidates/grails/3.1.6

/home/nome_do_seu_usuario/.jenv/candidates/grails/3.1.4

E é só isso! Abraços e até a próxima.

Intermediário

Personalizando os marshallers das classes de domínio

Pessoal,

Depois de um bom tempo sem publicar nada, volto aqui para passar algumas dicas para vocês! O tema de hoje são os marshallers. Segundo a Wikipedia, marshalling (que é o processo que um marshaller executa) pode ser entendido como:

“…the process of transforming the memory representation of an object to a data format suitable for storage or transmission, and it is typically used when data must be moved between different parts of a computer program or from one program to another.”

Ou seja, o marshaller atua para transformar a representação de um objeto para um formato de dados adequado para armazenamento ou transmissão. Normalmente ele é usado quando ocorre a transferência de dados entre partes diferentes de um programa, ou de um programa para outro.

Um jeito fácil para compreender o primeiro caso é pensar em uma aplicação desktop para gerenciamento de projetos. Imaginemos que você quer associar uma tarefa a um de seus subordinados. Você clica na tarefa, e depois seleciona o nome do colaborador em uma lista. É importante perceber que nessa tela somente aparecerá o nome do colaborador, mas por exemplo, na sua classe Colaborador, você pode ter mais informações como data da contratação, cargo, etc. Portanto, você pode ter um marshaller para disponibilizar somente as informações que importam para essa tela em específico, ao invés de utilizar a classe inteira.

Do mesmo modo, uma aplicação mobile pode acessar um webservice que retorne o nome de lojas em uma determinada região e suas coordenadas geográficas para mostrá-las em um mapa. Nesse caso, a aplicação que oferece o webservice, pode ter mais informações da loja, as quais não quer expor, como por exemplo o nome do proprietário. Novamente pode-se criar um marshaller específico para esse webservice, preservando assim as demais informações.

O Grails registra marshallers padrão para cada classe de domínio. Eles exibem, por padrão, todas as informações da classe, exceto campos com os seguintes nomes: password, dateCreated e lastUpdated. No entanto, é possível definir nossos próprios marshallers para cada uma de nossas classes de domínio. Os marshallers são extremamente úteis, principalmente quando queremos expor nossa API, seja em JSON, XML, ou qualquer outro formato, por isso é importante saber personalizá-los.

Agora que vimos a função e a importância dos marshallers, vamos criar uma ne ova aplicação (marshallers) ver como criar um marshaller para uma classe de domínio no Grails. O primeiro passo é criar uma classe de domínio. Vamos criar a classe Car, conforme a classe exibida a seguir:

package com.vaidegrails

class Car {

    String maker
    String model
    BigDecimal price
    Integer speed
    Integer power

    static constraints = {
    }
}

Nessa classe definimos as informações que queremos armazenar de cada carro. Para esse exemplo, vamos considerar que é importante armazenar os nomes da montadora (maker) e do modelo do carro (model), o preço (price), a velocidade máxima (speed) e a potência (power).

Vamos agora gerar um controller padrão para essa classe. O resultado será o seguinte:

package com.vaidegrails

import static org.springframework.http.HttpStatus.*
import grails.transaction.Transactional

@Transactional(readOnly = true)
class CarController {

    static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]

    def index(Integer max) {
        params.max = Math.min(max ?: 10, 100)
        respond Car.list(params), model:[carCount: Car.count()]
    }

    def show(Car car) {
        respond car
    }

    def create() {
        respond new Car(params)
    }

    @Transactional
    def save(Car car) {
        if (car == null) {
            transactionStatus.setRollbackOnly()
            notFound()
            return
        }

        if (car.hasErrors()) {
            transactionStatus.setRollbackOnly()
            respond car.errors, view:'create'
            return
        }

        car.save flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.created.message', args: [message(code: 'car.label', default: 'Car'), car.id])
                redirect car
            }
            '*' { respond car, [status: CREATED] }
        }
    }

    def edit(Car car) {
        respond car
    }

    @Transactional
    def update(Car car) {
        if (car == null) {
            transactionStatus.setRollbackOnly()
            notFound()
            return
        }

        if (car.hasErrors()) {
            transactionStatus.setRollbackOnly()
            respond car.errors, view:'edit'
            return
        }

        car.save flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.updated.message', args: [message(code: 'car.label', default: 'Car'), car.id])
                redirect car
            }
            '*'{ respond car, [status: OK] }
        }
    }

    @Transactional
    def delete(Car car) {

        if (car == null) {
            transactionStatus.setRollbackOnly()
            notFound()
            return
        }

        car.delete flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.deleted.message', args: [message(code: 'car.label', default: 'Car'), car.id])
                redirect action:"index", method:"GET"
            }
            '*'{ render status: NO_CONTENT }
        }
    }

    protected void notFound() {
        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.not.found.message', args: [message(code: 'car.label', default: 'Car'), params.id])
                redirect action: "index", method: "GET"
            }
            '*'{ render status: NOT_FOUND }
        }
    }
}

Podemos agora alterar o método init do nosso arquivo BootStrap.groovy, e utilizá-lo para adicionar alguns carros na base. Com isso, conseguiremos testar o marshaller padrão do Grails. Após as alterações, o método init ficará do seguinte modo:

def init = { servletContext ->
        new Car(maker: "Porsche", model: "GT9-R", price: 680000, speed: 414, power: 824).save(failOnError: true)
        new Car(maker: "Audi", model: "RS6 MTM Clubsport", price: 500000, speed: 350, power: 537).save(failOnError: true)
        new Car(maker: "Mercedes-Benz", model: "C 63 AMG Edo Competition T-Model ", price: 280000, speed: 343, power: 441).save(failOnError: true)
        new Car(maker: "BMW", model: "M3 Manhart Racing V8R Biturbo ", price: 300000, speed: 338, power: 513).save(failOnError: true)

}

Após colocar a aplicação para rodar, podemos acessar o métodos de listagem e detalhes do CarController e especificar o formato esperado. Por exemplo, para JSON, podemos entrar nos seguintes endereços:

[{"id": ​1, "maker": "Porsche", "model": "GT9-R", "power": ​824, "price": ​680000.00, "speed": ​414},
{"id": ​2, "maker": "Audi", "model": "RS6 MTM Clubsport", "power": ​537, "price": ​500000.00, "speed": ​350},
{"id": ​3, "maker": "Mercedes-Benz", "model": "C 63 AMG Edo Competition T-Model", "power": ​441, "price": ​280000.00, "speed": ​343},
{"id": ​4, "maker": "BMW", "model": "M3 Manhart Racing V8R Biturbo", "power": ​513, "price": ​300000.00, "speed": ​338}]
{"id": ​1, "maker": "Porsche", "model": "GT9-R", "power": ​824, "price": ​680000.00, "speed": ​414}

Vamos supor que na verdade queremos apenas expor o id, o maker e a velocidade do carro. Além disso, queremos alterar o nome do campo speed para “speed (in kilometers)“.

Para fazer isso, basta acrescentar o seguinte trecho de código no método init do BootStrap.groovy:

JSON.registerObjectMarshaller(Car, { car ->
    return [id: car.id, model: car.model, 'speed (in kilometers)': car.speed]
})

Alguns detalhes são importantes aqui. O primeiro detalhe é que estamos chamando o método estático registerObjectMarshaller da classe JSON. Com ele, estamos informando que queremos registrar um marshaller somente quando o tipo de conteúdo gerado for JSON. Para o XML por exemplo, continuaremos usando o marshaller padrão.

O segundo detalhe, é que esse método aceita dois parâmetros. O primeiro parâmetro, é a classe para a qual desejamos registrar o marshaller. Nesse exemplo a classe Car. Se tivéssemos outras classes, elas continuariam usando o marshaller padrão tanto para JSON, quanto para XML. O segundo parâmetro é uma closure. Essa closure tem como parâmetro o objeto que passará pela transformação do marshaller. Nós colocamos o nome dele de car, mas poderíamos ter definido qualquer nome. O retorno dessa closure, deve ser um mapa, com o nome das propriedades do JSON e seus respectivos valores. No nosso caso, as chaves são “id”, “model” e “speed (in kilometers)” e os valores são os valores do id, do model e da speed do nosso objeto.

Viu só como é fácil? Ao parar e rodar novamente a aplicação, tanto o método de listagem quanto o de detalhes apresentarão um registro conforme o que definimos. Por exemplo, ao acessar novamente o endereço http://localhost:8080/car/show/1.json temos a seguinte resposta:

{"id": ​1, "model": "GT9-R", "speed (in kilometers)": ​414}

Se acessarmos a versão XML http://localhost:8080/car/show/1.xml veremos que continua sendo utilizado o marshaller padrão:

<car id="1">
    <maker>Porsche</maker>
    <model>GT9-R</model>
    <power>824</power>
    <price>680000.00</price>
    <speed>414</speed>
</car>

Gostaram dessa dica? Mas a pergunta que fica é: Como eu faço caso queira ter mais de um marshaller em JSON para a classe Car? É possível? Bom, esse é um assunto para um próximo post, mas sim, é possível!

Comentem, façam perguntas, críticas, elogios. Tá com preguiça de copiar os códigos daqui? Clone o projeto funcional em:
https://github.com/vaidegrails/marshallers

Por último, mas muito mais importante, uma citação da Bíblia:

Não se amoldem ao padrão deste mundo, mas transformem-se pela renovação da sua mente, para que sejam capazes de experimentar e comprovar a boa, agradável e perfeita vontade de Deus.
Romanos 12:2

							
Retrospectiva

Os números de 2015

Pessoal, finzinho do ano, e os duendes de estatísticas do WordPress.com prepararam um relatório para o ano de 2015 do Vai de Grails! Esse é apenas o primeiro ano, então os números estão modestos, por isso espero contar com a ajuda de vocês para que 2016 seja ainda melhor!

Aqui está um resumo do relatório:

Um bonde de São Francisco leva 60 pessoas. Este blog foi visitado cerca de 1.600 vezes em 2015. Se fosse um bonde, eram precisas 27 viagens para as transportar.

Clique aqui para ver o relatório completo