quarta-feira, 28 de agosto de 2013

Saia do meu caminho!

Boa noite.
Hoje é dia de resolvermos uns dos problemas mais graves do nosso atual jogo. Precisamos verificar se há peças em nosso caminho antes de realizarmos o movimento. Mas por que isso? Conforme dito no post anterior, todas as peças (com exceção do Cavalo), não podem passar por "cima" de outras em um movimento. Veja a figura abaixo que ilustra a situação:
Um movimento válido para a Torre seria uma casa antes do Peão branco. Assim como a Torre também não poderia fazer nenhum movimento horizontal neste momento, pois há um Cavalo na frente. 
E como resolver isso de forma dinâmica em nosso código?

Bom, de alguma forma, nós temos que percorrer as casas do tabuleiro procurando por peças que podem interferir em nosso caminho. Mas nós temos que escrever isso, e para saber qual peça nos atrapalhará precisamos realizar algumas validações. Por exemplo, vejamos a primeira peça que encontramos no tabuleiro que não seja a Torre, que é o Cavalo. Poderíamos fazer a seguinte pergunta: o movimento da Torre é válido com relação ao Cavalo? A resposta é SIM, então essa é uma potencial peça que poderá atrapalhar nossos planos de movimento. Vejamos a segunda peça, que é o Peão branco que se encontra na primeira coluna. O movimento da Torre é válido com relação a essa peça? A resposta é SIM novamente, então esta é uma outra peça que poderia atrapalhar o movimento. Agora veja a última peça, que também é um Peão branco só que na segunda coluna. O movimento da Torre é válido com relação a essa peça? A resposta é NÃO, pois uma Torre nunca poderia chegar àquela posição considerando a posição atual dela. Então temos duas peças que podem atrapalhar o movimento. O próximo passo é verificar se cada peça que se encontra em nosso caminho está verdadeiramente no trajeto do destino. Começamos pela primeira peça, o Cavalo. Esta peça está no mesmo trajeto que o destino escolhido para a Torre? A resposta é NÃO, pois o destino da Torre é a mesma coluna só que anda várias linhas, enquanto o cavalo está na mesma linha. Agora a segunda peça, o Peão branco está no mesmo trajeto que o destino escolhido para a Torre? A resposta é SIM, porque a linha do Peão é uma linha antes do destino escolhido para a Torre. Desta forma o movimento é inválido. Se o destino da Torre fosse uma linha antes, o peão ainda estaria no trajeto, porém a linha do Peão seria uma DEPOIS do destino, então não teria problema.
Consegue entender a complexidade de traduzirmos isso para o código?
Então vamos lá. Primeiramente, criaremos um método na classe TabuleiroModel, chamado temPecaNaFrente. Este método responderá a todas as questões levantadas acima:

private boolean temPecaNaFrente(PecaModel p, int novaLinha, int novaColuna) {
        boolean temPeca = false;
        if (novaLinha > p.getLinha()) {
            a1: for (int i = p.getLinha(); i <= novaLinha; i++) {
                if (isColunaComOutraPeca(p, novaColuna, i, novaLinha)) {
                    temPeca = true;
                    break a1;
                }
            }
        } else {
            a2: for (int i = p.getLinha(); i >= novaLinha; i--) {
                if (isColunaComOutraPeca(p, novaColuna, i, novaLinha)) {
                    temPeca = true;
                    break a2;
                }
            }
        }
        return temPeca;
    }
O método acima verifica se a nova linha é maior do que a linha da peça selecionada. Caso seja, então vamos percorrer linha a linha, de forma crescente, para verificar se cada casa possui uma peça na frente. Repare que em cada iteração do laço for é invocado um método isColunaComOutraPeca, que será criado mais adiante. Se este método retornar verdadeiro, paramos a iteração do laço e atribuímos true a variável temPeca. Caso a nova linha seja MENOR do que a linha da peça selecionada, ou seja, está voltando, o método também faz a verificação linha a linha, porém de forma inversa.
Lembre-se, todo o nosso tabuleiro não passa de uma matriz (um array de arrays). O método isColunaComOutraPeca é criado abaixo:

