quarta-feira, 8 de janeiro de 2014

Data Binding

Olá, este post tem como função explicar o Data Binding, como usar e o por que. Então, lá vamos nós.

Data Binding é um processo que estabiliza uma conexão entre uma aplicação User Interface(JFrame) e a lógica do negócio. Se as configurações e notificações estiverem corretas, o Data Binding reflete as mudanças que elas fazem. Vamos supor que temos um AlunoFrame e nela um componente JTextField tNome, também temos a classe Aluno com o getNome e setNome. Se nós aplicarmos o Data Binding vamos fazer que quando seja digitado algo no TextField nome, automaticamente o setNome vai receber o que foi escrito, eles ficam sincronizados, as mudanças que ocorrem no nome ocorrem também no setNome e vice-versa. Mas então tu podes pensar, "por que não usar um setNome neste TextField?".

public class AlunoFrame extends javax.swing.JFrame{
     Aluno aluno = new Aluno();
     JTextField nome = new javax.swing.JTextField();
     /...

      private void tNomeActionPerformed(java.awt.event.ActionEvent evt){
         aluno.setNome(tNome.getText());         
     }

Podemos ver que fazendo assim não é nem um pouco elegante, deixamos o usuário com muita acessibilidade. Se por acaso ele quiser alterar para setMatricula ele pode, e não é isso que nós queremos. Nós temos que abstrair o usuário sobre o que está acontecendo. E também vale lembrar que para fazer espelhamento, deste modo fica muito "amador". Por isso vamos usar o Data Bindig, agora na prática vai ficar bem mais visível sua utilidade. Então vamos criar uma classe Bind que será a responsável por fazer a sincronização do JFrame com o negócio, so let's go.

public class Bind extends JTextField{    

