segunda-feira, 15 de julho de 2013

Todos podem aprender brincando

Boa noite!
Estive revirando alguns materiais da faculdade/pós graduação neste fim de semana e acabei achando um projeto muito bacana, na época em que o professor tentava de uma maneira divertida nos ensinar a programação orientada a objetos. Este projeto consistia em fazermos um jogo de Xadrez, onde precisaríamos basicamente montar a lógica do movimento das peças, como em um jogo real mesmo. E como na época eu não havia terminado todo ele, resolvi ressuscitá-lo e compartilhar com vocês, para que possamos aprender juntos! E melhor, começando do ZERO! Ou seja, vamos aprender desde a criação do tabuleiro até as peças do jogo, então pegue sua cadeira e vamos em frente!

1) Início
Para darmos início ao nosso jogo de Xadrez, precisamos saber os componentes que precisamos para montá-lo:
a) Um tabuleiro com 64 posições, sendo intercaladas em cores de preto/branco, ou seja, uma matriz de 8,8, onde teremos os eixos X e Y, começando na posição 0 e terminando na posição 7.
b) Peças do Xadrez: precisamos de todas as peças do nosso jogo (peões, reis, rainhas, etc) e que possam ser peças pretas ou brancas, pois no mínimo são dois jogadores.
c) Figuras: precisamos de figuras para representar as peças no tabuleiro

2) Implementação - Tabuleiro
Tendo em mente o que precisamos, é hora de partir para o trabalho duro. Vamos começar com o tabuleiro e depois, gradativamente, iremos programando os demais componentes. Bom, como dito anteriormente, um tabuleiro é composto por uma matriz de 64 posições (8 x 8), em que cada posição do tabuleiro corresponde a uma posição na matriz. Por exemplo, a primeira "casa" do tabuleiro corresponde a posição 0,0 da matriz, bem como a segunda casa (na primeira linha) representa a posição 0,1 da matriz. A imagem a seguir ajuda a interpretar isso:
Imagem 01: Parte de um tabuleiro de Xadrez

Ou seja, o eixo Y é representado pelo primeiro número e o eixo X pelo segundo. 

Mas, não basta termos vários quadrados pintados de preto ou branco se eles não tiverem nenhuma ação, certo? As células precisam ser representadas por algo... algo que tenha as coordenadas X e Y e ao mesmo tempo possam ser configuradas com cor. Bom, isso pode ser um botão, um Panel... optaremos aqui pelo Panel (JPanel). Não há nenhum motivo particular nisso, apenas escolhemos JPanel para representar as células. 

Vamos então implementar a dificílima classe que representará isso?

public class Celula extends JPanel {
    private int linha;
    private int coluna;
}

Só isso? Sim, por enquanto sim.  Nossa classe Celula ainda não faz nada de útil. O que ela sabe atualmente é em que posição do tabuleiro ela se encontra - e só.

O tabuleiro
Bom, sabemos que um tabuleiro possui VÁRIAS células, e elas precisam ser representadas por uma matriz. 
Já que temos a classe Celula, precisamos dizer ao tabuleiro que ele terá várias instâncias dela. O tabuleiro também é um componente gráfico, então mais uma vez escolheremos um JPanel para representá-lo.
Vamos ao código:

public class Tabuleiro extends JPanel {
    private Celula[][] celulas = new Celula[8][8];
}

Veja o que fizemos, declaramos que um tabuleiro conterá uma matriz de células (em Java isso se chama array multidimensional, mas não entraremos em detalhes muito técnicos aqui). Este código está dizendo o seguinte, "declare em meu tabuleiro uma matriz de 8,8 que totalizará 64 posições". 

E então você quer dizer que rodando tudo isso já vai funcionar? De maneira nenhuma. Isso é apenas o COMEÇO. Precisamos ir com calma para que a gente não se perca :)

No próximo POST faremos a construção dinâmica do tabuleiro. Ele se parecerá com o seguinte:

Imagem 02: Tabuleiro de Xadrez completo