private boolean isColunaComOutraPeca(PecaModel p, int novaColuna, int i, int novaLinha) {
        if (novaColuna > p.getColuna()) {
            for (int j = p.getColuna(); j <= novaColuna; j++) {
                PecaModel pecaNaFrente = this.getPeca(i, j);
                if (pecaNaFrente != null && !pecaNaFrente.equals(p)) {
                    if (pecaNaFrente.getColuna() == novaColuna && !pecaNaFrente.getCorOriginal().equals(p.getCorOriginal())    ) {
                        continue;
                    }
                    return true;
                }
            }
        } else if (novaColuna < p.getColuna()) {
            for (int j = p.getColuna(); j >= novaColuna; j--) {
                PecaModel pecaNaFrente = this.getPeca(i, j);
                if (pecaNaFrente != null && !pecaNaFrente.equals(p)) {
                    if (pecaNaFrente.getColuna() == novaColuna && !pecaNaFrente.getCorOriginal().equals(p.getCorOriginal())    ) {
                        continue;
                    }
                    return true;
                }
            }
        } else {
            PecaModel pecaNaFrente = this.getPeca(i, novaColuna);
            if (pecaNaFrente != null && !pecaNaFrente.equals(p)) {
                if (!(pecaNaFrente.getLinha() == novaLinha && !pecaNaFrente.getCorOriginal().equals(p.getCorOriginal()))) {
                    return true;
                }
            }
        }
        return false;
    }


Este método executa a seguinte lógica. Ele verifica se a coluna de destino é maior do que a coluna da peça selecionada. No caso da Torre, isso só será verdade para movimentos lineares. Depois dessa verificação, fazemos um laço partindo da coluna da peça selecionada até a coluna de destino, e buscamos então qualquer peça que esteja naquela linha e coluna. Caso exista uma peça, e essa peça não for a própria peça selecionada, então já sabemos que há alguma peça atrapalhando o caminho. Mas ainda tem mais... se a coluna da peça que está atrapalhando o caminho for igual a coluna de destino e a cor NÃO for igual a peça selecionada, então temos aqui uma peça inimiga! E isso quer dizer que temos que eliminá-la! Então o movimento torna-se válido, caso contrário o movimento torna-se inválido. A lógica se repete caso a coluna de destino for menor do que a coluna da peça selecionada ou quando a coluna de destino é igual a coluna da peça selecionada.

UFA! Quanta coisa, não? Agora uma última coisa, precisamos chamar o método temPecaNaFrente no método realizaJogada:

public void realizaJogada(int linha, int coluna) {
        if (pecaSelecionada == null) {
            pecaSelecionada = this.getPeca(linha, coluna);
            if (pecaSelecionada != null) {
                pecaSelecionada.setSelecionada(true);
            }
        } else {
            PecaModel outraPeca = this.getPeca(linha, coluna);
            if (outraPeca != null && outraPeca.equals(pecaSelecionada)) {
                pecaSelecionada.setSelecionada(false);
                pecaSelecionada = null;
            } else {
                if (pecaSelecionada.validaMovimento(linha, coluna)
                        && !this.temPecaNaFrente(pecaSelecionada, linha, coluna)) {
                    this.pecas[pecaSelecionada.getLinha()][pecaSelecionada
                            .getColuna()] = null;
                    this.pecas[linha][coluna] = pecaSelecionada;
                    pecaSelecionada.setSelecionada(false);
                    pecaSelecionada.setLinha(linha);
                    pecaSelecionada.setColuna(coluna);
                    pecaSelecionada = null;
                }
            }
        }
        this.notificaListener();
    }


Definitivamente há outras formas de fazer, mas por enquanto essa é a maneira que encontrei.
Nos próximos POSTS continuaremos a validar os movimentos das outras peças, temos muito trabalho pela frente!

Um abraço e até logo.  

sábado, 24 de agosto de 2013

O livre arbítrio das peças não é tão livre assim

