Escalabilidade de aplicações Web: futuro vs presente = Cassandra vs Mysql+memcached

Muito interessante o post do Digg que fala sobre as tecnologias, estratégias e problemas que o Digg (assim como outras aplicações gigantes na Web) vive ao redor do tema escalabilidade.

Quando se trata de aplicações web populares como Digg, Twitter e Facebook, escalabilidade se torna um desafio e tanto, e manter a aplicação com redundância, performance e consistência gera um custo grande de manutenção e monitoramento.

Até muito recentemente, ou até hoje mesmo, muitos desses sites usam a solução de Mysql + memcached para poderem suportar o nível de escalabilidade necessário. Por exemplo, até o fim de 2008, o Facebook possuía mais de 800 servidores de memcached para poder servir mais de 28 terabytes de cache. É mole? 28 Tera de cache! E isso, só para poder servir a leitura de dados em cache.  Na hora de escrever os dados, aí usa-se uma solução de Mysql configurado com Master-Slave, e muitas vezes com particionamento vertical.

O fato atualmente é: esta solução não está mais dando conta do recado. Alguns desses sites estão saindo da solução com Mysql+memcached e estão indo para o mundo não SQL. E o que muitos deles estão adotando é o Cassandra.

Cassandra é um banco de dados distribuído, altamente escalável, baseado no conceito de BigTable.

É isso. E vem por aí uma nova era para as soluções de aplicações web de alto volume.
Vale a leitura do post do Digg.
Abcs

GWT + Grails = Rock n Roll: Parte 2 - Separados e falando com RequestBuiler e JSON

Este post é a Parte 2 da sequência de posts sobre o tema GWT + Grails = Rock n Roll. Você pode ver a Parte 1 aqui. Nesta primeira mostrei como criar uma aplicação baseada em GWT e Grails. Para juntar os dois, usei o plugin Grails-Gwt.

Neste post de hoje, depois de alguns dias lendo sobre GWT, fazendo testes e brincando com a aplicação criada no post da Parte 1, resolvi tentar também desenvolver outra aplicação com GWT + Grails mas desta vez sem usar o plugin. Desta forma, poderia eu mesmo decidir se prefiro com ou sem o Plugin. Este post, então, mostrará como criar uma solução composta de duas aplicações isoladas, uma GWT e outra Grails, que se falam via troca de dados usando JSON.

Separando Grails e GWT em duas aplicações distintas

Como descrevi na Parte 1, não usar o plugin e ter duas aplicações distintas (uma GWT e outra Grails) significa ter que lidar com a Same Origin Policy (SOP) em tempo de desenvolvimento. Em produção simplesmente pode-se dar um jeito de levar os arquivos Html, Css e Javascript gerados pelo GWT para o propeto grails (em último caso, basta copiar e colar de um lado para o outro). Mas em desenvolvimento é preciso lidar com SOP de uma maneira mais produtiva do que ter que ficar copiando e colando de um lado para outro. A maneira mais simples que encontrei foi usando uma ProxyServlet, originalmente criada por Jason Edward, e depois evoluída por Matt Raible. O código fonte desta classe eu peguei no projeto Grails OAuth Plugin criado pelo M Raible. É simples de usar, e resolve o problema facilmente. O que ela faz neste nosso contexto é:

  • a aplicações GWT no cliente faz uma requisição para o servidor;
  • a aplicações GWT no servidor recebe esta requisição e repassa para a aplicação Grails
  • a aplicação Grails recebe esta requisição e responde JSON
  • a aplicação GWT recebe esta resposta JSON e repassa para o cliente GWT

Desta forma não precisamos nos preocupar com SOP.

O que se ganha em fazer isso? Para que, afinal, quero ter duas aplicações separadas (uma GWT e outra Grails). Bom, isso acaba sendo uma decisão pessoal de cada um, ok? Mas para mim, comecei a achar mais interessante seguir os padrões de cada projeto. Um projeto GWT, segundo as recomendações, deve ser organizado de uma maneira, com determinada árvore de diretórios, etc. Pode não ser seguido, mas é um padrão recomendado. Então, porque não seguir e falar a mesma lingua em chats, fóruns de discussão, novos desenvolvedores na equipe, etc?

