jun 14

O PostgreSQL permite que usuários possam desenvolver funções em outras linguagens, além de SQL. Essas linguagens são chamadas de procedural languages (PLs), ou linguagens procedurais. Linguagens como C, Tcl, Python, Perl, Java, e outras, são suportadas desde que informadas no momento da compilação e instalação do postgres.

Para verificar as PLs suportadas pelo seu postgres (as que foram ativadas no momento da instalação) basta executar a seguinte SQL:

  • SELECT * FROM pg_language;

Você pode adicionar o suporte a outras linguagens, que não estejam listadas ao executar a SQL acima. Mas para isso seria necessário recompilar e reinstalar o postgres ou, em algumas distribuições Linux, por exemplo, instalar o pacote RPM adicional para suportar a linguagem desejada.

O postgres já vem com suporte nativo a algumas linguagens, sem a necessidade de informá-las no momento da instalação, como: SQL, PLPgSQL, Internal e C. Utilizar uma dessas linguagens nativas nos poupa tempo e tem um custo menor, uma vez que não precisaremos instalar novos interpretadores ou compiladores na máquina onde está instalado nosso postgres.

No órgão onde trabalho surgiu a necessidade de se criar uma PL no postgres para envio de e-mail. Ao fazer uma busca pelo Google encontrei facilmente duas soluções: uma delas utilizando a linguagem Tcl e a outra utilizando Python. Ambas as soluções são simples e de fácil implementação, além de funcionarem perfeitamente. O problema em utilizar uma dessas duas soluções é que possuímos mais de 8 servidores rodando o PostgreSQL, o que aumentaria o custo para implementar tal função, já que teríamos que recompilar o postgres com suporte a uma dessas duas linguagens, além de termos que instalar seus compiladores e interpretadores.