Bom dia.
Nosso jogo de Xadrez está evoluindo. Precisamos agora implementar as regras do jogo. E é aí que começa a ficar um pouco mais complicado.
No POST anterior, implementamos o movimento das peças, fazendo-as circular livremente por todo o tabuleiro. Mas eu e você sabemos que em um jogo verdadeiro de Xadrez, existem regras, e que essas regras impedem um determinado tipo de movimento para uma peça específica. Além disso, nenhuma peça pode "passar por cima" de outra peça, com exceção do poderoso Cavalo (minha peça preferida, diga-se de passagem).
O que precisamos agora é implementar, de alguma forma, a regra do movimento de cada peça. Por exemplo, a Torre não pode mover-se diagonalmente, enquanto que o Bispo não pode realizar movimentos horizontais/verticais, somente diagonais. O Cavalo, por sua vez, faz o movimento em "L", enquanto a Rainha herda a capacidade de movimento do Bispo + Torre.
São essas regras que vamos começar a implementar a partir de agora, e começaremos pelo mais fácil: a Torre.
Vamos fazer algumas modificações em nossas classes. Primeiramente, vamos tornar a nossa classe "PecaModel" uma classe abstrata. Por que isso? Veremos mais adiante que teremos um método em comum para todas as peças, que serão implementados de formas diferentes, e precisamos do Polimorfismo para fazer a "coisa" funcionar:

public abstract class PecaModel {...}

Não se assuste com os erros de compilação que você receberá a partir do momento que fizer isso. 
Na sequência, vamos criar um método abstrato que deverá ser implementado por todas as classes filhas e que será responsável por validar o movimento daquela determinada peça:

public abstract boolean validaMovimento(int novaLinha, int novaColuna); 

Basicamente vamos verificar se a peça pode se mover para a nova linha e a nova coluna desejada.
O próximo passo é começarmos a criar as classes de cada peça e implementarmos o método validaMovimento de acordo com a regra daquela peça. Vamos começar pela Torre, conforme dito no início:

public class Torre extends PecaModel {

    @Override
    public boolean validaMovimento(int novaLinha, int novaColuna) {
        if (this.getColuna() != novaColuna && this.getLinha() == novaLinha) {
            return true;
        } else if (this.getLinha() != novaLinha && this.getColuna() == novaColuna) {
            return true;
        }
        return false;
    }
   
    public Torre(String cor, int linha, int coluna, String corOriginal) {
        super(cor,linha,coluna,corOriginal);
    }
} 


Vamos entender o que isso faz? Primeiramente, observe a anotação @Override que indica que estamos sobrescrevendo nosso método validaMovimento. Bom, sabemos que a Torre não pode realizar movimentos diagonais, então a lógica do método validaMovimento é verificar se isso é verdade ou não. Perceba que a lógica é muito boba. O primeiro if verifica se a coluna da peça que eu cliquei é diferente da coluna de destino. Se isso for verdade, a linha de destino tem que ser IGUAL a linha da peça selecionada. Ou seja, este primeiro if valida o movimento horizontal, já que a linha é a mesma. Já o else trata o inverso. Se a linha da peça que eu cliquei for diferente da linha de destino, a coluna de destino tem que ser IGUAL a coluna da peça que eu selecionei, ou seja, estamos validando o movimento vertical, já que a coluna é a mesma. Consegue entender a complexidade de movimento de outras peças, como por exemplo o poderoso Cavalo? Bom, eu ainda não quero pensar nisso. Continuando na classe Torre, vemos que temos um construtor que chama a versão da super classe. Isso é porque cada peça tem que instanciar os atributos padrão que todas as peças tem (linha, coluna, etc). Crie o atributo "corOriginal" na classe PecaModel para que possamos ter um valor somente com PRETA ou BRANCA, mais adiante veremos o motivo disso. 
Feito isso, precisamos alterar a classe TabuleiroModel pois ela está instanciando objetos abstratos, o que está incorreto e nem compila. Precisamos alterar o método montaTabuleiro() para criar classes concretas, desta forma:

public void montaTabuleiro() {
        pecas[0][0] = new Torre("TORREPRETO.gif", 0, 0, "PRETA");
        pecas[0][1] = new Cavalo("CAVALOPRETO.gif", 0, 1, "PRETA");
        pecas[5][0] = new Peao("PEAOBRANCO.gif", 5, 0, "BRANCA");
        pecas[6][1] = new Peao("PEAOBRANCO.gif", 6, 1, "BRANCA");
    }


OBS: Ainda não criamos a validação de movimento para as outras peças, mas coloque-as no tabuleiro para que você possa verificar se o movimento da Torre está correto.
Veja que o atributo que criamos "corOriginal" é somente para dizermos se a peça é PRETA ou BRANCA.
O último passo agora é passar a responsabilidade para o Tabuleiro, para que, ao tentar realizar o movimento, este pergunte à peça se ela pode se movimentar para o destino selecionado. Precisamos alterar o método realizaJogada() para que fique desta forma:

public void realizaJogada(int linha, int coluna) {
        ...
            } else {
                if (pecaSelecionada.validaMovimento(linha, coluna)) {
                    ...
                }
            }
        }
 }

Não colocarei o método inteiro pois já temos no POST anterior, veja somente que a parte alterada foi no else, onde adicionamos a chamada do validaMovimento para a peça em questão. Todo o código do else só poderá ser executado se o movimento for válido!

Ah... temos ainda muito o que fazer. Esta foi a validação apenas da Torre, mas temos todas as outras ainda para fazer. Além do mais, você não se esqueceu de que a única peça que passa por "cima" de outra é o Cavalo, certo? Então prepare-se para isso, que no próximo POST vamos trabalhar nesta funcionalidade:

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

quinta-feira, 15 de agosto de 2013

Dança das peças

Boa noite galera!
É hora de dar vida as nossas peças. O nosso tabuleiro de Xadrez precisa nos proporcionar movimentos, para que você possa usar aquela sua jogada bem trabalhada e causar arrepios em seu adversário.
Chega de conversa, vamos trabalhar porque temos muito o que fazer.
Para começar, vou partir do princípio de que você já esteja um pouco familiarizado com os eventos do Java (ActionListener, MouseListener, etc). Caso não faça ideia do que eu estou falando, é melhor dar uma lida aqui. Caso contrário, saberá que alguma de nossas classes terá que responder aos eventos de mouse (clique). Como saber qual peça está selecionada e qual casa eu cliquei? Usaremos um MouseListener que "escutará" os eventos de clique no tabuleiro para nos ajudar a responder essas perguntas.

Não postarei o código todo novamente, e sim as partes que formos alterando, ok?
Bom, então a primeira coisa a fazer é com que a nossa classe Tabuleiro implemente a interface MouseListener para escutar os eventos de clique:

public class Tabuleiro extends JPanel implements MouseListener{...}

Ao fazer isso, nós temos que fornecer implementações "válidas" para todos os métodos abstratos declarados nessa interface. Por "válidas" entenda que o método tem que ter um corpo (par de chaves). De todos os métodos, o único que realmente precisaremos escrever alguma lógica é o mouseClicked que é efetivamente o clique do mouse.
Vamos para a implementação?

@Override
    public void mouseClicked(MouseEvent arg0) {
        Celula c = (Celula)arg0.getSource();
        this.tabuleiroModel.realizaJogada(c.getLinha(), c.getColuna());
    }

Hey! Que método é esse de "realizaJogada"? Calma, já vamos chegar lá. Primeiro vamos entender esse método. Na primeira linha, usamos o método getSource() do argumento MouseEvent para descobrirmos e pegarmos que tipo de objeto veio como resposta ao clique. Como nosso tabuleiro é preenchido somente com células, o downcast é extremamente seguro, não sendo necessário fazer a verificação com instanceof. Na segunda linha, passamos a linha e a coluna da célula selecionada para um método realizaJogada do objeto TabuleiroModel, que será explicado e criado a seguir.

Como estamos aplicando boas práticas MVC no nosso projeto, a "lógica" do negócio não pode estar na camada de apresentação. E é por isso que o método realizaJogada será criado no TabuleiroModel. Mas, o que esse método precisa fazer? Como você deve lembrar, na classe TabuleiroModel possuímos uma matriz de peças. A lógica é basicamente tirar a peça selecionada da posição antiga e colocá-la na nova posição. Exemplo:
Figura 01: Preparando movimento da Torre

Observe que selecionamos a peça TORRE e queremos andar uma "casa" para frente. Vamos implementar essa lógica. Primeiramente, vamos criar uma variável na classe TabuleiroModel para representar a peca que está sendo selecionada no momento:

private PecaModel pecaSelecionada = null;