Além disso, separar os dois projetos provoca uma reflexão conceitual interessante sobre arquitetura de aplicações ricas para a web (RIA - Rich Internet Applications). Ao separar, você está literalmente, fisicamente, implementando a arquitetura SOFEA (Service Oriented Front-End Architecture). SOFEA foi muito bem apresentado no artigo Life Above the Service Tier (vale a leitura. Este pessoa hoje em dia criou um grupo sobre este assunto e tem um site em: ThinServerArchitecture.com ).

Numa arquiteturea SOFEA, toda a lógica de interface com usuário está sendo rodada no cliente, no nosso caso, no browser. Aqui então, as camadas View e Contoller da aplicação terão um projeto só pra elas (o projeto GWT). Ou seja, o desacoplamento é total. Você simplesmente desacopla o máximo que pode o tal do Front-End. Isso é interessante na minha opinião, pois aí a sua aplicação servidora, que roda no servidor, ela acaba por ter a responsabilidade apenas de prover serviços para a aplicação de Front-End (User Interface - UI). Parece até que estamos voltando para o conceito Cliente x Servidor, e de certa forma, estamos sim, mas um pouco diferente, pois é um Thin Client, onde apenas as regras de interface e controle de fluxo de navegação estão no cliente. Todas as demais regras de negócio, estão e devem estar no servidor.

Outras duas justificativas para esta separação em duas aplicações são:
  • Pode ficar mais simples equipes diferentes trabalharem cada uma em um projeto diferente
  • Cada projeto pode ser versionado independentemente
Bom, depois de todas essas justificativas, o fato é: criei uma nova aplicação que é composta por um projeto GWT responsável pelo Front-End, e por outro projeto Grails responsável pelo Back-End (provendo serviços, lembra SOA?). Veja que as coisas começam até a ficar mais coesas e desacopladas. Interessante resultado....

Comunicação entre GWT e Grails com JSON

Para a comunicação entre o Front-End e o Back-End, escolhi usar JSON. A aplicação grails pode facilmente gerar uma resposta JSON, enquanto que a aplicação GWT pode facilmente consumir JSON. Então, sendo o JSON um formato leve para troca de dados, e sendo ele facilmente servido e consumido pelo Grails e GWT respectivamente, acho que JSON é uma boa escolha. Mas, se você preferir trabalhar com XML, ou outro formato proprietário, a decisão é sua.

Portanto, para criarmos esta nova aplicação, basta criar um novo projeto GWT, e outro Grails.

Aplicação Front-End (GWT)

Eu estou usando o Eclipse com o plugin do GWT, portanto, para criar um novo projeto basta clicar na opção de criar novo projeto GWT do Eclipse. Criei este projeto GWT chamado rockgwtfront, com o pacote com.rockgwt.front

O wizard do Eclipse já cria uma classe EntryPoint, o arquivo XML de configuração do Module, e também cria um Serviço RPC de exemplo. Mas não precisaremos deste serviço para este exemplo, portanto, pode apagar o pacote com.rockgwt.front.server e o pacote com.rockgwt.front.shared, e também pode apagar os arquivos GreetingService.java e GreetingServiceAsync.java do pacote com.rockgwt.front.client. Depois altere a classe Rockgwtfront.java para não usar mais este Serviço RPC. No final das contas, fiquei com a classe de EntryPoint abaixo:

package com.rockgwt.front.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONException;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;

public class Rockgwtfront implements EntryPoint {