    public Bind() {
        
    } 
    //criamos um método bind que vai receber os seguintes parametros
    //obj que será o objeto da classe que queremos alterar
    //atributo que será qual o atributo da classe que queremos mudar
    //campoFrame que é o que queremos onde a alteração seja feita
    //texto é a informação que vamos passar
    public void bind(Object obj, String atributo, Object campoFrame, String texto) throws NoSuchMethodException, IllegalAccessException...{

        //aqui nós vamos ver qual tipo é o campoFrame 
        //e depois repassamos para seu método correspondente
        if(campoFrame instanceof JTextField){
            JTextField tf = (JTextField) campoFrame;
            bindTextField(obj, atributo, tf, texto);
            return;
        }

        //exemplo com outros tipos de componentes
        if(campoFrame instanceof JComboBox){
            JComboBox cb = (JComboBox) campoFrame;
            bindComboBoxBinder(obj, atributo, cb, texto);            
            return;
        }
        if(campoFrame instanceof JRadioButton){
            JRadioButton rb = (JRadioButton) campoFrame;
            bindRadio(obj, atributo, rb, texto);
            return;
        }        
    }
Após implementar essa parte, nós precisamos fazer o bindTextField que terá como função ir lá no set da classe do objeto passado e alterar. Essa parte eu admito que é um pouco mais chatinha e complexa de entender pois vamos usar reflections e regex, então vou explicar por partes.

private void bindTextField(Object obj, String atributo, JTextField tf, String texto) throws NoSuchMethodException, IllegalAccessException... {
        tf.setText(texto);       
        
        //aqui nós vamos precisar usar reflections para saber os atributos
        //da classe do objeto que temos

        Field[] f = obj.getClass().getDeclaredFields(); //criamos um vetor de Field para pegar os atributos
        Field field = null; 
        
        //fazemos um for each para pesquisar dentro daquele nosso vetor 
        //para saber pegarmos o atributo que queremos alterar             
        for(Field campo : f){
            if(campo.getName().equals(atributo)){ //enquanto a variavel campo não for igual ao atributo continua o for
                field = campo; //a variavel field recebe o campo quando achado
                break;
            }
        }
        //agora que já achamos o atributo, nós precisamos encontrar o set dele
        //ATENÇÃO AGORA
        //Vamos criar uma String s que irá concatenar a palavra set com 
        //a primeira letra do atributo em maiuscula e o restante em minuscula
        String s = "set" + field.getName().toUpperCase().charAt(0)+ field.getName().substring(1);

        //no nosso exemplo fica s = "set"+N+ome
Depois que "formamos" o setNome, nós precisamos achar ele nos métodos da classe e fazer a alteração.
String tipo = field.getType().getSimpleName();//aqui criamos uma variavel tipo que irá
                                                      //pegar o nome do Tipo do campo field(que é nome)

        Method meth = null; //é criada uma variavel do tipo Method que será usada 
                            //para chegar ao método setNome
        
        //é feito um switch para ver qual é o Tipo do nosso atributo que será atualizado
        switch(tipo){
            case "String":
              //meth = aluno.getClass().getMethod(setNome, tipo String);
                meth = obj.getClass().getMethod(s, String.class);
                //usamos o metodo invoke para passar o objeto e a nova informação
                meth.invoke(obj, texto);
                break;
            case "int": case "Integer":
                meth = obj.getClass().getMethod(s,Integer.TYPE);
                meth.invoke(obj, Integer.parseInt(texto));
                break;
            case "float": case "Float": 
                meth = obj.getClass().getMethod(s,Float.TYPE);
                meth.invoke(obj, Float.parseFloat(texto));                
                break;
            case "double": case "Double":
                meth = obj.getClass().getMethod(s,Double.TYPE);
                meth.invoke(obj, Double.parseDouble(texto));  
                break;
            case "booelan": 
                Boolean.parseBoolean(texto);
                break;
            case "Date":
                 //OBSERVAÇÃO COM O DATE
                 //d{2}dias / d{2} mes / d{4} ano
                Pattern pattern = Pattern.compile("\\d{2}\\/\\d{2}\\/\\d{4}");
                        
                if(pattern.matcher(texto).find()){
                    SimpleDateFormat data = new SimpleDateFormat("dd/MM/yyyy");
                    meth = obj.getClass().getMethod(s, Date.class);
                    meth.invoke(obj, data.parse(texto));
                    
                }
                break;
        }       
    }
O case Date vou explicar por aqui pois é o mais complicado deles. Se por caso o nosso aluno tenha dataDeNascimento do tipo Date, vai ser necessário usar regex para formatar a data conforme for configurada pelo usuário, apartir do SimplesDateFormat(esqueçam todas gambiarras feitas até então). Criamos uma variável do tipo Pattern, quando colocamos o d{2} dizemos que aquela parte recebe até dois decimais. Mais a baixo temos um SimplesDateFormat que está separando por dia, mês e ano. Após isso, é igual aos outros.

Aqui terminamos nossa classe Bind, agora vamos ver como usar ela. No nosso formulário, no campo tNome nós precisamos usar o evento KeyReleased, fica da seguinte forma.

private void tNomeKeyReleased(java.awt.event.KeyEvent evt) {                                  
        Bind t = new Bind();
        t.bind(aluno2, "nome", tCampoParaMostrar, tNome.getText());
}

Admito que demorei para pegar a ideia do Data Binding, para entender como funciona essa sincronização via objeto, mas não é complicado de fazer, só é necessário tempo. Sobre reflections e regex, a ideia é bem fácil de entender.

terça-feira, 7 de janeiro de 2014

GenericTableModel com Reflection e Annotation


GenericTableModel com Reflection e Annotations

Vou falar um pouco sobre TableModel, Reflection e Annotation.

O que é o TableModel? 
A maioria dos componentes swing possuem uma arquitetura que separa model e view, de forma que é definida uma interface para cada model. Dentro deste contexto, TableModel é a interface que representa o model da JTable. Se não informarmos qual será o model, a JTable usará por padrão uma instância de DefaultTableModel.

Ai que muitas discussões ocorrem. A quem diga para nunca usar DefaultTableModel, alguns já garantiram a sua morte, mas como poucos tirariam tempo para desenvolver o seu TableModel muitos o utilizam e não veem problema nisso. Mas uma coisa é certa, a complexidade de manter um DefaultTableModel é grande. 

Segundo VinnyGodoy, moderador do maior forum java do Brasil(www.guj.com.br), esses seriam os argumentos para não usar esse modelo.

Não use DefaultTableModel!!!!
Motivos:
1. É mais difícil que escrever seu próprio TableModel;
2. É mais lento (usa classes sincronizadas);
3. Ocupa mais espaço em memória (duplica seus dados);
4. Deixa o código mais confuso e difícil de manter;
5. Usa casts inseguros;
6. Força que você tenha que exibir informações desnecessárias (como o ID) na tabela, ou controlar o ID numa lista separada;
7. Faz a sua mulher te deixar, o leite da sua geladeira azedar, e pessoas apontarem o dedo para você na rua;


Por que a JTable precisa de um TableModel?
A JTable chama os métodos do TableModel para obter informações sobre o conteúdo da tabela, como número de linhas e colunas, conteúdo de cada célula, etc.

Qual o papel da classe AbstractTableModel? 
AbstractTableModel é uma classe abstrata que oferece a implementação de alguns métodos da interface TableModel, além de um conjunto de métodos úteis. Portanto o usual é estender esta classe ao invés de implementar TableModel diretamente.

Ok, entendi. Tenho que Criar meu próprio TableModel extendendo a classe AbstractTableModel e cumprindo o contrato sobrescrevendo seus métodos. Mas a onde entra Reflection nisso?

Bom, se você assim como eu, também não tinha ideia de o que era Reflection e como ela funciona, posso garantir, e mais fácil do que parece.

Por que Reflection? 
Java permite que, enquanto escrevemos nosso código, tenhamos total controle sobre exatamente o que vai ser executado, o que faz parte do nosso sistema.
Em tempo de desenvolvimento, olhando nosso código, sabemos quantos atributos uma classe tem, quais métodos ela tem, qual chamada de método está sendo feita e assim por diante.
O que a reflection faz é isso. Olhar para dentro de nossa classe e descobrir seu conteúdo.

O ponto de partida de reflection é a classe "Class".
Através dela conseguimos obter informações como os atributos dela, os métodos, os construtores etc.

Reflection é um pacote do Java que permite chamadas dinâmicas em tempo de execução sem precisar conhecer as classes e objetos envolvidos quando escrevemos nosso código (tempo de compilação).

É ideal para resolvermos determinadas coisas que nosso programa só descobre quando realmente estiver o rodando.

Neste caso, ao criar uma GenericTableModel, ela deve estar pronta a receber qualquer list("Genérico, não?") como parâmetro e mostrar a partir de uma jTable seus dados contidos.
O TableModel não sabe que atributos tem esse list, mas através de reflection, ela consegue "descobrir" esses campos e gerar a jTable.

É possível fazer muitas coisas usando reflection. Apenas para citar algumas possibilidades:
* Listar todos os atributos de uma classe e pegar seus valores em um objeto específico;
* Instanciar classes cujo nome só vamos conhecer em tempo de execução;
* Invocar métodos dinamicamente baseado no nome do método como String;
* Descobrir se determinados pedaços do código foram anotados com as anotações do Java 5.

Ex:
public class Pessoa {
 private String nome;
 private String email;
 private int idade;
 // Getters, setters, métodos de pessoa...
}

Class classe = Pessoa.class;
for (Field field : classe.getDeclaredFields()) {
System.out.println(field.getName());
}

A saída Será:
nome
email
idade

Dessa maneira, posso deixar o TableModel Genérico.
A cada execução, a cada classe distinta, ele descobre seus atributos e age sobre eles da mesma forma. 

Ok. Funcional. Mas e se eu quiser que meu GenericTabelModel não atue sobre todos os atributos, como eu faço para "marcar" um atributo ignorado? Como eu Faço para marcar apenas o Atributo que quero que apareça na jTable?

Bom, e ai que entra as Annotations. 
Não vou explicar o funcionamento de annotation, ja que o colega Bruno Lima, fez um post sobre o seu funcionamento. (@Annotations "metadados" que não interferem diretamente no código anotado) 

Posso criar anotações e usar na minha classe, onde em tempo de execução e de acordo com a annotation criada o programa age da maneira que eu especificar. 

No casso do GenericTableModel trabalhei com as Seguintes Annotations: 
@TableModel - Anotação de classe, atua sobre todos os seus atributos, coloca todos na jTable.
@ColumnIgnore - Anotação de campo. o Atributo que possuir essa anotação, não irá aparecer na jTable.
@Column - Anotação de Campo e Metodos. O atributo que possuir essa anotação vai aparecer na jTable.     * colName() = Pode-se alterar o nome da coluna, 
    * colPosition() = Posição de coluna na jTable 
    * formatt() = formatar um campo, sendo sua saida uma String. 


Funcionamento:
         GenericTableModel tableModel = new GenericTableModel(getData(), 
            Pessoa.class);
 JTable table = new JTable(tableModel);
 JFrame frame = new JFrame("GenericTableModel");
 table.setModel(tableModel);



private List getData() {
List list = new ArrayList();
list.add(new Pessoa("Marcos", "viny_scholl@hotmail.com", 21, "xxxxx", 1000.5));
list.add(new Pessoa("Marco", "tony_scholl@hotmail.com", 21, "bbbbbb", 21.75 ));
list.add(new Pessoa("Felipe", "felipe_scholl@hotmail.com", 27, "qwert", 75.40));
return list;
}

Exemplos de Execução da GenericTableModel com diferentes Annotations.
Ex1:
  
@TableModel(includeAll=true)
public class CopyOfPessoa {
 private String nome;
 private String email;
 @ColumnIgnore
 private int idade;
 private String senha;
 private double saldo;
}
Saída: 