Então não percam o próximo POST! Até breve!

domingo, 7 de julho de 2013

Não reinvente a roda - alguém já fez isso por você!

Boa noite!
O assunto de hoje é algo muito interessante e que eu descobri há pouco tempo, e que se eu tivesse descoberto antes, teria poupado muitas e muitas noites de sono.
Mas que solução mágica é essa?
Bom, quem nunca pensou em como seria bom se os criadores da linguagem Java tivessem pensado em TUDO, como por exemplo, criar um método na classe String que fosse segura com relação a irritante exceção NullPointerException. Bem, nós sabemos que não dá para se pensar em tudo - nós é que precisamos cuidar do que estamos fazendo. Mas eu sempre fiquei com uma pulga atrás da orelha e me perguntava porque ninguém havia feito métodos para evitar esse tipo de coisa, afinal é relativamente simples, não é mesmo?
Até que um dia, olhando um extenso código de outra pessoa eu vi um tal de StringUtils.isEmpty. WTF? Pensei comigo, "bom, a pessoa deve ter feito essa classe pois com certeza sempre teve a mesma preocupação que eu, fazer as coisas de forma mais elegante e segura" (sim, o elegante está destacado aqui pois programar em Java qualquer um programa, mas programar com elegância são poucos). Ao abrir a classe, vi um import bem peculiar: org.apache.commons.lang3.StringUtils. Fiz uma pesquisa básica no Google e... voilá! Descobri que a Apache tem um excelente projeto com várias coisas úteis desse tipo! E o nome não poderia ser mais claro - Apache Commons. E fica ainda melhor: lá você poderá encontrar não só classes utilitárias do pacote java.lang, mas de várias outras, como Collections, e-mail, EL... 
As duas que mais me chamaram a atenção, até o momento, foram as classes StringUtils e ObjectUtils. Vamos ver alguns métodos?

StringUtils:

  • isEmpty(CharSequence cs) - Verifica se o CharSequence é nulo OU vazio. Exemplo:

 StringUtils.isEmpty(null)      = true
 StringUtils.isEmpty("")        = true
 StringUtils.isEmpty(" ")       = false
 StringUtils.isEmpty("bob")     = false
 StringUtils.isEmpty("  bob  ") = false
  • difference(String str1, String str2) - Retorna a diferença das duas Strings. Exemplo:
StringUtils.difference(null, null) = null StringUtils.difference("", "") = "" StringUtils.difference("", "abc") = "abc" StringUtils.difference("abc", "") = "" StringUtils.difference("abc", "abc") = "" StringUtils.difference("ab", "abxyz") = "xyz" StringUtils.difference("abcde", "abxyz") = "xyz" StringUtils.difference("abcde", "xyz") = "xyz"

ObjectUtils:

  • defaultIfNull(T object, T defaultValue) - Atribui o valor default caso o objeto passado seja nulo. Exemplo:
 ObjectUtils.defaultIfNull(null, null)      = null
 ObjectUtils.defaultIfNull(null, "")        = ""
 ObjectUtils.defaultIfNull(null, "zz")      = "zz"
 ObjectUtils.defaultIfNull("abc", *)        = "abc"
 ObjectUtils.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE

OBS: Exemplos tirados da própria documentação!

Isso não é mágico? Eu pelo menos achei sensacional, e com certeza usarei emmeus projetos. Além de serem métodos muito eficientes, deixam o seu códigoextremamente limpo e elegante.
Para mais informações, visite o site da Apache Commons! Os exemplos acima estão no componente Lang, e você pode ir direto no link clicando aqui.

Por hoje é só minha gente, um abraço e até a próxima!


terça-feira, 25 de junho de 2013

Descobrindo a poderosa engenharia de aplicações Java Web - Parte 3

Dando continuidade aos nossos estudos, hoje falo um pouco sobre os Servlets. Os Servlets são classes Java que nos auxiliam no tratamento das solicitações HTTP antes de enviarmos a resposta para o servidor. Primeiramente, uma rápida olhada na hierarquia de classes e interfaces:

O que vem abaixo de HttpServlet são os nossos próprios Servlets. Eles DEVEM estender HttpServlet. Por que? Se olharmos na documentação, veremos que a classe HttpServlet possui um método chamado service que conta com dois parâmetros: HttpServletRequest e HttpServletResponse. O objeto HttpServletRequest cuida da solicitação (requisição), já o HttpServletResponse cuida da resposta. Precisamos desses dois objetos para podermos, por exemplo, pegar os parâmetros de entrada da requisição, pegar parâmetros iniciais do Servlet, setar atributos (de requisição ou de sessão, por exemplo). O método service é chamado quando o container recebe a primeira solicitação do cliente. Ele aloca uma Thread específica para este Servlet e processa a requisição.Além do método service, dois métodos importantíssimos a classe HttpServlet possui:
  • doPost(HttpServletRequest, HttpServletResponse)
  • doGet(HttpServletRequest, HttpServletResponse)
Vamos voltar um pouco a fita, lá para os nossos formulários HTML. Quando criamos uma página, geralmente há um FORM onde o usuário preencherá algumas informações, e na sequência apertará um botão como "enviar dados" para obter algum tipo de resposta. Pois bem, quando estamos criando nossos formulários, precisamos dizer qual é o método que será executado no servidor, se é POST ou GET. Bem, qual a diferença dos dois? O método GET envia todos os parâmetros informados no preenchimento do formulário, os anexa na URL e envia a requisição para o servidor. O que isso significa? Significa que você terá uma URL gigante com cada um dos parâmetros separados pelo caractere "&". Exemplo: http://www.minhapagina.com.br?usuario=Eduardo&senha=123 Consegue enxergar o potencial problema nisso? Os dados são expostos na URL, como senhas e outras coisas importantes. Além disso, o método GET tem uma limitação de caracteres. Isso quer dizer que em um dado momento, alguma informação pode ser enviada incompleta pois ultrapassou o limite de caracteres. 
O método POST trabalha um pouco diferente. Os dados não são enviados na URL da página, e sim no corpo da solicitação (alguns chamam isso de payload). Além do mais, o POST não tem limite. 
Quando usar o método GET?
Use-o quando quer somente OBTER coisas, como uma foto ou uma música no servidor, ou uma página específica. Nunca use o GET que cause algum efeito colateral. No exemplo da autenticação, o uso do GET não é apropriado pois os dados ficariam visíveis na URL enviada. Ele não deve ser usado, por exemplo, para inserir novos valores no banco de dados.
Quando usar o método POST?
Quando você for fazer alguma operação mais criteriosa, como por exemplo, diminuir o saldo de uma conta, ou fazer uma autenticação de usuário. 

E você não vai falar dos métodos doPost() e doGet()?
Não há como não falar, visto que eles são essenciais. O doGet() é chamado quando, adivinha? O método do seu formulário é GET! E o doPost()... bom, vou deixar que você complete. Você nunca pode ter os dois métodos! Na prática isso quer dizer o seguinte, você nunca pode ter metade de uma lógica implementada no doGet() e a outra metade no doPost(). Caso seu formulário seja GET mas você queira chamar o doPost(), sem problemas, apenas delegue para que o doGet() chame o doPost(), como no exemplo abaixo:

public void doGet(HttpServletRequest request, HttpServletResponse response) {
    doPost(request,response);
} 


E o que eu vou colocar no doPost() ou no doGet()?
É aqui que a brincadeira começa. Sua lógica será processada aqui. Você pode chamar outros métodos de outras classes normalmente, trabalhar os seus dados e devolver a resposta. É tão simples quanto descrevi. Mas e a resposta... como eu devo enviá-la? 
Bom, esse é um assunto que vai ter que ficar para a próxima postagem, pois entraremos no mundo dos JSP's!

Por hoje é só, até a próxima!

