Olá a todos,
Quem aqui já desenvolveu aplicações desktop em qualquer linguagem (Delphi, C++, VB, Java) sabe que existem duas partes que tendem a transformarem-se no famoso "código macarronico" se você não possuir um padrão de desenvolvimento ou uma boa capacidade de organização.
1. Ligação dos campos com as variáveis que os representam.
2. Controle de Habilitação e Desabilitação de campos baseados em regras de Negócio.
Para resolver esse tipo de problema diversos modelos foram criados, entre eles pode-se citar o MVC utilizado hoje em dia no Swing (É uma das mais conhecidas APIs para desenvolvimento Desktop em Java). Apesar do MVC do swing proporcionar uma organização no código o que acaba padronizando tudo, ele sempre foi criticado por ser muito complexo, assim, tornando o desenvolvimento caro pois você sempre precisa de desenvolvedores experientes.
Seguindo nesta mesma linha surgiu o Genesis que é uma ferramenta OpenSource (disponivel em sua totalidade e com manual em Português) desenvolvida pela Summa Technologies do Brasil sendo que os principais culpados pela criança são
Michael Nascimento e Allan Jones . A idéia básica do Genesis é permitir que programadores com pouca experiência conseguiam desenvolver aplicações Desktop com suporte a conexão a EJBs transparentemente. O Genesis pode ser divido em duas partes: client e shared.
O lado client é conhecido como binding, essa parte da API vincula todos os elementos de uma Interface (Construida em Swing, SWT ou Thinlet) a um Pojo (Plain Old Java Object). Imagine que você tenha uma interface como na figura.

O Genesis Client permite que você crie uma classe java simples sem herança nem dependencias de nenhum tipo contendo os campos relacionados a interface/métodos e vincule a interface com essa classe (Esta classe é chamada de Form). Além disso ainda possibilita constrolar a ativação e desativação dos botões, validação de campos etc.
Outro bônus é que como a interface é totalmente separada do "negócio" é possivel construir Unit Tests (outra hora faço um post sobre isso) o que permite testar a aplicação inteira sem interação humana.
O lado shared é assim chamado pois utiliza Aspectos (falo disso outra hora tb) para executar um conjunto de operações dentro de um EJB Container de maneira transparente, assim pode-se dizer que as classes estão entre (shared) a parte cliente e servidora, entretando neste post não vou entrar em detalhes.
Um bom começo seria assistir o
vídeo que mostra como fazer binding simples: dois campos texto e um botão. É importante salientar que como no exemplo foi utilizadas anotações, é necessária a utilização do jdk1.5, entretando, o genesis também pode ser utilizado com jdk1.4, maiores informações podem ser encontradas na
página da API.
Continuando o exemplo apresentado no vídeo, imagine que você deseja colocar um ComboBox na interface, basta para isso utilização a anotação @DataProvider, que pode ser utilizado para Combos, Listas e Tabelas. Para utilizar esta funcionalidade você deve criar um método qualquer que retorna uma lista de Objetos e informar qual a propriedade na classe que irá receber o objeto selecionando:
@DataProvider(objectField="sistema", widgetName="sistemas") public List populaSistema() { List sistemas = new ArrayList(); sistemas.add(new Sistema("JPA","JPA")); sistemas.add(new Sistema("EJB","EJB")); return sistemas; }
Neste exemplo, o campo ComboBox com o nome sistemas será populado com a lista retornada e quando um item do combo for selecionado ele estará disponível na propriedade sistema do form.
Outra configuração importante é informar ao Genesis qual propriedade (do objeto Sistema) será apresentadas na tela, para isso deve-se adicionar as seguintes linhas na inicialização da inteface:
sistemas.putClientProperty(SwingBinder.KEY_PROPERTY, "sigla");sistemas.putClientProperty(SwingBinder.VALUE_PROPERTY, "nome");sistemas.setRenderer(new KeyValueListCellRenderer(sistemas));
Neste caso, a propriedade que será mostrada na lista será NOME.
Outra funcionalidade interessante é a utilização de Formatadores. Imagine que você possui um campo de um tipo qualquer mas deseja que o texto para o usuário seja formatado de uma maneira especifica, por exemplo, você quer que o nome apresentado no combo acima seja iniciado com -- e finalizado com --, basta você adicionar o seguinte código na inicialização da interface:
Formatter f = new Formatter() { public String format(Object o) { return "--"+o+"--"; } };
e registrar o Formatador após fazer o Binder
binder.registerFormatter("sistema.nome", f);
Toda vez que a propriedade nome for inserida no list o Genesis irá chamar o formatador definido. Obviamente esse exemplo não tem muito sentido pratico, foi feito apenas para demostração. Um exemplo mais prático poderia envolver formatação de números, datas, códigos etc. Salienta-se que os formatadores podem ser utilizados com qualquer tipo de campo.
No exemplo passo a passo foi demostrado como vincular um botão a um método utilizando-se a anotação
@Action, agora imagine que você precisar ativar esse botão apenas em uma determinada condição. Em nosso exemplo poderiamos ativar o botão apenas se todos os campos estiverem selecionados, para isso deve-se utilizar a anotação
@Condition.
Primeiro você cria a condição (você pode utilizar diversas sintaxes para criá-la, vou utilizar aqui a que considero mais simples):
@Condition("loginSenhaOk=genesis.isNotEmpty('form:usuario') && genesis.isNotEmpty('form:senha') &&genesis.isNotEmpty('form:sistema')")
Criamos aqui uma condição denominada loginSenhaOk que será verdadeira quando todos os campos da inteface estiverem selecionados. Está anotação deverá ser feita no inicio do Pojo, e poderá ser utilizada em quaisquer campos ou ações utilizando-se as anotações
@VisibledWhen,
@EnabledWhen entre outras.
Como os próprios nomes dizem
@VisibledWhen fará com que o botão fique visivel quando a condição for verdadeira e o
@EnabledWhen deve ser utilizado para habilitar o botão. Estas anotações devem estar antes do método a ser controlado:
@Action@VisibledWhen("loginSenhaOk")public void limpar() { setUsuario(null); setSenha(null); setSistema(null);}Outras anotações de controle podem ser utilizadas, no
site do Genesis você pode encontrar uma lista completa.
Agora, imagine que você queira apresentar uma tela de confirmação antes de executar uma ação. Para isso você pode utilizar a anotação
@BeforAction, ela permite que um método seja executado antes de uma ação, este método pode retornar void ou boolean, caso retornar void a ação será sempre executada, caso retornar boolean a ação será executada se o retorno for true.
No nosso caso vamos criar um método que apresenta uma tela perguntando se o usuário deseja limpar realmente a tela e executar este método antes da ação limpar.
@BeforeActionpublic boolean limpar(){ if ( JOptionPane.showConfirmDialog(null,"Limpar?", "Limpar?" ,JOptionPane.YES_NO_OPTION) == 0 ) return true; return false;}
O método deverá possui o mesmo nome do método da ação, entretando deverá ser declado na interface e não no Pojo ou Form.
O exemplo completo pode ser baixado
aqui.
Aconselho a quem está iniciando um projeto com Swing, Thinlet ou SWT a fazer um exemplo de tela o mais complexa possível utilizando-se as APIs acima em sua maneira original e depois a mesma interface utilizando o Genesis, vocês perceberam que o código utilizando o genesis fica mais simples e organizado com pouco esforço.
[]s