 ----------------------------------------
Ex2:
 
@TableModel(includeAll=true)
public class CopyOfPessoa {
 @ColumnIgnore
 private String nome;
 @ColumnIgnore
 private String email;
 @ColumnIgnore
 private int idade;
 @ColumnIgnore
 private String senha;
 private double saldo;
}
Saída: 

----------------------------------------
Ex3:
 
@TableModel(includeAll=false)
public class CopyOfPessoa {

 private String nome;
 @Column
 private String email;
 private int idade;
 @Column
 private String senha;
 @Column
 private double saldo;
}
Saída: 

---------------------------------------- 
Ex4:
Com a Formatação possivel Pelo @Column
 
@TableModel(includeAll=false)
public class CopyOfPessoa {

 @Column(colName = "Nome", colPosition = 0)
 private String nome;
 @Column(colName = "Email", colPosition = 1)
 private String email;
 @Column(colName = "Idade", colPosition = 4)
 private int idade;
 @Column(colName = "Pass", colPosition = 3)
 private String senha;
 @Column(colName = "Saldo", colPosition = 2, formatter="R$ %,#.2f")
 private double saldo;
}
Saída: 



Assim, posso trabalhar de diferentes formas e com diferentes resultados de saída, a partir de uma unica classe usando Reflection e Annotations. 

Temos uma tabela Dinâmica. Uma GenerictableModel.

Referencias:
http://www.guj.com.br/java/199067-redimensionar-jtable---pra-variar--resolvido-/2#1001295
http://www.guj.com.br/java/149861-recuperar-id-de-jtable/2#813171
http://devsv.wordpress.com/2012/07/08/como-implementar-um-tablemodel/
http://markytechs.wordpress.com/2009/05/29/objecttablemodel/
http://www.guj.com.br/java/231928-morte-definitiva-ao-default-table-model#1399642
Caelum FJ-16 -Laboratório Java com Testes, XML e Design Patterns


Marcos Vinicius Scholl:
Graduando em Tecnologia em Análise e Desenvolvimento de Sistemas - TADS 
Universidade Federal do Rio Grande - FURG 
Instituto Federal de Educação, Ciência e Tecnologia do Rio Grande do Sul IFRS - Campus Rio Grande 
Rua Eng. Alfredo Huch, 475 - Rio Grande, RS - Brasil - 96201-460 

Sobre o autor:
Marcos Vinicius Scholl estuda na área de Tecnologia de Informação. É entusiasta na área de tecnologia. Gremista de paixão e anticolorado por prazer!

Post Sobre armazenamento de objetos em um Cache

o que é um cache?

Nos dias atuais cada vez mais acessamos sites, usamos banco de dados, e nossos proprios

computadores tem grande capacidade de armazenamento de processamento.Com a finalidade

de agilizar essas consultas e processamentos que existe a memoria cache, sendo uma

memoria de acesso muito rapido, que guarda pequenas quantidades de informações, as mais

acessadas por nós, seja em sites, no nosso HD ou ate mesmo um banco de dados.


Tipos mais típicos de cache

Como falado anteriormente, alguns tipos mais tipicos de caches sao:

1-Cache de sites: são caches guardados pelo navegador que usamos, guardam informaçoes

de uma pagina que visitamos na web, para que ao acessa-las novamente nao precisamos

carregar a pagina completamente, e sim informaçoes que foram atualizadas nela, assim

agilzando o processo de carregamento.

2-Cache no processador: uma memoria de alto desenpenho que fica embutida dentro do

processador, é utilizada para que o processador acesse dados mais rapidos, evitando a

busca na memoria ram que é mais lenta.Normalmente utilizada em 3 niveis no processador.
Nivel L1, L2 e alguns processadores chegam a ter o nivel L3.

3- Cache do disco : fica localizada junto ao disco rigido do nosso computador, ela

armazena as ultimas trilhas feita pelo HD assim evitando que a cabeça de leitura e

gravação passe varias vezes pelo mesmo lugar.


Características de um cache:
E uma memoria de velocidade de leitura e escrita muito mais rapido, por isso é

utilizado para armazenar dados que são lidos ou gravados varias vezes.
Possui um tempo de vida, assim nada fica sempre armazenado no cache para sempre.

Sobre meu projeto:

Bom, tendo explicado um pouco sobre memoria cache, vou mostrar um pouco do meu projeto

de cache, mostrando os codigos em java, o projeto tem como finalidade criar um toolkit

que atraves de anotaçoes feitas por quem desenvolve uma classe seja colocado na memoria

ram utilizada pela maquina virtual do java, assim evitando por exemplo o acesso a um

banco de dados utilizado por um sistema.



Alguns Métodos da minha classe cache :

Essa classe manipula o cache, ela possui um objeto cache estatico que só pode ser

instancia dentro dela mesmo, e todos os metodos necessario para adicionar, remover,ou

até mesmo limpar todo o cache.

verifica se uma chave existe :
   