segunda-feira, 17 de junho de 2013

Descobrindo a poderosa engenharia de aplicações Java Web - Parte 2

Boa noite!
No POST anterior, dei uma pincelada bem por cima sobre a estrutura básica de uma aplicação WEB.
É hora de mais detalhes.

O servidor WEB
Quando vemos a palavra "servidor", estamos nos referindo tanto ao hardware como ao software. Um servidor WEB é capaz de processar requisições HTTP enviadas através de browsers (clientes). Isso significa que quando estamos em um site e preenchemos um formulário ou clicamos em um botão, o browser (navegador) irá enviar uma solicitação HTTP para o servidor web. Um dos servidores WEB mais conhecidos e utilizados até o momento é o Apache.

Mas por que eu preciso de um servidor WEB? 
Justamente para processar as requisições HTTP oriundas dos clientes. Mas não só por isso. Um servidor WEB é capaz de armazenar outras páginas que serão acessadas pelos usuários, armazenar sons, imagens, scripts auxiliares (PHP, Perl, etc). Ele é capaz de lidar com muitos acessos simultâneos, utilizando o mecanismo de threads. Ele é capaz de processar e criar páginas dinamicamente e devolver uma página diferente ao usuário, como por exemplo retornar uma página de erro ou de sucesso, se a determinada ação foi ou não bem sucedida.

O container
O container é um software que gerencia uma porção de coisas que são essenciais para sua aplicação. É ele que cuida do gerenciamento de segurança, do suporte a threads, gerenciamento do ciclo de vida das sessões, e muito mais! Um Web Container é um poderoso amigo que ajuda o servidor WEB a tratar solicitações em que o mesmo não é capaz de tratar, como solicitações dinâmicas. Exemplo? O usuário está em um site de compras e decide verificar se aquele CD que ele tanto quer está disponível em estoque. Então ele escolhe o CD e clica em "Pesquisar estoque". Bom, essa solicitação vai chegar no servidor WEB e ele dirá "opa, preciso de ajuda! Eu realmente não sei como verificar isso, vou chamar o meu amigo Container". Então o servidor WEB encaminha a solicitação ao Container. E é o container que vai direcionar essa solicitação para um de seus vários programas auxiliares que sabem como verificar o estoque para aquele CD. Depois que é feita essa verificação, o container responde ao servidor WEB que o CD está sim disponível no estoque, e o servidor web por sua vez "monta" uma resposta e a envia para o cliente. Simples, não?
Existem vários Web Containers disponíveis no mercado. Um deles é o Tomcat (desenvolvido inclusive pelo pessoal da Apache). O Tomcat acaba atuando como servidor web e container web, quando não se tem um servidor web instalado, mas nada comparado a robustez do Apache. Porém, o Tomcat não é um servidor JEE completo (ele consegue apenas entender Servlets e JSP). Um servidor JEE completo, contempla um servidor EJB + container web. Ainda não chegamos lá, mas um servidor JEE completo, por exemplo, é o JBoss, mas vamos com calma :)

A seguir, uma figura que exemplifica isso que expliquei acima, mostrando os dois tipos - Um servidor JEE completo e apenas um WEB Container:

Figura 1: Estrutura (adaptado de Head First - Servlets e JSP (pág. 65))

Por hoje é só pessoal!
No próximo POST é hora de começar a ver sobre Servlets!

Um abraço e até a próxima.



sábado, 15 de junho de 2013

Descobrindo a poderosa engenharia de aplicações Java Web - Parte 1

Boa noite.
Hoje começo uma série onde o objetivo é destrinchar a arquitetura de aplicações Java Web, incluindo aplicações JEE completas (utilizando EJB por exemplo).
Eu sempre foquei bastante na arquitetura JSE (antigamente chamada de J2SE), em questões de detalhes minuciosos desta arquitetura. Ainda tenho bastante a aprender, porém é hora de aprender a fundo os detalhes do JEE.
Uma coisa que sempre achei importante quando você está trabalhando com uma determinada tecnologia é conhecê-la profundamente. Pra mim, conhecer superficialmente uma coisa o faz ser um programador comum e menos cuidadoso. Sim, porque quando você tem um conhecimento mais aprofundado da tecnologia em si, sabe usar melhor os recursos, sabe projetar uma estrutura segura e resistente, além é claro de utilizar todo o poder que a tecnologia oferece. Então vamos juntos descobrir passo a passo como é que funciona essa coisa?