    public void onModuleLoad() {
        final Button sendButton = new Button("Get Hendrix songs");
        final FlexTable songsTable = new FlexTable();

        // We can add style names to widgets
        sendButton.addStyleName("sendButton");
        
        sendButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                String hendrixSongsServiceUrl = GWT.getHostPageBaseURL();
                if(!GWT.getHostPageBaseURL().contains("rockgwt"))
                    hendrixSongsServiceUrl += "rockgwt/";
                    
                hendrixSongsServiceUrl += "hendrix/songs";
                RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, hendrixSongsServiceUrl);
                builder.setTimeoutMillis(10000);
                builder.setCallback(new RequestCallback() {
                    
                    @Override
                    public void onResponseReceived(Request request, Response response) {
                        if (response.getStatusCode() == 200) {
                            
                            JSONValue v = JSONParser.parse(response.getText());
                            JSONArray songs = v.isArray();
                            if(songs != null){
                                updateBacklogItemsTable(songsTable, songs);
                            }
                            else{
                                throw new JSONException("O retorno nao veio como um objeto de Projeto"); 
                            }
                        } else {
                            onError(request, new RequestException(response.getText()));
                        }
                    }
                    
                    @Override
                    public void onError(Request request, Throwable exception) {
                        Window.alert(exception.getLocalizedMessage());
                    }
                });
                try {
                    builder.send();
                } catch (RequestException e) {
                    Window.alert(e.getLocalizedMessage());
                }
            }
        });

        RootPanel.get("sendButtonContainer").add(sendButton);
        RootPanel.get("songsTableContainer").add(songsTable);

    }
    
    private void updateBacklogItemsTable(FlexTable songsTable, JSONArray songs) {
        songsTable.clear();
        for (int i=0; i<songs.size(); i++) {
            JSONObject item = songs.get(i).isObject();
            songsTable.setWidget(i, 0, new Label(item.get("name").isString().stringValue()));
            songsTable.setWidget(i, 1, new Label(item.get("album").isString().stringValue()));
        }
                    
    }
}


Veja que a classe acima utiliza um RequestBuilder para realizar a requisição no servidor. Este RequestBuilder é uma classe do GWT que pode ser usada para fazer requisições remotas. Com ela, as requisições são sempre assíncronas, SEMPRE. Veja que passei um objeto Callback que será chamado quando esta requisição voltar do servidor. Assim, neste callback posso fazer o que for preciso com a resposta recebida. Neste caso, devo fazer o parse do JSON para poder trabalhar com os dados retornados. No fim de tudo, pego esses dados e os apresento numa tabela, só isso.

Veja que a aplicação GWT espera um retorno JSON no seguinte formato:
[{"name":"Hey Joe", "album":"Are You Experienced"},
{"name":"Bold as Love", "album":"Axis: Bold as Love"}]

Portanto, é preciso que a aplicação Grails retorne um JSON exatamente neste formato acima.