      public  boolean hasKey(String chave){
 boolean chaveExisteNoCache = true;
 if(chaveEhValida(chave)&&temEssaChaveNaListaDeObjetos(chave)) return chaveExisteNoCache;
 return  chaveExisteNoCache=false;
      }


retorna um objeto do cache :
     
 public Object get(String chave){
  
  if(chaveEhValida(chave)==false){
   System.out.println("chave invalida");
   return chave;
  }
  if(temEssaChaveNaListaDeObjetos(chave)==false){
   System.out.println("objeto inexistente na lista");
   return chave;
  }
  
  
  Object objeto = listaObjetosNoCache.get(chave);
  return objeto;
 }

metodo que adiciona um objeto no cache :
/**
    
 public  void add(String chave,Object objeto,int tempo){
  
  if(chaveEhValida(chave) && validaObjeto(objeto)){
   addChaveObjetoNoCache(chave,objeto);
   addChaveParaMonitorar(chave,tempo);
  }
  
  
 }


metodo altera o tempo de um objeto no cache :
public void alteraTempoDoObjeto(String chave,int tempoEmMinutos){
    if(chaveEhValida(chave)&&(temEssaChaveNaListaDeObjetos(chave))){
       long novoTempo = calculaTempoDeDuracaoNoCache(tempoEmMinutos);
       atualizaTempoDaChave(chave, novoTempo);
       System.out.println("tempo alterado da chave para : "+tempoEmMinutos +" minutos");
    }
    else System.out.println("chave invalida ou objeto inexistente no cache ");
}



Devido ao tamanho da classe deixo os outros métodos para outra hora : )

Abaixo sobre a classe da anotação:

Anotação que inclui um objeto no cache feita em cima de um metodo, por meio de uma

interface, é uma anotaçao que deve ser inserida em um metodo de uma interface, que sera

reconhecida pelo metodo proxy utilizado na classe cache.

package cache;

/**
 *Classe utilitaria para anotar metodos que serao inseridos no cache da JVM
 *@author Andrei Garcia (andrei_garcia2@hotmail.com)
 *@since JDK.7
*/


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 *Anotação para ser utilizada sobre uma interface ,sendo anotada
 * em cima de um método,metodo o qual sera inserido no cache da JVM seu objeto de 

retorno
 *
 *@author Andrei Garcia
 *@category anotação
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ColocarNoCache {

 int tempo() default 60;


}




Bom era isso, espero que tenham curtido o posto : )





Referencias

http://www.tecmundo.com.br/tira-duvidas/21555
http://pt.wikipedia.org/wiki/Cache