quinta-feira, 20 de dezembro de 2007

As pequenas coisas

Validadores
Não sei porque, mas para mim (ou seria, para "eu") são as pequenas coisas que vão mudando o mundo (veja de registro no rodapé).

Assim, fiquei muito feliz em implementar a primeira versão (cachorra ainda, eu sei) dos validadores do Merlin.

A foto dá uma idéia do resultado:


Aqui, a área de mensagens (que é configurável, diga-se de passagem) exibe duas mensagens de validação, em conjunto com as bordas coloridas para os campos Nome e Email. O cômputo (eta, desenterrou essa palavra?!) dessas informações é automático, internacionalizável e baseado em templates do Velocity e FreeMaker (claro, nessa versão alpha isso é fake), sendo efetuado pelos algoritmos de renderização integrados.

A base para essa validação são as anotações do JPA, do Hibernate Validator, do Hibernate e, em breve, da sopa de letrinhas das JSR 227, 295 e 303.

Quanto à aparência, o padrão na implementação Swing deve seguir as bases do JGoodies (ainda em estudo) quanto ao esquema de cores, efeitos visuais, instantes de validação e exibição de mensagens. Quanto ao posicionamento de elementos, o "estilo Eclipse" é usado como base - isso se percebe pela ampla área branca acima.

Saliento, nesse ponto, que devo dar uma incrementada nesse renderizador padrão, permitindo a expansão e retração dessa área. Claro, tudo isso é o "padrão", e pode ser alterado ao gosto do desenvolvedor com seus padrões "de casa".

Sem mais.

_____
NOTA: Acho que estou com um distúrbio gramatical, que deve ter um nome qualquer. Notem que as duas últimas palavras da frase começam com a letra "M". Muito freqüentemente estou fazendo isso, e só percebdo depois do ocorrido. Essa semana ainda, escrevi uma frase com cino palavras seguidas que começavam com a letra "N"; uma coisa nada comum. Estou me balizando para evitar isso, mas tá brabo. Acho que vou ao médico :)

quarta-feira, 28 de novembro de 2007

Renderizadores e Binding

As JSRs 227, 273, 295 e 303 devem ser as linhas-mestre, mas, infelizmente, elas não estão prontas na totalidade e dificilmente terão um ponto comum. Assim, tenho que correr atrás de uma forma de fazer binding dos controles e dados no Merlin.

Ontem a noite, postei no grupo do merlin uma thread sobre renderizadores e binding customizados, com as idéias preliminares que eu tinha sobre isso. Porém, não sosseguei, e passei o dia hoje trabalhando no assunto. Fiz uma versão essencial, e o demo mostra o resultado.

As questões técnicas eu deixo em segundo plano, mas a essência é importante discutir.

Binding
Ao meu ver, o famoso binding pode ser interpretado como tarefa do controlador no modelo MVC, atuando entre a View e o Modelo (vejam como é difícil optar por uma língua única: português e ingles parecem viver juntos na Informática).

E ele pode ser ativado em momentos diferentes, várias vezes durante a interação do usuário. Essas várias vezes nada mais são que os eventos que a View (o controle da tela) dispara durante a interação com o usuário.

O binder (objeto que está fazendo o binding) pode ser ativado em um (ou vários) desses eventos, tanto para frente quanto para trás.

Para frente e para trás, podem ser interpretados como ações de "carregar o controle em função do valor do modelo" (load) e "atualizar o modelo em função do valor do controle" (update), respectivamente. Ou o contrário, é o freguês que manda :)

Pois bem, cada ação de load ou update, pode incorrer em sucesso ou fracasso. Geralmente, as ações de load (carregar o controle) não vão dar problemas no sistema, uma vez que é esperado que o modelo de dados esteja consistente. Porém, as ações de update podem, e geralmente vão, dar problemas. Isso porque é nesse momento que estamos capturando as CGDAS do usuário.

Quando uma CGDA dessas acontece, é função do binder avisar o sistema sobre o erro ocorrido. Assim, ele dispara uma mensagem com o que aconteceu. O controller captura essa mensagem e atualiza a view e o ciclo está finalizado.

Complexidades
Nota-se que tudo isso é um processo complexo, e que não pode ser fixo. Em outras palavras, por mais que tenhamos uma engenhosa miríade de código (tal como os validadores do Eclipse), precisamos ter uma porta de saída para o desenvolvedor. E essa porta de saída não pode ser a dos fundos.

A porta de saída precisa ser elegante, projetada e de fácil manuseio. É aí que entram as reais capacidades do framework e o porquê as JSRs acima.

A anotação RenderAs e o Binding
Como visto no post anterior, a anotação RenderAs serve para escolhermos um controle de tela diferente do padrão para um determinado campo de um objeto.