É preciso adicionar ao ~/rockgwtfront/war/WEB-INF/lib  do projeto os JARs necessários para a ProxyServlet citada acima. Portanto, adicione commons-fileupload-1.2.1.jar, httpclient-4.0.1.jar, e httpmime-4.0.1.jar ao lib. Crie a classe ProxyServlet. Você pode baixar o OAuth 1.3 e pegar o ProxyServlet de lá. Em seguida, é preciso configurar o web.xml para que ele saiba que o ProxyServlet existe. Vou mapear este proxyServlet para ele ser chamado para toda requisição que tenha o padrão /rockgwtback/*. Veja abaixo:


<web-app>
  <servlet>
        <servlet-name>RockServletservlet-name>
        <servlet-class>com.rockgwt.front.servlet.ProxyServletservlet-class>
        <init-param>
            <param-name>proxyHostparam-name>
            <param-value>localhostparam-value>
        init-param>
        <init-param>
            <param-name>proxyPortparam-name>
            <param-value>8080param-value>
        init-param>
        <init-param>
            <param-name>secureparam-name>
            <param-value>falseparam-value>
        init-param>
    servlet>
  
    <servlet-mapping>
        <servlet-name>RockServletservlet-name>
        <url-pattern>/rockgwt/*url-pattern>
    servlet-mapping>
  
 
  <welcome-file-list>
    <welcome-file>Rockgwtfront.htmlwelcome-file>
  welcome-file-list>
web-app>

Veja que o servlet-mapping mostra como deverá ser a url a ser chamada pelo cliente GWT para o servidor Grails. ( /rockgwtback/* ).
Aplicação Back-End (Grails)

Para o projeto Grails, ou você cria normalmente por linha de comando, ou pode até criar pelo Eclipse mesmo se estiver usando o STS (SpringSource Tool Suite). Criei este projeto Grails chamando-o de rockgwtback. Para este projeto, criei um controller chamado HendrixController que possui a action "musics". Esta action retorna uma lista de músicas do Hendrix. Veja abaixo:

package com.rockgwt.back.controller

class HendrixController {
    def index = { }

    def songs = {
        println "chegou"
        render(builder: 'json') {
                songs = array {
                       song name: '1) Hey Joe', album: 'Are You Experienced'
                       song name: '2) Bold as Love', album: 'Axis: Bold as Love'
                   }
        }
    }

}

Alterei também o nome da aplicação dentro do application.properties, colocando app.name=rockgwt, pois foi assim que eu coloquei a URL da requisição lá em cima, na aplicação GWT, e também no servlet-mappging do web.xml

É isso!

Assim, temos um sistema rodando com Grails e GWT, independentes um do outro, mas juntos formando a nossa aplicação. Faltaria aqui neste exemplo uma forma de juntar as duas aplicações para produção. Provavelmente faria isso com o Maven. Em produção, então, seria uma única aplicação mesmo.

Grails + GWT = Rock n Roll: Parte 1 - Desbravando um novo mundo

Meus amigos leitores (quantos devem ser estes leitores? deixe uma mensagem dizendo que vc é meu leitor! rs...) ... Bem vindos ao maravilhoso mundo do Rock n Roll. As bandas de rock muitas vezes são mal vistas por pessoas mais tradicionais. Outras vezes são veneradas por jovens rebeldes. Não importa. As boas bandas no final das contas só fazem uma coisa: dão um show de Rock n Roll. Mas o que é isso afinal? Sem dúvida a música é o principal produto desta fábrica rebelde. Por trás de pessoas tatuadas, cheias de brincos e roupa rasgada, por vezes alcoólatras e drogadas, bem no fundo há músicos que juntos ( e aqui está o mais importante: JUNTOS) conseguem tocar almas sedentas de Rock puro e simples. Já ouviu um bom Lynyrd Skynyrd com suas 3 guitarras, piano, batera, etc? É brincadeira o que esses caras tinham de musicalidade. Juntos eles deixam os fãs de rock embasbacados até hoje em dia.


Depois desta introdução metafórica, vou iniciar hoje uma série de posts a respeito de GWT e Grails, duas tecnologias que juntas, para mim, estão despontando como a maior banda de Rock dos últimos tempos.

Sobre o Grails todos sabem que eu acho que é simplesmente o melhor framework para desenvolvimento web na plataforma java (pelo menos daqueles que eu conheço).

Sobre o GWT (Google Web Toolkit), eu sou um mero iniciante, ou melhor, curioso. Para ser sincero, tenho ficado um pouco cansado de lidar diretamente com HTML, CSS e Javascript, principalmente com a montanha de Javascript que se lida ao desenvolver aplicações AJAX. Mesmo usando bibliotecas como jQuery, ou Prototype, mesmo assim, é muito Javascript para se lidar.

Por conta disso (e outros motivos), acho que o GWT pode ser de grande ajuda, de grande ajuda MESMO. Um dos grandes motivos também é a crença que eu estou ficando de que o GWT pode ajudar muito a se ter uma arquitetura decente também na camada View, e não apenas no model, no controller, na DAO, etc. Se formos olhando uma arquitetura de uma aplicação Grails tradicional de baixo para cima, podemos ver que:
  • - a DAO está bem resolvida,
  • - os Serviços estão lá e cumprem seu papel (de controle transacional, por exemplo),
  • - os Controllers também tem seu papel de fronteira entre o mundo HTTP e nossas regras de negócio,
  • - mas aí chega na View e facilmente a gente começa a se perder e fazer uma bagunça com HTMLs, CSSs, Styles, Javascript em arquivos .js, Javascript inline, e por aí vai.
Andei estudando um pouco de GWT para entender mais a fundo e estou começando a acreditar que ele pode ser usado para, mais facilmente, arquitetar decentemente a camada View. Por exemplo, pode-se usar um MVP (Model View Presenter) com o GWT. Alguém aí pode dizer que pode-se fazer isso também com o Javascript diretamente. Sim, até pode, mas que o GWT facilita as coisas, ah facilita. Primeiro: É JAVA! Você ganha ferramentas, refactorings, debugging, e muito mais. Ganha também o fato de que o GWT abstrai você de preocupações mundanas, como por exemplo a ofuscação e minimização do Javascript. Ele faz isso pra gente.

Então é isso galera. Vamos começar.... Vou escrever os posts de acordo com a aventura que eu mesmo estou passando. Nunca desenvolvi uma aplicação real com GWT + Grails. Então vamos desenvolver uma juntos. Será pequena, mas vamos nessa!

Entendendo o GWT

Para começar eu instalei o plugin do GWT para Eclipse. Baixei também o SDK do GWT (neste momento estou usando a versão 2.0.3 do GWT). A página que uso para download de tudo é essa: http://code.google.com/intl/en/webtoolkit/download.html

Fiz uma pequena experiência com o GWT sozinho, sem o Grails ainda. Para isso, pelo Eclipse eu criei um projeto GWT novo, usando os wizards que o plugin me dá. Ele cria um projeto já sendo executado de dentro do eclipse, tudo bonito. E esse novo projeto já tem uma pequena página de exemplo, com um diálogo modal, uma requisição Ajax e tudo mais. Tudo para você começar a entender o tal do EntryPoint, entender os Modules, os Widgets e tudo mais.

Portanto, a primeira sugestão que eu dou é essa: brincar com a aplicação nova gerada pelo plugin do Eclipse.

A primeira coisa que percebi com aplicações GWT é que tudo é AJAX. Toda a comunicação com o servidor é assíncrona. Aí, vi que a aplicação gerada pelo plugin do Eclipse tem um "layout" diferente da aplicação Grails. Então surgiu o primeiro problema: como juntar os dois mundos?

Bom, em último caso, o GWT no fundo só serve para gerar os HTMLs e Javascript. Então você pode compilar seu projeto GWT, pegar o HTML e Javascript gerado, e copiar para seu projeto Grails para a parte de web-app. Simples assim! Mas isso não seria nada produtivo.

Aí me veio a dúvida: como que as pessoas por aí juntam o Grails com o GWT? Elas fazem um projeto GWT e outro Grails, e depois juntam de alguma forma (com maven por exemplo)? Ou vai tudo num projeto só?

E mais: se forem dois projetos distintos, como lidar com a Same Origin Policy (SOP)?

E vi que realmente tem gente que usa a primeira forma, e gente que usa a segunda. E tudo gente de respeito por aí. Por exemplo, eu gosto muito o Matt Raible. Desde meus tempos de AppFuse eu sou fã dele. Aprendi muito com a estrutura que ele montou para o AppFuse.

E não é que o Matt Raible usa a primeira forma? Ele tem dois projetos, um GWT e outro Grails. Aí, em desenvolvimento ele deixa assim mesmo, como duas aplicações web rodando simultaneamente. E simplesmente lida com a SOP através de um Proxy espertinho na aplicação GWT. Este proxy recebe as requisições no servidor do cliente GWT, repassa para a aplicação Grails, recebe de volta a resposta desta, e repassa a mesma para o browser que tem o cliente GWT. Muito doido, mas funciona.
E em produção ele na verdade junta tudo. Ele tem lá um Maven bem esperto que faz tudo isso pra ele automaticamente, gerando um único WAR que tem a aplicação Grails e o cliente GWT. Aí simplesmente o problema do SOP desaparece.

A outra alternativa é juntar tudo desde o início numa única aplicação. Para facilitar esta tarefa, um tal de Peter Ledbrook fez o GWT Plugin para Grails (não se deixe enganar por esta página. O plugin já está na versão 0.5 e suporta GWT 2.0).

Eu, por enquanto, vou seguir este caminho mais simples (sempre gosto da simplicidade): vou usar o GWT Plugin para Grails. Parece tão simples agora......mas eu fiquei umas duas semanas até chegar a esta conclusão. E até agora queria entender porque o Matt Raible não usa o plugin. Talvez ele seja ruim por algum motivo. Se for isso, eu ainda não descobri.

Então amigo, aí vão os passos iniciais:
  • - Instalar o SDK do GWT
  • - Criar a variável de ambiente GWT_HOME apontando para a raiz do SDK do GWT
  • - Instalar o Plugin de Eclipse do GWT
  • - Criar uma aplicação pura e simples GWT usando o plugin do eclipse.
  • - Abrir a aplicação no browser usando a URL apresentada pelo Eclipse (com o parâmetro gwt.codesrv na URL - este parâmetro é que permite você alterar o código Java e imediatamente dar um refresh no browser e ver sua mudança lá).
  • - Garantir que o browser instalou o plugin de execução do GWT.
  • - Executar esta aplicação e brincar um pouco com os diferentes Layouts de GWT.
Pronto. Agora que você brincou o GWT um pouco, vamos juntar os dois ( GWT + Grails ):
  • - Criar uma nova aplicação Grails com o comando grails create-app rockgwt
  • - Vai pra dentro dela ( cd rockgwt )
  • - Instalar o plugin GWT do Grails (usando o comando grails install-plugin gwt ). Eu estou usando o grails 1.2.x e o plugin 0.5
  • - Criar um GWT Module com o comando do plugin grails create-gwt-module com.rockgwt.RockNRoll
  • - Criar a página principal do GWT para o seu Module. Eu fiz isso criando um controller do grails e uma Page index.gsp para este controller. Esta page é que irá hospedar o GWT:
  • 1) grails create-controller com.rockgwt.controller.Principal
  • 2) grails create-gwt-page principal/index.gsp com.rockgwt.RockNRoll (quando este comando te perguntar se você quer criar o Controller, diga que não, pois você acabou de criá-lo no passo anterior --- acho que o plugin não reconhece o Controller criado com package, sei lá).
  • - Compilar o seu módulo com o comando grails compile-gwt-modules (demora um pouquinho mesmo)
  • - Executar o Development Mode com o comando grails run-gwt-client Perceba que vai se abrir a janela da aplicação Development Mode do GWT
  • - Abra outro Terminal , vá para o seu projeto rockgwt e execute a aplicação grails (é isso mesmo, você terá duas coisas rodando: o grails run-app da aplicação, e o grails run-gwt-client anterior, do GWT).
  • - Abra o browser e vá para a Home da sua aplicação GWT + Grails em: http://localhost:8080/rockgwt?gwt.codesvr=127.0.0.1:9997
  • - Na verdade, pode ser que na sua máquina a porta final seja outra, não sei. Para ganrantir sucesso, basta clicar no botão Launch Default Browser existente na janela do Development Mode.
  • - O endereço que você quer acessar no final de tudo será o seu controler Principal, ou seja:
    http://localhost:8080/rockgwt/principal/index?gwt.codesvr=127.0.0.1:9997
  • - Não deixe de colocar este parâmetro maluco. Ele é o responsável por permitir que você altere o código Java e dê um refresh no browser para ver as modificações imediatamente.
Agora, abra a sua classe RockNRoll e deixe ela assim:
(esta classe se encontra no seu projeto rockgwt em src/gwt/com/rockgwt/client)

package com.rockgwt.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.RootPanel;

/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class RockNRoll implements EntryPoint {
/**
* This is the entry point method.
*/
public void onModuleLoad() {

final Button sendButton = new Button("Rock n Roll");

RootPanel.get().add(sendButton);
}
}