Deixando de ser "O site" para ser "A aplicação".
Antigamente, fazíamos "sites" na Internet onde apresentávamos conteúdo estático, como uma série de textos e imagens que eram somente aquilo e pronto. Não haviam interações com o usuário, geralmente haviam muitos GIF's pulando na tela e letras coloridas anunciando alguma coisa. Após isso começou a surgir os sites mais "inteligentes", onde você colocava um valor em um campo de texto, esse valor era processado e o site te retornava alguma coisa. E daí foram surgindo as aplicações Web, como e-commerces, sites de relacionamentos e diversos tipos.
E onde é que o Java entra nessa história toda? É aqui que tudo começa.

Criando corpo
Bom, quando você precisa de algo mais além de exibir páginas WEB estáticas, como por exemplo, acessar um banco de dados e retornar uma listagem de clientes cadastrados no sistema, você precisa escrever um "programa" que converse com o servidor WEB para que os dois trabalhem em conjunto. Ou seja, quando você clica em um botão "enviar dados", o servidor WEB precisa dizer "Ok, eu sei que eu não consigo tratar disso sozinho, então vou pedir ajuda a um amigo meu que pode fazer isso que ele quer". Esse "amigo" é uma aplicação que pode realizar tarefas mais complexas. Então o usuário acessa uma página da WEB, preenche uma série de campos em um formulário e clica em "OK". Esses dados precisam ser processados em algum lugar, onde serão feitas validações e outros procedimentos, e então o usuário verá outra página dizendo que tudo deu certo ou que houve algum tipo de erro. A imagem a seguir explica como esse processo funciona:
Figura 1: Estrutura básica

Bom, não tenho dons artísticos, mas é mais ou menos assim que a coisa funciona.

E como essas estruturas se conversam?
Essa é uma pergunta muito interessante, e poderíamos escrever um livro inteiro só disso (a propósito, tudo está BEM resumido aqui, é só a primeira parte). Bom, o servidor WEB Apache utiliza o protocolo HTTP para interpretar as requisições feitas pelo usuário, através de um browser. Seu papel então é receber as solicitações dos clientes (através de métodos GET ou POST). Como o Browser também fala a mesma língua que o servidor, então quando o servidor envia uma resposta no formato HTML, o browser pega essa resposta e formata para exibir num formato amigável para o usuário. Ou seja, o servidor recebe uma requisição HTTP e responde em formato HTML (apesar de que o servidor pode enviar vários tipos de resposta, como um áudio, vídeo, um PDF, etc.). E qual é o papel do Servlet? É exatamente executar tarefas mais complexas, como validação de dados, acesso ao Banco de Dados, etc., e o Servlet é chamado pelo Container WEB. 

Mas era só isso?
Infelizmente (ou felizmente, dependendo do ponto de vista) não. Há MUITOS detalhes que precisamos descobrir ainda. Esse foi apenas um resumão do que vem pela frente. Nos próximos POSTS pretendo detalhar o que é exatamente esse tal de Servlet, por quem ele é gerenciado, o que é o Tomcat, enfim, destrinchar mesmo. Afinal, você não quer passar vergonha com seu amigo quando não souber explicar como funciona aquele maravilhoso site de compras on-line! 

Por hoje é só, um abraço e até a próxima!

quarta-feira, 12 de junho de 2013

Mas o que diabos essa interrogação está fazendo em meu SQL?