A seguir, veja a lógica do método:
public void realizaJogada(int linha, int coluna) {
        // se não há peça selecionada, pegue a peça da linha e coluna e marque-a como selecionada = true
        if (pecaSelecionada == null) {
            pecaSelecionada = this.getPeca(linha, coluna);
            if (pecaSelecionada != null) {
                pecaSelecionada.setSelecionada(true);
            }
        } else {
            // caso haja uma peça selecionada, quer dizer que falta definir o destino da peça selecionada.
            PecaModel outraPeca = this.getPeca(linha, coluna);
            // aqui verificamos se o usuário clicou na mesma peça. Caso tenha clicado, só setar a propriedade "selecionada" para false.
            if (outraPeca != null && outraPeca.equals(pecaSelecionada)) {
                pecaSelecionada.setSelecionada(false);
                pecaSelecionada = null;
            } else {
                // caso o destino selecionado não seja a própria peça selecionada, então "atualizamos" a posição da peça.
                this.pecas[pecaSelecionada.getLinha()][pecaSelecionada.getColuna()] = null;
               
                this.pecas[linha][coluna] = pecaSelecionada;
                pecaSelecionada.setSelecionada(false);
                pecaSelecionada.setLinha(linha);
                pecaSelecionada.setColuna(coluna);
                pecaSelecionada = null;
            }
        }
    }

Observe que o método "realizaJogada" será chamado a cada vez que o usuário clicar o mouse.
Se compilarmos e executarmos este código, não vamos notar diferença nenhuma na nossa tela. Isso porque nós não atualizamos o nosso tabuleiro visual! E agora, quem poderá nos salvar?
Precisamos criar uma forma de "avisar" a camada de visão (o nosso tabuleiro visual) que o modelo foi alterado. Se você já ouviu falar no padrão "Observer", sabe do que estou falando. Vamos criar uma simples interface "ouvidora" de tabuleiros:

public interface TabuleiroListener {
    public void tabuleiroChanged();
}

Esta interface define apenas um método que será responsável por atualizar o nosso tabuleiro visual. E quem deve implementar essa interface? O "provedor" dos eventos, ou seja, aquela classe que irá disparar os eventos. Você já sabe. É claro que é a classe Tabuleiro quem deve implementar esta interface, visto que os cliques (ações) ocorrem lá. Vamos ao código?

public class Tabuleiro extends JPanel implements TabuleiroListener, MouseListener {
...
 @Override
    public void tabuleiroChanged() {
        this.montaTabuleiro();
    }
}

Se você olhar nos posts anteriores, saberá que o método montaTabuleiro coloca as peças no lugar e reorganiza o layout. Então a ideia é simples, mas quem que vai chamar esse método tabuleiroChanged()? Beleza, ele está aí declarado, implementado, mas não vejo ninguém o chamando. Bom, se o modelo foi alterado, quem é responsável por avisar a visão de que houve alguma mudança? É claro que é o próprio modelo quem deverá invocar esse método!
Vamos fazer isso funcionar de vez.
Crie uma variável do tipo TabuleiroListener na classe TabuleiroModela:

private TabuleiroListener listener;

Em seguida, crie um método configurador na mesma classe, para atribuirmos um valor a essa variável:
public void setTabuleiroListener(TabuleiroListener listener) {
        this.listener = listener;
}

Agora, no construtor da classe Tabuleiro, registre-o como "ouvinte" do modelo:
tabuleiroModel.setTabuleiroListener(this);

Esta linha está dizendo: "hey, quero ficar sabendo de todas as alterações aí no seu modelo!".
Pois bem, agora só falta dizer para o modelo avisar a visão de que ele mesmo se alterou.
Lembra do método realizaJogada()? Pois bem, ao final dele, basta fazer esse aviso a visão:

listener.tabuleiroChanged();

Ou seja, a cada jogada realizada, esse método será invocado. E adivinha... ? O método tabuleiroChanged remonta todo o tabuleiro, pegando as alterações que foram feitas!
Veja o resultado abaixo:

Imagem 02: Torre prestes a ser movida
Imagem 03: Torre em sua nova posição

Ufa! Quanta coisa! Mas não se iluda, falta muuuuita coisa a ser feita. Por exemplo, ainda não estamos validando o movimento das peças... a torre pode se movimentar em todos os sentidos, o que em um jogo de Xadrez isso não é permitido. Então, mãos a obra e aguardem o próximo POST para fazermos o movimento válido das peças, verificando se existem peças "inimigas"e todas as particularidades do jogo.
É agora que começa a ficar divertido, então, não percam!

Um abraço e até a próxima :)

terça-feira, 30 de julho de 2013

Colocando as peças no lugar

Olá.
Depois de alguns dias de molho e outros ocupado demais, cá estou para continuarmos nosso jogo de Xadrez.
No último POST, prometi que iria mostrar como colocar as peças no tabuleiro.
Pois bem. As peças na realidade nada mais são do que uma coleção de PecaModelS na matriz Pecas, localizada na classe TabuleiroModel. Você se lembra disso?
Caso não lembre, declaramos ele da seguinte forma:

private PecaModel pecas[][];

Nós vamos colocar as nossas peças no método montaTabuleiro() da classe TabuleiroModel, que havíamos deixado em branco antes. Observe que para construir uma Peca, precisamos informar a cor, a linha e a coluna:

public void montaTabuleiro() {
        pecas[0][0] = new PecaModel("TORREPRETO.gif", 0, 0);
        pecas[0][1] = new PecaModel("CAVALOPRETO.gif", 0, 1);
        ...
    }

Repare que só fiz para as duas primeiras peças, mas você deve terminar até completar todas as peças. Agora, porque eu coloquei aquele nome "TORREPRETO.gif", sendo que ali teoricamente deveria ser a cor da peça? Bem, vou explicar isso daqui a pouco, mas vou adiantar um pouco. Nós precisamos representar as nossas peças graficamente, ou seja, precisamos ter um cavalo ou uma torre em forma de figura para que seja um jogo de Xadrez de verdade, e o que eu informei ali é um nome de um arquivo. 

Continuando, vamos para a classe Peca, aquela que extends JLabel, lembra? Vamos relembrar o construtor desta classe:

public Peca(PecaModel peca) {
        this.pecaModel = peca;
}

Aqui nada de estranho, associamos um PecaModel a nossa classe Peca. Mas é agora que vem o segredo. Lembra que no construtor de PecaModel eu passei um nome de arquivo? Pois é aqui que vamos usá-lo, para que, ao associarmos um PecaModel a uma Peca, possamos buscar uma imagem para associação!
Vamos mudar o nosso construtor de Peca para o seguinte código:

public Peca(PecaModel peca) {
        this.pecaModel = peca;
        this.setIcon(new ImageIcon(getClass().getResource(
                "/imagens/" + pecaModel.getCor())));

}

Observe o método setIcon (sim, é this porque Peca É-UM JLabel, e JLabel possui um método setIcon!).
E que diretório é esse /imagens? Crie um subdiretório no src com o nome imagens. É aqui que suas peças deverão ser adicionadas. Observe que o nome do arquivo deve coincidir com o nome que você passou no construtor de PecaModel.

Chegando na última parte do nosso POST de hoje, precisamos mostrar essas peças no tabuleiro. No artigo anterior, conseguimos mostrar o tabuleiro, através do método montaTabuleiro da classe Tabuleiro. Vamos modificá-lo para adicionar as peças? Destacarei as partes que foram adicionadas em vermelho para facilitar o entendimento:

private TabuleiroModel tabuleiroModel = new TabuleiroModel();

public void montaTabuleiro() {
        this.setLayout(new GridLayout(8, 8));
        tabuleiroModel.montaTabuleiro();

        this.removeAll();
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                PecaModel pecaModel = tabuleiroModel.getPeca(i, j);
                Celula celula;
                if (pecaModel != null) {
                    Peca peca = new Peca(pecaModel);
                    celula = new Celula(peca);
                } else {
                    celula = new Celula(i, j);
                }

                if ((i + j) % 2 == 0) {
                    celula.setBackground(Color.WHITE);
                } else {
                    celula.setBackground(Color.BLACK);
                }
                this.add(celula);
            }
        }
        this.revalidate();
    }

Vamos a lógica dos elementos novos adicionados no código. Primeiramente, instanciamos um TabuleiroModel fora do método montaTabuleiro para que possamos ter uma referência ao modelo do tabuleiro (ou seja, acessar suas peças, etc). Na sequência, pedimos para o tabuleiro se organizar (para o modelo se ajustar, colocando as devidas peças em seus devidos lugares). Para cada linha/coluna, nós criamos um PecaModel e verificamos se naquela linha e coluna há uma peça. Caso haja (pecaModel != null), então construímos uma Celula passando quem? Exatamente a peca que está naquela posição! A célula já saberá em qual linha e coluna deverá ser colocada, pois a própria Peca tem essa informação. Caso não haja nenhuma peça na respectiva linha e coluna, construímos uma célula em branco. Muito bacana, não é?
O resultado deverá ficar assim:



Imagem 01: Tabuleiro com peças