Quando ela é usada, é muito provável que estejamos saindo do contexto comum e caindo em casos onde precisamos, manualmente, dizer como o (mal)dito campo será mapeado para o controle da tela e vice-versa. É nesse momento que entra o binding.

Na implementação que fiz hoje (sofrendo com os genéricos do Java, diga-se de passagem), eu coloquei a feature do binding bem pertinho da anotação RenderAs. Tão pertinho, que ela está dentro, até. Vejamos o exemplo:

class UmCliente {

Strin
g nome;
@RenderAs(JTextField.class)
boolean vip = true;


}


Esse código produz algo como essa figura:


Notem que o campo vip parece ter sofrido um toString() para ser exibido no respectivo controle. E foi mais ou menos isso mesmo (pelo menos, nessa versão alpha do Merlin).

Para termos uma coisa mais elegante, podemos fazer algo como:

class UmCliente {

String nome;

@RenderAs(value=JTextField.class,binder=BooleanToTextComponent.class)
boolean vip = true;

}


Agora, além de especificar um controle de tela diferente, eu avisei o Merlin para colocar um binder específico. O resultado disso é algo como a figura:


Mas como esse binder é implementado? Vejam abaixo:

public class BooleanToTextComponentBinder implements IBinder[Boolean,JTextComponent] {

public boolean load(Boolean model, JTextComponent view) {


view.setText(model.booleanValue() == true ? "SIM" : "NÃO");
return true;


}

public boolean update(Boolean model, JTextComponent view) {


model = view.getText().equals("NÃO") ? Boolean.TRUE : Boolean.FALSE;
return true;


}

}

A interface genérica IBinder[M,V] (que o post mostra incorretamente, pois caracteres "maior que" e "menor que" não são suportados aqui) do Merlin, e especifica os métodos load e update, como discutido anteriormente. Graças aos tipos genéricos, não precisamos conversões para acessar tanto o modelo, quanto o controle de tela. E, no miolo dos métodos, código Java simples...

Conclusões
Não está tão simples quanto eu quero, mas para uma versão feita em três horas e meia está louco de bom (sim, o resto do dia foi perdido fazendo o vídeo-demo. Pode?)

Espero que das JSRs converjam (existe essa palavra?) logo, de forma que o primeiro release do Merlin esteja bem fundamentado nelas.

Por hora é isso.

terça-feira, 27 de novembro de 2007

@RenderAs

Hoje o trabalho estava fácil, e então decidi dar uma olhada na implementação do Merlin, para deixar redonda uma versão - básica, diga-se de passagem - para ser mostrada na banca do mestrado, lá por Março do ano que vem.

Pois bem, fiquei feliz, porque muitas coisas que eu estava imaginando, na verdade eu já tinha até implementado. Estou falando do RenderAs.

RenderAs
Essencialmente, como todo Gerador Baseado em Modelos, o Merlin utliza regras heurísticas para mapear um atributo de um objeto em um controle em um formulário, como um campo String mapeado para um TextBox. Muitas heurísticas existem, e é bem verdade que um grande escopo de coisas podem ser feitas automaticamente. Com mais algumas heurísticas (e essas sim, que somente o Merlin utiliza) coisas bem interessantes podem ser feitas (...)

Porém, nem sempre as heurísticas dão conta do recado. Nesses momentos, o programador precisa colocar a mão na massa e dizer, explicitamente, o que ele deseja que seja mostrado na tela. No Merlin, para fazer isso, lançamos mão da anotação @RenderAs, como no exemplo:

class Usuario {
String nome;
@RenderAs(JTextArea.class)
String descricao;
}

Ao ser renderizado um formulário para o objeto Usuario, este conterá um TextBox referente ao campo nome, e um TextArea referente ao campo descricao. Caso a anotação @RenderAs não tivesse sido utilizada, ambos campos seriam renderizados como caixas de texto simples (uma fixa, e outra variável - devido algumas heurísticas).

Neutralidade
O programador experiente logo perceberá que parece estarmos atrelando nosso objeto ao framework Swing, devido a classe JTextArea. Na verdade, isso não ocorre.

O Merlin trabalha tanto em nível físico, quanto em nível abstrato para seus mapeamentos. Em outras palavras, é possível utilizar algo como:

class Usuario {
String nome;
@RenderAs(TEXT_AREA)
String descricao;
}

Nesse exemplo, puxando mais letrinhas do mundo das ferramentas model-based, estamos trabalhando com Abstract Interface Objects (AIOs) ao invés de Concrete Interface Objects (CIOs). Hum, interessante...

Mas, novamente, um leitor atento perguntará? Bom, mas e se já tivermos uma aplicação construída para um framework como Swing ou SWT, e quisermos migrá-la para uma plataforma web, como o JSF, como faríamos ?