Boa noite galera.
Primeiramente, quero parabenizar a todos os casais de namorados nesse dia 12/06/2013! Aproveitem seu dia! :)
Se você, assim como eu, não tirou a noite para namorar, e ainda por cima quer aprender algo novo, então está no lugar certo.
O "mão na massa" de hoje trata-se de como tornar seus SQL's mais legíveis em sua aplicação, torná-los mais inteligentes e menos suscetível a falhas. Bom, para início de conversa, escrever SQL's no meio do código é algo muito deselegante, mas quando você não usa um Framework para auxiliá-lo, infelizmente não há muito o que se fazer. Mesmo que você separe as suas SQL's em um arquivo de propriedades, por exemplo (.properties), em algum lugar você estará escrevendo querys complexas, longas e feias. Como por enquanto é o nosso caso, vou partir do princípio que suas querys estão devidamente alojadas em algum DAO da vida e que não estejam misturadas com sua regra de negócio.
O problema que venho tentar resolver é muito simples: como tornar minha SQL legível e inteligente? Bom, o que vínhamos fazendo até hoje em nossos códigos, é algo muito parecido com isso:
PreparedStatement stmt = Conexao.prepareStatement("select * from table where field1 = ? 
and field2 = ?");

stmt.setString(1,"name");
stmt.setString(2,"address");
Aí você me diz: "Certo, mas está muito claro que o parâmetro 1 (a primeira interrogação) refere-se ao campo 1 e a segunda ao campo 2". Muito bem, você está certo. Mas agora me diga, o que acontece se eu fizer o seguinte:
PreparedStatement stmt = Conexao.prepareStatement("select * from table where field2 = ? and field1 = ?");
stmt.setString(1,"name");
stmt.setString(2,"address");
Já até sei o que você vai dizer: "Mas é óbvio que daí teremos que trocar a configuração dos parâmetros, o que era 1 vira 2 e o que era 2 vira 1. Essa é obrigação do programador!". Muito bem outra vez, só que essa query tem apenas dois parâmetros. E uma query com dez, vinte parâmetros? Onde está seu Deus agora? Brincadeiras a parte, mas você quer realmente ficar com cabelos brancos todas as vezes que precisar mexer em uma listagem de parâmetros de uma SQL? Ou pior, você quer realmente ficar conferindo o que cada "?" dessas quer dizer? 
Eu não. E aposto que muita gente também não. E uma dessas mentes incomodadas, assim como eu, resolveu fazer um trabalho magnífico, que é de fazer um objeto que entende NamedParameters! E o que seria?
Imagine algo como isso, considerando o mesmo exemplo anterior:
PreparedStatement stmt = Conexao.prepareStatement("select * from table where field1 = :name
and field2 = :address");
stmt.setString("name","Eduardo");
stmt.setString("address","Rua sem fim");
Parece que aqui as coisas estão ficando um pouco melhores, não?
Veja que interessante, agora mesmo que mudemos a ordem dos parâmetros na nossa query, nunca mais precisaremos dar manutenção na configuração dos parâmetros! Veja, se o "field2" viesse antes do "field1", não precisaríamos mexer em nada, pois sabemos que o "field2" é o endereço, independentemente da posição em que o mesmo se encontra. Não é genial? 
Bom, mas para isso ser possível, alguém teve que escrever uma classe com esse comportamento. O nome do (in)feliz é Adam Crume, e a classe dele está publicada aqui. Eu não vou colar a classe aqui, pois ela é bem extensa, caso alguém precise, me comunique. Até aqui tudo muito bom, tudo muito bem. Só que eu, nunca satisfeito, com certeza fiquei coçando a cabeça tentando tornar o meu trabalho ainda mais genérico possível. Eu tenho um sério problema de querer automatizar muita coisa, e isso dá (muito) trabalho. Mas eu não desisti, e criei uma solução em conjunto com a do Adam. 
Na solução citada, podemos perfeitamente setar os nossos parâmetros agora através de nomes (não é por acaso que a classe foi batizada de NamedParameterStatement). Ela funciona da seguinte forma:
NamedParameterStatement p = new NamedParameterStatement(conexao,query);
p.setString("name","Eduardo");
p.setString("address","Rua sem Fim");
p.executeQuery();
Pois bem, ainda, de certa forma, precisamos setar os parâmetros na "mão" de alguma forma, mesmo que agora ficou ridiculamente mais fácil. Mas, por que não tornar isso um pouco mais inteligente? E se disséssemos assim: "eu vou passar a minha query para você. Você é quem cuide dela, afinal, você é quem sabe o que deve configurar nos parâmetros". E é aí que fiz uma solução para isso. 
A minha solução foi a seguinte, para cada bean que eu tiver, eu configuro um mapa de parâmetros (chave - valor). E para cada chave, eu coloco o valor do próprio bean. E quando eu precisar configurar os parâmetros da query, eu peço para que a query busque os seus parâmetros no bean que está sendo executado! Vamos ver um exemplo?
...
Map<String,Object> parametros = new HashMap<String,Object>();
public void setMapParameters() {
  parametros.put("chave", this.pk);
  parametros.put("nome", this.nome);
  parametros.put("endereco", this.endereco);
  parametros.put("telefone", this.telefone);
}

No código acima temos o nosso bean "Pessoa", onde para cada campo, eu coloquei em um mapa. Se eu vou usar ou não, pouco me importa, no futuro pode ser necessário. Então para cada campo de pessoa, eu coloquei o próprio valor desse bean. Lembre-se, no futuro sua SQL poderá mudar, então já deixe sua estrutura preparada.

Agora vem a parte old school. Sim, deu um trabalho danado para fazer isso. Essa segunda parte tratamos de fazer com que a SQL preencha corretamente cada um de seus parâmetros. Vamos ver como fica?


public void mapParameters(NamedParameterStatement p, String qry, Pessoa p) throws SQLException {
        int beginIndex = 0;
        int endIndex = 0;
        String parametro = "";
        String sqlOriginal = "";
        sqlOriginal = qry;
        for (int i = 0; i < qry.length(); i++) {
            if (qry.charAt(i) == ':') {
                beginIndex = i;
            }
            if (beginIndex != 0) {
                if (qry.charAt(i) == ' ' || qry.charAt(i) == ',' || qry.charAt(i) == ')' || i + 1 == qry.length()) {
                    endIndex = i + 1;
                    if (!Character.isLetter(qry.charAt(i))) {
                        endIndex = i;
                    }
                    parametro = qry.substring(beginIndex + 1, endIndex);
                    parametro = parametro.trim();
                    beginIndex = 0;
                    endIndex = 0;
                    Object valor = p.parametros.get(parametro.trim().toLowerCase());
                    if (valor instanceof Integer) {
                        p.setInt(parametro, (Integer) valor);
                    } else if (valor instanceof Timestamp) {
                        p.setTimestamp(parametro, (Timestamp) valor);
                    } else {
                        p.setString(parametro, (String) valor);
                    }
                    sqlOriginal = sqlOriginal.replace(":" + parametro, valor + "");
                }
            }
        }
        System.out.println(sqlOriginal);
    }
Legal, certo? E agora a parte mais legal, onde mostro como usar isso:
Pessoa p = new Pessoa();
p.nome = "Eduardo";
p.telefone = "9999";

String qry = "select * from pessoa where nome = :nome and telefone = :telefone";
NamedParameterStatement stmt = new NamedParameterStatement(conexao,qry);

this.mapParameters(stmt,qry,p);
stmt.executeQuery();
Veja, todo o trabalho de setar os parâmetros, ficou com o método mapParameters() que se encarregou de setar cada parâmetro no seu devido lugar. Nosso código ficou muito mais limpo e com chances de falhas quase 0, porque mesmo que eu adicione mais parâmetros na consulta, meu bean já está preparado com todos os parâmetros, e dinamicamente ele irá se entender. Essa é mais uma prova de que podemos sim melhorar nossos códigos para que fiquem o mais genérico possível, seguindo o lema "write once, run anywhere".

Ufa, o POST de hoje foi bem legal, não?
Um abraço, e até a próxima!

quinta-feira, 6 de junho de 2013

Melhorando performance em ETL com Java

Boa noite.
A linguagem Java nos proporciona a fazer milhares de aplicações a nosso gosto, integrações de vários tipos, processamentos complexos, carga de dados e outras "baixarias". Um dos processos mais onerosos que talvez possamos ter é efetuar transferência de dados de uma origem para um destino, em grande volume. Não, não é aquela sua tabela de clientes que possui 30.000 registros, 50.000 ou 100.000. Estamos falando de centenas de milhares de linhas, onde elas precisam ser transferidas para uma base estatística. O que estou falando aqui é de um processo típico de ETL. Sim, eu sei que o mercado oferece várias alternativas bem interessantes para fazermos cargas de dados para ambientes de Data Warehouse, tais como o Kettle (feito em Java inclusive), e o Integration Services da nossa amiga Microsoft. A plataforma SAP também possui um módulo de ETL, no entanto esqueci o nome da ferramenta. Enfim, todas essas ferramentas são ótimas no que fazem, só que tem um pequeno detalhe: quando sua regra de negócio começa a ficar muito complexa, as dificuldades começam a aparecer, e talvez se pudéssemos ter um controle melhor da situação, poderíamos ficar um pouco mais confortáveis com o processo que está sendo executado. Tudo bem, você pode programar tudo via banco de dados (PL/SQL), transferindo todo o overhead para o BD. Aí vai depender de caso a caso.
Sim, então vamos fazer em Java, muito legal não? Afinal, eu conheço Java, é só criar uns objetos ali, deixar tudo organizadinho e partir para o abraço... que bom se fosse fácil assim.
Primeiramente, você precisa ter em mente que você irá trabalhar com milhares e milhares de registros ao mesmo tempo, e precisa de um tempo razoável para fazer toda a transferência, fazendo corretamente todos os tratamentos necessários. Fazer um processo de ETL em Java envolve muito mais conceitos do que uma aplicação "comercial". Há preocupações sérias aqui, como por exemplo, o heap space da JVM e outras coisas. Mas, vamos ao que interessa. Se você tem um processo parecido e está enfrentando alguns problemas de performance, cito algumas dicas que pode auxiliá-lo a melhorar um pouco isso.
  1. Não invente moda. Sim, os frameworks estão aí para nos ajudar, deixam o código mais bonito e tudo, mas deixe-os para trás aqui. Considere usar JDBC puro para fazer esse tipo de coisa. No final das contas, ao usar um Framework, por "baixo dos panos" isso tudo vai ser convertido em milhares de PreparedStatements da vida, então, facilite e faça o acesso direto.
  2. Seja cuidadoso. Cuidado ao deixar recursos de conexão espalhados em seu código sem serem encerrados, como ResultSet's e PreparedStatement's.
  3. Ajude o GarbageCollector. Considere  dar uma "ajuda" básica ao seu coletor de lixo, liberando seus objetos através da atribuição = null.
  4. Processamento em lote. Se você faz todos os tratamentos e depois precisa inserir no banco de dados, porque não juntar uma quantidade considerável de linhas e mandar o banco executar tudo de uma vez só, em vez de linha a linha? Isso torna o processamento muito mais rápido! Agora, tenha cuidado para que as linhas que você irá mandar para o batch (lote) estejam todas corretas. Por corretas quero dizer que não tenham potencial para violar uma constraint por exemplo.
  5. Processamento paralelo. Se você pode carregar dados de duas tabelas ao mesmo tempo e as duas não tiverem dependência, considere o uso de Threads para auxiliá-lo!
Algumas dicas são básicas, outras nem tanto. O fato é que esse tipo de processamento é bem complicado, e nos tira noites de sono. Carga é sempre um assunto delicado.

Por hoje é só pessoal! Obrigado e até logo.