Mas ainda temos muito trabalho pela frente. Neste momento, não conseguimos mover sequer uma peça e nem fazer nenhum tipo de interação, ou seja, JOGAR. No próximo POST, aprenderemos a criar VIDA para as nossas queridas peças! Um abraço e até logo!                                                  






sexta-feira, 19 de julho de 2013

Erro ao liberar conexão no DB2

Para liberar uma conexão (chamar close() em um objeto Connection) utilizando DB2, verifique o autoCommit da sua conexão. Caso esteja como FALSE, você precisará fazer um commit() ou um rollback() explícito na conexão antes de liberá-la, se não o fizer, você receberá um belo SQLException dizendo que o estado da transação é inválido. Caso o seu autoCommit estiver como TRUE, então não é necessário fazer os comandos acima.
Demorei uns 40 minutos entre debug e pesquisa no Google para achar uma referência.
Estou utilizando o driver db2java.jar e não procurei um driver mais recente, então pode ser que já tenham corrigido essa detalhe em versões mais recentes.
Enfim, se enfrentou esse mesmo problema, aí está a solução.

Até a próxima dica rápida! :)

quinta-feira, 18 de julho de 2013

Criando forma ao nosso tabuleiro

Boa noite!
No post anterior, demos início ao nosso jogo de Xadrez.
Hoje vamos dar forma ao nosso tabuleiro. Mas, para isso, precisamos modificar e incluir novas coisas em nosso projeto.
Nós precisamos de uma maneira de representar o modelo de nosso tabuleiro. Aqui não estamos falando do tabuleiro em si, aquele que você vê na tabela, mas estamos falando do que um tabuleiro contém. Então, vamos criar o código que representará isso:
public class TabuleiroModel {
 private PecaModel pecas[][];

 public TabuleiroModel() {
  pecas = new PecaModel[8][8];
 }

 public void montaTabuleiro() {
 }

 public PecaModel[][] getPecas() {
  return pecas;
 }

 public void setPecas(PecaModel[][] pecas) {
  this.pecas = pecas;
 }
 
 public PecaModel getPeca(int linha, int coluna) {
  return pecas[linha][coluna];
 }
}

Veja que aqui não temos nenhum elemento de interface gráfica. Esta classe apenas representa o modelo do tabuleiro. Mas e o que é aquele PecaModel? Bom, precisamos de Peças em nosso jogo, correto? Então, assim como o tabuleiro, precisamos de uma classe que representa cada peça do jogo. Vamos ao código, para que a classe TabuleiroModel faça mais sentido:
public abstract class PecaModel {
 private boolean selecionada;
 private String cor;
 private int linha;
 private int coluna;

 public int getLinha() {
  return linha;
 }

 public void setLinha(int linha) {
  this.linha = linha;
 }

 public int getColuna() {
  return coluna;
 }

 public void setColuna(int coluna) {
  this.coluna = coluna;
 }

 public PecaModel(String cor, int linha, int coluna) {
  this.cor = cor;
  this.linha = linha;
  this.coluna = coluna;
 }

 public boolean isSelecionada() {
  return selecionada;
 }

 public void setSelecionada(boolean selecionada) {
  this.selecionada = selecionada;
 }

 public String getCor() {
  return cor;
 }

 public void setCor(String cor) {
  this.cor = cor;
 }
}

Bom, a classe acima representa uma peça. Não sabemos que tipo de peça é (torre, cavalo, etc), por isso ela é uma classe abstrata. Não faz sentido fazer Peca p = new Peca(). Que cor? Que tipo de peça? Por esse motivo ela é abstrata. Se observamos a classe TabuleiroModel, vamos encontrar uma matriz de PecaModel, representado pelo atributo pecas. Ele representa uma matriz de 8x8, onde cada posição dessa armazenará um PecaModel. E faz muito sentido isso, porque dizemos "um tabuleiro tem várias peças". O método que nos auxiliará a "pegar" determinada peça de nosso tabuleiro é o getPeca, onde o mesmo retorna um PecaModel, recebendo a linha e a coluna que a suposta peça se encontra (mais para frente vamos entender o porque de "suposta").