Pronto. Dê um refresh no seu browser, e o botão "Rock n Roll" estará lá.

UPDATE (8/3/2010):
- Apenas para completar, para poder usra o Eclipse com tudo redondo, clique no botao direito do mouse em cima de src/gwt e selecione a opção Build Path > Use As Source Folder
- E por último clique com o direito do mouse em cima do projeto rockgwt e selecione a opção Google > Webtoolkit Settings, lá dentro do wizard que se abre, selecione o primeiro checkbox que aprece lá em cima "Use Google Web Toolkit". Assim você terá tudo que precisa no classpath da aplicação no Eclipse.

Até a Parte 2 desta série... Aguardo Comentários para saber se estou agradando com este tema. Abcs

Executando códigos diferentes em Desenvolvimento e Produção

Há vezes em que queremos executar códigos diferentes dependendo do ambiente que a aplicação está sendo executada. Por exemplo, integrações com sistemas externos algumas vezes são simuladas em Desenvolvimento, e são executadas pra valer em Produção.


Aí vai uma maneira simples de executar uma coisa em Desenvolvimento e outra em Produção (ou para quantos ambientes você tiver...).
import grails.util.Environment;

class MeuController{
Environment.executeForCurrentEnvironment {
production {
// AQUI vai o código que deve ser executado em produção
}
development {
// AQUI vai o código a ser executado em desenvolvimento.
}
}
}