A resposta é: não é preciso fazer nada.

Diferente de outras ferramentas, o Merlin suporta o mapeamento bidirecional entre AIOs e CIOs, de forma que, mesmo um objeto anotado com um JTextArea poderá ser renderizado corretamente em uma aplicação para Internet.

Obviamente, essa abordagem tem seus custos. E quais são? Tão simplesmente a dependência de compilação das classes do pacote gráfico original (no caso, o Swing). Em outras palavras, um problema de projeto, e não do framework.

O futuro
Mais coisas incorrem dessas customizações, como binding e outras funcionalidades. Isso ainda não está implementado e também nem pensei no assunto, visto que, como disse no início do post, minha preocupação para o momento é deixar o que existe mais ou menos redondo, para não dar "tela azul" na frente dos homi.

Amanhã quero comentar o @Dependence.

quinta-feira, 8 de novembro de 2007

@Order

O Merlin é baseado em anotações. De fato, as anotações já existentes na própria linguagem Java e as definidas pelas especificações Java EE mais as do Hibernate também são reaproveitadas sempre que possível. Não obstante, as ainda no forno JSR 295 (Beans Binding) e a JSR 299 (Web Beans - aka Seam), também serão assim que a estabilidade as alcançe.

Entretanto, elas não são anotações para especificar interfaces de usuário (IU). Assim, torna-se necessário complementos. Nesse sentido, o Merlin define um conjunto de anotações (ainda em construção) para esse propósito.

As anotações do Merlin são, via regra, abstratas. Em outras palavras, elas não visam elementos dependentes de toolkits gráficos ou plataformas. Por exemplo, uma informação order:before("nome") sobre a propriedade observacoes não diz nada além do óbvio: que a propriedade observacoes deve ser posicionada antes da propriedade nome quando uma tela for gerada. Mas o que significa antes ?

Isso vai depender dos algoritmos de renderização atachados ao objeto. Se optarmos por algoritmos simples, como um FlowLayout() - semelhante ao FlowLayout do Swing, o TextArea com as observações (do Cliente, por exemplo) será mostrado à esquerda do seu nome. Se estivéssemos usando um GridLayout(), suas observações serão exibidas acima de seu nome, provavelmente.

Notem que tudo isso é bem subjetivo, tanto que termino a frase com um típico "ou não", como os mais chegados podem perceber. Mas isso está fora do escopo aqui, e vou explicar em momento oportuno.

A questão aqui é a seguinte: ao se definir as anotações necessárias, percebe-se que as variações existentes em uma IU são muitas. Enquanto que o mapeamento de herança para um modelo relacional pode ser feito de umas 5 formas diferentes, as possibilidades de mapear uma proprieade de um objeto para um controle de tela são, no mínimo, dezenas de vezes maiores. Se falarmos de posicionamento (layout), a coisa tende ao infinito. Tentar definir um denominador comum para as anotações para o Merlin pode ser muito dificil. Ou melhor dizendo, é inviável.

Então, o que fazer ? Ao invés de definirmos anotações específicas (como uma @Order, para o caso acima), podemos utilizar os seus próprios Agentes para isso. Vejamos um exemplo:

Hoje, o que existe é isso:

public class Cliente extends Pessoa implements PessoaFisica, PessoaJuridica {
String nome;
@Order(before="nome") String observacoes;
}

Já usando agentes:

public class Cliente extends Pessoa implements PessoaFisica, PessoaJuridica {
String nome;
@Agent({property="before=nome"}) String observacoes;
}

O que temos de diferente? No resultado final, nada. Mas como ganho em flexibilidade, tudo. Em outras palavras, a segunda alternativa reduz drasticamente o número de anotações necessárias para o Merlin, mantendo a mesma semântica de funcionamento. De quebra, também não perdemos em controle de sintaxe. Isso ocorre porque os parsers de código (futuros plugins para um Eclipse ou Netbeans da vida) vão pegar qualquer resbalada do programador.

Hoje, a versão alpha-1 do Merlin ainda é baseada na famigerada @Order. Mas depois de pensar bem no caso, e trocar uns contatos com alguns colegas (João, valeu; Mac, tu não conta!), a versão baseada em agentes será a opção do projeto.

sexta-feira, 12 de outubro de 2007

Hum, acho que isso vai ser legal

Pense...

this.class.methods.name.grep(~/get.*/).sort()

segunda-feira, 8 de outubro de 2007

Blog do projeto 3Layer Merlin é criado

Bem, e este é o primeiro post, ora bolas :)

Abaixo, os links importantes, os quais podem ser acessados também na barra lateral dos posts.

Site do projeto: http://merlin.dev.java.net

Empresa mantenedora: http://www.3layer.com.br

O autor (ou eu, :)), em : java.net