Depois de exaustivas tentativas buscando alguma solução para envio de e-mail em linguagem C para o postgres acabei optando por desenvolver uma. Claro que para diminuir o trabalho fui em busca de uma solução já pronta em C apenas para envio de e-mail. Achei algumas bibliotecas e códigos em C, mas um tanto complicados e grandes demais para uma pequena tarefa. Eu queria apenas um código simples, de poucas linhas e que atendesse à necessidade: envio de e-mail (não necessitava nem mesmo de autenticação via SMTP, já que eu iria adicionar o endereço dos servidores postgres como Open Relay no servidor de e-mail). Achei então o que eu estava procurando: apenas um arquivo de código, simples e funcional, que envia e-mail via socket, sem a necessidade de bibliotecas adicionais. Até o nome da solução é simples: Simple SMTP Mailer desenvolvido por Mayukh Bose. (O código pode ser encontrado em seu site pessoal: http://www.mayukhbose.com/freebies/c-code.php#smtp).

Com o código de envio de e-mails em mãos, fui em busca de uma boa documentação para integrar tal funcionalidade ao PostgreSQL. Encontrei na própria documentação do postgres, inclusive já traduzida para o português no site: http://pgdocptbr.sourceforge.net/pg80/xfunc-c.html. Esta documentação é bem completa e explica detalhadamente como desenvolver uma PL em linguagem C para o postgres. Sugiro que leia toda a documentação antes de iniciar o desenvolvimento de uma PL para o postgres.

Para desenvolver a função, utilizei a convenção mais atual para PL chamada de Versão 1 (mais fácil e com mais recursos que a versão anterior chamada Versão 0). Essa versão diminui a complexidade de troca de dados entre o postgres e seu código em C.

Para declarar uma função em C utilizando a Versão 1, basta declará-la desta forma:

Datum nome_da_função(PG_FUNCTION_ARGS)

e chamar a macro:

PG_FUNCTION_INFO_V1(nome_da_função);

que deve obrigatoriamente estar no mesmo arquivo fonte da sua função e, por convenção, estar escrita antes da própria função.

Na função em versão-1 os argumentos enviados pela função do postgres são recuperados utilizando a macro PG_GET_xxx(y), onde xxx corresponde ao tipo de dado do argumento e y corresponde ao número do argumento da função a ser buscado, iniciado a partir de 0. Podemos também retornar dados para o postgres utilizando a macro PG_RETURN_xxx(y) onde xxx corresponde ao tipo de dado a ser retornado e y corresponde ao valor a ser retornado.

Veja como exemplo a função abaixo, escrita em C, retirada do site da documentação do Postgres:

Código em C:

#include "postgres.h"
#include
#include "fmgr.h"

PG_FUNCTION_INFO_V1(somar_um);

Datum
somar_um(PG_FUNCTION_ARGS)
{
    int32   arg = PG_GETARG_INT32(0);

    PG_RETURN_INT32(arg + 1);
}

A função acima é simples: apenas recebe do postgres um inteiro como parâmetro e retorna como valor o resultado do incremento do valor recebido em 1 unidade.

Para que a função acima funcione precisamos obviamente de compilar nosso código e criar sua função relativa em SQL:

Função em SQL para integração com o código em C:

CREATE FUNCTION somar_um(integer) RETURNS integer
     AS 'DIRETÓRIO/funcs', 'somar_um'
     LANGUAGE C STRICT;

Perceba que na função SQL somar_um(integer) acima recebemos um integer como parâmetro, exatamente como estamos esperando no nosso código em C. Para cada tipo de dado em nossa SQL existe um tipo de dado relativo em C, que pode ser visto na tabela encontrada em: http://pgdocptbr.sourceforge.net/pg80/xfunc-c.html#XFUNC-C-TYPE-TABLE.

Não vou entrar em detalhes de como criar uma PL em C, até porque a documentação (http://pgdocptbr.sourceforge.net/pg80/xfunc-c.html) é bem completa e esperamos que você a tenha lido pelo menos uma vez para a leitura deste artigo.

De volta à nossa função de envio de e-mails para postgres, criamos nosso código em C, integrando à solução de envio de e-mails já pronta encontrada na Internet, a qual adicionei apenas o suporte para e-mails em HTML, além de texto plano, e é claro, adicionei a funcionalidade para integração com o PostgreSQL. Para facilitar o entendimento, traduzi os comentários dos métodos de envio de e-mail para o português.
O método “sendmail” desenvolvi baseado na documentação do postgres, e traduzi os comentários meus para inglês, para que possa ser distribuído facilmente na Internet.
Antes de utilizar e redistribuir o código abaixo, peço apenas que leia os direitos autorais localizados no próprio código fonte e mantenha sempre os nomes dos autores responsáveis pelo desenvolvimento do mesmo.

Para nossa solução bastou apenas 3 arquivos:

  1. Makefile: contendo as diretivas necessárias para compilação do código fonte;
  2. smtp.h: arquivo contendo as configurações básicas para funcionamento de nosso código em C;
  3. sendmail.c: código da nossa função em C.

Abaixo segue o link para baixar o arquivo contendo o código completo da solução, bem como o arquivo README explicando detalhadamente seu processo de instalação.

Para testar a solução, não esqueça de adicionar o host do seu servidor postgres como Open Relay no seu servidor de e-mail.

Espero que esta solução possa ajudar muita gente e que várias pessoas possam contribuir melhorando o código e adicionando funcionalidades ao mesmo =]

Link para download do programa

cy-a

written by Lucas Freitas \\ tags: , , , , , ,

mai 28

Um Enum (enumeração) é um tipo especial de classe. É basicamente uma lista de constantes enumeradas e está disponível a partir da versão 5 do Java. O Enum foi criado com o intuito de impedir que valores inesperados sejam recebidos em um trecho do seu código, impedindo com isso que erros sejam lançados em tempo de execução.

Imagine, por exemplo, que você tenha um Barco no rio Amazonas, no estado do Amapá, e que este viaje apenas pelos municípios deste estado. Você deverá ter na classe Barco um método que recebe como parâmetro a cidade para a qual o barco deve se deslocar. Como você faria? Bom, você poderia usar como parâmetro um objeto do tipo String, ou talvez um inteiro com o código da cidade. Seu código ficaria parecido com esse:


class Barco {

    public void viajaPara(String cidade) {
        System.out.println("Viajando para " + cidade);
    }

}

O código funcionará perfeitamente, mas você correria o risco de um usuário informar uma cidade inesperada, veja:


public class Exemplo1 {

    public static void main(String[] args) {
        Barco barco = new  Barco();
        barco.viajaPara("Goiânia"); // ao executar, será mostrado na saída: Viajando para Goiânia
    }

}

Sabemos que Goiânia está fora da rota normal do barco e que não deveria ser aceita como parâmetro, pois não é uma cidade do estado do Amapá. Como evitar este problema? Com certeza criar um monte de blocos condicionais com “if” para checar se trata-se de uma cidade do estado do Amapá não seria a melhor das soluções.

Pensando exatamente neste tipo de problema os desenvolvedores do Java criaram o Enum, nos possibilitando escolher um item dentre vários disponíveis em uma lista enumerada.

Veja agora o exemplo anterior utilizando um Enum:


enum CidadesNavegaveis {
    AMAPA, CALCOENE, FERREIRA_GOMES, LARANJAL_DO_JARI, MACAPA, MAZAGAO, OIAPOQUE,
PORTO_GRANDE, SANTANA, SERRA_DO_NAVIO, TARTARUGALZINHO, VITORIA_DO_JARI;
}

class Barco {
    public void viajaPara(CidadesNavegaveis cidade) { // perfeito! Impedimos um valor inesperado em tempo de execução!
        System.out.println("Viajando para " + cidade);
 }

}

public class Exemplo1 {

 public static void main(String[] args) {
 Barco barco = new  Barco();
 barco.viajaPara(CidadesNavegaveis.MACAPA); // recebendo um item dentre os disponíveis
 }

}

Agora sim podemos assegurar de que nosso barco navegará apenas entre as cidades desejadas.

Um Enum pode ser declarado em um arquivo Java separado ou como um membro de uma classe, mas nunca dentro de um método.

Declarando um Enum em um arquivo Java separado

Arquivo CidadesNavegaveis.java:

enum CidadesNavegaveis {
    AMAPA, CALCOENE, FERREIRA_GOMES, LARANJAL_DO_JARI, MACAPA, MAZAGAO, OIAPOQUE,
PORTO_GRANDE, SANTANA, SERRA_DO_NAVIO, TARTARUGALZINHO, VITORIA_DO_JARI;
}

Declarando um Enum como membro de uma classe

Arquivo Barco.java:

class Barco {

    enum CidadesNavegaveis {
        AMAPA, CALCOENE, FERREIRA_GOMES, LARANJAL_DO_JARI, MACAPA, MAZAGAO, OIAPOQUE,
PORTO_GRANDE, SANTANA, SERRA_DO_NAVIO, TARTARUGALZINHO, VITORIA_DO_JARI;
    }

    public void viajaPara(CidadesNavegaveis cidade) {
        System.out.println("Viajando para " + cidade);
    }

}

Cada item enumerado em um Enum é uma instância do próprio Enum. No exemplo acima, cada cidade enumerada (MACAPA, MAZAGAO, OIAPOQUE, etc) é uma instância do tipo CidadesNavegaveis. Confuso, não?!? Para que você entenda melhor, o Enum é algo parecido como isto:

class CidadesNavegaveis {

    public static final CidadesNavegaveis AMAPA = new CidadesNavegaveis("AMAPA", 0);
    public static final CidadesNavegaveis CALCOENE = new CidadesNavegaveis("CALCOENE", 1);
    public static final CidadesNavegaveis FERREIRA_GOMES = new CidadesNavegaveis("FERREIRA_GOMES", 2);
    public static final CidadesNavegaveis LARANJAL_DO_JARI = new CidadesNavegaveis("LARANJAL_DO_JARI", 3);
    public static final CidadesNavegaveis MACAPA = new CidadesNavegaveis("MACAPA", 4);

    // ...

    public CidadesNavegaveis(String nome, int indice) {
        // ...
    }

}

Em um Enum todos os valores enumerados são static e final, portanto são constantes. Os valores são também implicitamente public, e cada valor guarda seu próprio índice, que é definido na ordem em que o item é declarado.

Além de definir constantes enumeradas, no Enum podemos também criar construtores, variáveis de instância, métodos e algo muito estranho chamado “corpo de classe específico da constante”.

Nosso barco agora sabe para quais cidades ele pode se deslocar, mas ainda não é inteligente o bastante para saber aonde fica cada cidade. Vamos ajudar no nosso barco relacionando cada cidade enumerada com sua respectiva coordenada geográfica. Podemos, para isto, utilizar um construtor para passar a coordenada como parâmetro e preencher uma variável de instância, caso precisemos recuperar este valor mais tarde. Nosso Enum ficaria assim:

enum CidadesNavegaveis {

    AMAPA("2.051082,-50.794464"),
    CALCOENE("1.933227,-50.736237"),
    FERREIRA_GOMES("-0.116043,-51.28315"),
    LARANJAL_DO_JARI("0.854155,-51.182556"),
    MACAPA("0.034457,-51.066564"),
    MAZAGAO("2.497911,-50.947037"),
    OIAPOQUE("-0.906334,-51.965332");

    CidadesNavegaveis(String coordenada) {
        this.coordenada = coordenada;
    }

    private String coordenada;

    public String getCoordenada() {
        return coordenada;
    }

}

Perceba que agora cada item enumerado passa como parâmetro uma String contendo a coordenada geográfica para o construtor do Enum, e essa String é armazenada em uma variável de instância. Essa variável poderá ser acessada posteriormente pelo método getCoordenada que criamos. Veja:

class Barco {

    public void viajaPara(CidadesNavegaveis cidade) {
        System.out.println("Viajando para " + cidade);
        System.out.println("Coordenada: " + cidade.getCoordenada()); // Agora nossa classe Barco imprime também a coordenada geográfica da cidade enviada como parâmetro.
    }

}

Não é possível invocar diretamente um construtor de um Enum, ele é acessado automaticamente pelo item enumerado, que enviará os parâmetros necessários, como fizemos no item enumerado MACAPA(“0.034457,-51.066564″) que passa uma String como parâmetro ao construtor. O Enum aceita construtores com mais de um parâmetro e também nos permite sobrecarregar o construtor.

Outro recurso importante em um Enum é a possibilidade de criar um “corpo de classe específico da constante”. Imagine que nosso barco precise saber qual cidade é a capital do estado. Ao invés de criar blocos condicionais com “if” podemos criar um método que retorne true caso a cidade seja capital e false caso não seja. Teremos então um método padrão que retornará sempre false, e para a cidade que é capital iremos sobrecarregar este método para que ele retorne true. Veja:

enum CidadesNavegaveis {

    AMAPA("2.051082,-50.794464"),
    CALCOENE("1.933227,-50.736237"),
    FERREIRA_GOMES("-0.116043,-51.28315"),
    LARANJAL_DO_JARI("0.854155,-51.182556"),
    MACAPA("0.034457,-51.066564") { // corpo de classe específico da constante
        public boolean isCapital() { // método sobrecarregado, para a capital
            return true;
        }
    },
    MAZAGAO("2.497911,-50.947037"),
    OIAPOQUE("-0.906334,-51.965332");

    CidadesNavegaveis(String coordenada) {
        this.coordenada = coordenada;
    }

    private String coordenada;

    public String getCoordenada() {
        return coordenada;
    }

    public boolean isCapital() { // método padrão, para cidades não-capital
        return false;
    }

}

Agora nosso método viajaPara imprimirá true caso a cidade informada como parâmetro seja MACAPA, a capital do Amapá. Veja:

class Barco {

    public void viajaPara(CidadesNavegaveis cidade) {
        System.out.println("Viajando para " + cidade);
        System.out.println("Coordenada: " + cidade.getCoordenada());
        System.out.println("É capital: " + cidade.isCapital());
    }

}

Não é possível estender explicitamente uma classe em um Enum. Ele estende implicitamente a classe java.lang.Enum, e herda desta alguns métodos, como o values() que retorna um Array contendo os itens enumerados definidos pelo programador. Este método nos permite, por exemplo, iterar entre nossos itens enumerados, veja:

public class Exemplo2 {

    public static void main(String[] args) {
        for (CidadesNavegaveis cidade: CidadesNavegaveis.values()) {
            System.out.println(cidade);
        }
    }

}

O código acima imprimirá na tela todas as cidades enumeradas em nosso Enum CidadesNavegaveis.

Como vimos o Enum é um recurso bastante útil em Java, diminuindo o risco de um possível erro em tempo de execução.

cy-a

[Referências]

Mc Graw Hill / Alta Books

    Sun Certified Java Associate Study Guide, 2010.
    Certificação Sun Java Associado - SCJA: Guia de viagem para passar no exame, 2008.
    Certificação Sun para Programador Java 6 Guia de Estudo, 2008.
    Head First Java, 2005.

written by Lucas Freitas \\ tags:

mar 25

Sem dúvida, JSF e EJB 3.0 são os dois melhores recursos do Java EE 5. O EJB3 por ser um poderoso modelo para a lógica de negócio e persistência do lado do servidor, e o JSF por promover um poderoso modelo para a camada de apresentação. Mas Infelizmente a especificação Java EE 5 não fornece uma maneira padrão de integrar estes dois modelos. Para o bem de todos, os desenvolvedores do JSF e EJB 3.0 previram a necessidade da integração destes dois modelos e os deixaram aptos para que um framework externo pudesse fazê-la.

Visando atender justamente à essa necessidade de integração, Gavin King (fundador do projeto Hibernate) criou o Jboss Seam. O Seam é um framework para construir aplicações web ricas com Java. Seam simplifica e extende o Java EE, facilitando o uso de seus componentes web e de negócios e agregando ainda mais recursos e funcionalidades para o mesmo.

O Seam faz uma ponte direta entre os componentes JSF e os componentes EJB3, eliminando a necessidade de utilizar um Javabean comum como fachada e possibilitando utilizar um EJB como managed bean. O Seam também elimina a necessidade de mapeamento do managed-bean no faces-config.xml, ligando diretamente um componente JSF a um componente EJB.

Mas o Seam ainda vai além, ele integra tecnologias como AJAX, JSF, EJB 3.0, JPA e BPM de forma simplificada e poderosa para que você possa construir projetos web complexos de forma ágil e simples.

Algumas vantagens do Seam Framework:

  • AJAX integrado: O SEAM suporta as duas maiores soluções baseadas em AJAX para JSF: RichFaces e ICEfaces
  • Suporte a BPM: Com o SEAM é fácil implementar fluxos de trabalho complexos, colaboração e gerenciamento de tarefas usando o jBPM.
  • Suporte a template com Facelets
  • Modelo de baixo acoplamento com uso de Injeção de Dependência e Bijeção
  • Validação por annotations
  • Segurança com Jboss Rules
  • Gerenciamento de transações com JPA
  • Conceito avançado de conversação
  • Gerenciamento de workspace: Seam possibilita o uso de conversações isoladas e seguras em diferentes abas do browser
  • Envio de e-mail
  • Geração de PDF
  • Indexação com o Hibernate Search e Jboss Cache

O modelo Seam fez tanto sucesso que virou uma especificação, JSR 299, WebBeans. Em um futuro muito próximo se tornará um padrão para o desenvolvimento Java EE. Sem dúvidas, não há motivos para não usá-lo.

cy-a

written by Lucas Freitas \\ tags: , ,

Theme designed by Wordpress Hosting supported by Best Web Hosting.