Boas informações sobre grails em português

Pessoal


para quem ainda não conhece, foi lançado o Grailsbrasil Blogs que é um agregador de blogs em português sobre o Grails. Lá você poderá ver diversos posts de diversas pessoas que escrevem sobre Grails e afins. Vale conhecer.

Abcs
Felipe

Grails e datas: Bind automático de atributo do tipo Date com formato customizado

Segue uma pequena receita de bolo para quem não está usando o datePicker padrão do Grails.


O Grails vem com uma tag que é a g:datePicker.

Ela serve para gerar listboxes (comboboxes) de dia, mês, ano, hora, minuto e segundo. Você pode até escolher quais desses comboboxes você quer que apareçam.

Mas há vezes que não queremos usar estes combos, e simplesmente queremos um campo texto onde o usuário pode digitar a data num formato qualquer, como por exemplo, dd/MM/yyyy, ou dd/MM/yy, ou yyyyMMdd, ou...ou...ou...

E ainda, se você tiver uma aplicação com internacionalização, aí pode ser que para usuários com Locale em português, o formato de entrada deste texto de data é dd/MM/yyyy , porém, se for em inglês, aí é MM/dd/yyyy.

Bom, o objetivo aqui é mostrar como dizer para o Grails para usar este formato de entrada de datas para que ele faça o parse automaticamente toda vez que encontrar um atributo do tipo Date em um objeto de domínio (ou um objeto Command) que ele precisa fazer o bind dos parâmetros recebidos num POST (ou GET).