A princípio, nosso modelo está pronto. Temos nosso tabuleiro e nossa peça representados corretamente. Agora é hora de partirmos para a interface gráfica do nosso tabuleiro! Precisamos fazer alguns ajustes antes de termos nosso tabuleiro na tela.No post anterior, nós já criamos a classe que representa o tabuleiro graficamente. O que precisamos fazer agora é representar a Peca graficamente. Vamos escrever isso?
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Peca extends JLabel {
 private PecaModel pecaModel;

 public PecaModel getPecaModel() {
  return pecaModel;
 }

 public void setPecaModel(PecaModel pecaModel) {
  this.pecaModel = pecaModel;
 }

 public Peca(PecaModel peca) {
  this.pecaModel = peca;
 }
}

A classe Peca faz um extends em JLabel, para que possamos plotá-lo no tabuleiro. É um label normal, não há nada de diferente aqui. Além disso, observe que temos um atributo do tipo PecaModel (que é o modelo). O que é interessante é que não estamos colocando nossa regra de negócio na tela, o que é um bom começo, visto que, se lá na frente formos precisar usar uma interface Web, não teríamos problemas.

Calma, já estamos quase lá...

Lembra da classe Celula do post anterior? Vamos melhorá-la para se adequar a nossa nova realidade:
import javax.swing.JPanel;

public class Celula extends JPanel {
 private int linha;
 private int coluna;
 private Peca peca;
 
 public Celula(Peca peca) {
  this(peca.getPecaModel().getLinha(),peca.getPecaModel().getColuna());
  this.peca = peca;
  this.add(peca);
 }
 
 public Celula(int linha, int coluna) {
  this.linha = linha;
  this.coluna = coluna;
 }

 public int getLinha() {
  return linha;
 }

 public void setLinha(int linha) {
  this.linha = linha;
 }

 public int getColuna() {
  return coluna;
 }

 public void setColuna(int coluna) {
  this.coluna = coluna;
 }

 public Peca getPeca() {
  return peca;
 }

 public void setPeca(Peca peca) {
  this.peca = peca;
 }

}
Vamos com calma. Fiz questão de destacar as partes mais importantes dessa classe. Primeiramente, vemos um atributo do tipo Peca. Mas dessa vez NÃO é nosso modelo, é a Peca representada graficamente... pois quem tem o modelo da peca (PecaModel) é a própria classe Peca! Observe também os dois construtores da classe Celula, um recebendo uma Peca e outro recebendo uma linha e uma coluna... mas agora não é hora de explicar o porque disso. Apenas atente-se ao fato de que quando o construtor que recebe uma Peca é invocado, a célula adiciona a Peca a ela mesma, como se estivéssemos dizendo "Ok, coloque uma peça nessa célula aqui".
Bom, chegou a hora de montar o nosso tabuleiro (pelo menos fazer ele aparecer na tela!).
import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class Tabuleiro extends JPanel {
 public void montaTabuleiro() {
  this.setLayout(new GridLayout(8, 8));
  this.removeAll();
  for (int i = 0; i < 8; i++) {
   for (int j = 0; j < 8; j++) {
    Celula celula;
    celula = new Celula(i, j);
    if ((i + j) % 2 == 0) {
     celula.setBackground(Color.WHITE);
    } else {
     celula.setBackground(Color.BLACK);
    }
    this.add(celula);
   }
  }
  this.revalidate();
 }
}
Ué, e cade todos aquelas classes que sofremos para codificar?
Calma... estamos fazendo a base para o próximo POST, se não ia perder toda a graça, não é mesmo? :)
Bom, vamos explicar esse código:
A classe Tabuleiro continua sendo um JPanel, como no post anterior. Observe que fizemos um duplo laço (para simular a varredura em uma matriz mesmo), sendo o "i" a linha e o "j" a coluna. Dentro do laço mais interno, veja que instanciamos um objeto Celula, passando como parâmetros quem? A linha e a coluna! Ou seja, agora sabemos exatamente qual posição a célula ocupará no tabuleiro. Para saber se ela deve ser preta ou branca, fazemos a seguinte lógica: se o resto da divisão da soma entre i e j for igual a 0, então pintamos de branco, se não pintamos de preto. Após termos pintado a célula, precisamos adicioná-la no painel, através do método add(celula).
O final deverá se parecer com isso:

Ufa! Quanto trabalho por hoje! No próximo POST, vamos utilizar toda a estrutura que criamos anteriormente, para começarmos a colocar as nossas peças no tabuleiro! Uma prévia do que vem pela frente:
  Nosso tabuleiro conterá peças! :) Então, até a próxima!

PS: Achei esse link para formatar códigos muito bom! Parabéns ao criador.





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!