Então:
1) O usuário preenche um campo input type="text", com uma data num formato que você determina, ex: MM/dd/yyyy
2) Ele envia este POST, que chega no seu Controller disponível no atributo params
3) você quer fazer o bind automático usando (digamos que meu objeto de domínio seja Pessoa, e nele haja um atributo Date dtAniversario):
Pessoa tx = new Pessoa(params)

Para isso acontecer de forma correta, e o seu atributo dtAniversario estar preenchido corretamente com um valor do tipo Date, é preciso criar um PropertyEditorRegistrar customizado para você. Crie um pacote em src/groovy , digamos com.meusistema.editor , e crie lá o seu PropertyEditorRegistrar:

package com.meusistema.editor;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.context.i18n.LocaleContextHolder;

public class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {

def messageSource;

public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat(messageSource.getMessage("dateFormat4y",null,'dd/MM/yyyy',LocaleContextHolder.locale )),true));
}

}


Perceba que para funcionar corretamente, você precisa editar os seus grails-app/i18n/messages.properties (messages_en_US.properties, messages_pt_BR.properties) para que tenham cada uma a sua configuração correta. Ex para o pt_BR:
dateFormat4y=dd/MM/yyyy

O passo seguinte é registrar este PropertyEditorRegistrar no arquivo grails-app/conf/spring/resources.groovy:
beans = {

customPropertyEditorRegistrar(com.manubia.propertyeditor.CustomPropertyEditorRegistrar) {
messageSource = ref('messageSource')
}

}

Pronto. É isso!

Abcs a todos