BlogNotFoundException

Java, Linux, Open Source, etc...


Migrando para o Maven

O Maven é um poderoso framework para gerênciamento de projetos que fornece aos desenvolvedores os seguintes benefícios: Coerência, Reusabilidade, Agilidade e Manutenabilidade.

O Maven segue alguns princípios:

Convenção sobre configuração
Execução declarativa
Reuso da lógica de build
Organização de dependências coerente

Ao fornecer uma estrutura e um processo de desenvolvimento bem definidos, o Maven acaba tornando a vida dos desenvolvedores mais simples.

Maven x Ant

É quase inevitável a comparação entre as duas ferramentas. Na minha opinião o ANT deixa a desejar quando se trata de:
  • Gerenciamento do projeto
  • Gerencimento de dependências
  • Já o Maven segue o conceito de POM (Project Object Model), onde todos os artefatos gerados pelo projeto podem ser configurados. Ou seja, em poucas linha de descrição do projeto podemos realizar algumas tarefas padrão (compilação, empacotamento, rodar testes unitários, etc...).

    Sem falar que é bem mais fácil gerar relatórios (Emma, JDepend, JavaDoc, etc...) com o Maven, pois todos os relatórios são "agrupados" no site padrão que pode ser gerado pelo Maven.

    Muitos desenvolvedores tem problemas em migrar para o Maven por se sentirem obrigados a utilizar a estrutura de diretórios proposta pelo Maven. Mas poucos sabem que é possível utilizar o Maven em uma aplicação já existente e usufruir de todos os benefícios que essa excelente ferramenta oferece.

    Instalando o Maven
    O Maven pode ser baixado no seguinte link: http://maven.apache.org/download.html. O processo de instalação é bem simples: descompacte o arquivo ZIP em um diretório de sua preferência e coloque o caminho para a pasta bin (por exemplo: C:/Maven/bin) no PATH do seu sistema operacional:

    Entre no Painel de Controle > Desempenho e Manutenção > Sistema clique na aba Avançado, clique no botão Variáveis de Ambiente, selecione a variável PATH, adicione uma ";" e o caminho para a pasta bin da instalação do Maven. Não se esqueça que você deve ter a variável JAVA_HOME apontando para o diretório de instalação do Java.

    Para testar se a instalação foi realiza corretamente, rode o seguinte comando no console: mvn --version

    Plugins
    Geralmente utilizamos um plugin para auxiliar o desenvolvimento JEE, vamos tomar como exemplo o plugin Sysdeo. Esse plugin cria um projeto web no TomCat contendo a seguinte estrutura de diretórios:

    Projeto
    |
    +-- WEB-INF
    +---- src
    +---- classes
    +---- lib

    Parar informar ao Maven o diretório onde se encontram os arquivos .java utilize a tag sourceDirectory

    <build>
       ...
       <sourceDirectory>WEB-INF/src</sourceDirectory>
       ...
    <build>

    E para informar o diretório onde os arquivos .class devem ser armazenados:

    <build>
       ...
       <outputDirectory>WEB-INF/classes</outputDirectory>
       ...
    <build>

    Podemos também informar ao Maven onde encontrar e armazenar os testes unitarios através das tags:

    <build>
       ...
       <testSourceDirectory>WEB-INF/test/src</testSourceDirectory>
       ...
    <build>

    <build>
       ...
       <testOutputDirectory>WEB-INF/test/classes</testOutputDirectory>
       ...
    <build>

    O Maven possui diversos plugins que são responsáveis por gerar artefatos baseados no projeto. A seguir uma lista com os principais plugins:
  • compiler:compile - Compila os .java
  • compiler:testCompile - Compila os testes unitários
  • site: - gera um site para o projeto corrente
  • war:war - Cria um arquivo WAR a partir do projeto corrente
  • jar:jar - Cria um arquivo JAR a partir do projeto corrente
  • pmd:pmd - Gera um relatório do PMD
  • Se você está cansado do ANT e está procurando uma boa ferramenta para controlar o seu projeto, o Maven é uma mão na roda!

    Quem tem medo das exceções

    Muitas pessoas que esão inciando em Java tem uma certa dificuldade em entender bem as exceções. É fundamental que todo programador tenha uma boa noção sobre declaração, criação e tratamento de exceções para não sejam produzidos mais e mais códigos sem um bom tratamento de erros.

    Mas afinal o que é uma exceção ? uma exceção é um evento que ocorre durante a execução de um programa quando algum tipo de problema ocorre.

    Já que estamos falando de Java, e tudo que não for um tipo primitivo deve ser um objeto (pelo menos...), as exceções não fogem a essa regra. As exceções são intâncias da classe java.lang.Exception que por sua vez é subclasse de java.lang.Throwable

    A classe Throwable é a superclasse de todos os erros e exceções do Java. Ela possui duas subclasses:

    Error - Representa situações incomuns que não não causadas por erros no programa.
    Exception - Representa situações razoáveis que a aplicação deve tratar.

    A figura abaixo mostra a hierarquia das exceções.



    Os três tipos de exceções

    Checked exceptions
    As checked exceptions são subclasses de Exception e representam condições inválidas (dados errados, problemas com banco de dados, problemas com a rede, etc...).
    Se um método lançar uma checked exception deve manipulá-lo ou declará-lo.

    Unchecked exceptions
    As unchecked exceptions são subclasses de RuntimeException e representam erros de programação.
    Se um método lançar uma unchecked exception não será necessário manipulá-la ou declará-la.

    Error
    Um Error representa condições excepicionais externas a aplicação que geralmente não podem ser recuperados. Por exemplo, suponha que uma aplicação precisa abrir alguns arquivos e recuperar informações, mas por algum mal funcionamento do sistema não consiga. Esse mal funcionamento irá causar um java.io.IOError.
    Declarando e Manipulando exceções

    Para indicar as exceções que um método pode lançar, utilizamos a palavra-chave throws:
    public void foo() throws MinhaException {
    //
    }
    Para informar a JVM qual código executar quando uma determinada exceção ocorrer, utilizamos as palavras-chave try e catch:
    try {
    // bloco onde podem ocorrer exceções
    } catch (MinhaException exception) {
    // tratar exceção
    }
    Dicas: As checked exceptions forçam o desenolvedor a manipular os possíveis erros, então nunca faça isso:
    public void foo() {
    try {
    // algum código que possa lancar uma exceção
    } catch (Exception exception) {

    }
    }
    Dessa forma você está omitindo a exceção e nem mesmo poderá ver a pilha de erros.

    Nunca faça:
    try {
    // algum código que possa lancar uma exceção
    } catch (Exception exception) {
    System.out.println(exception);
    }
    ou
    try {
    // algum código que possa lancar uma exceção
    } catch (Exception exception) {
    System.out.println(exception.getMessage());
    }
    Dessa forma você não conseguirá rastrear onde está a possível causa do erro. Sempre utilize o método printStackTrace() da classe Throwable:
    try {
    // algum código que possa lancar uma exceção
    } catch (Exception exception) {
    exception.printStackTrace();
    }
    Ao utilizar o método printStackTrace(), preservamos a pilha de erros e tornamos mais fácil encontrar o local que originou o erro.

    Upload com WebWork

    Tenho visto muita gente com dificuldade em criar um upload no WebWork. Nesse post demonstrarei como é bastante simples criar um upload utilizando o suporte ao Commons FileUpload do WebWork.

    Primeiro passo: criar a action
    public class UploadAction extends ActionSupport {

    private File file;
    private String contentType;
    private String filename;

    public void setUpload(File file) {
    this.file = file;
    }
    public void setUploadContentType(String contentType) {
    this.contentType = contentType;
    }
    public void setUploadFileName(String filename) {
    this.filename = filename;
    }

    public String execute() throws Exception {
    if (file == null) {
    return INPUT;
    }
    }

    }
    Na action precisamos apenas criar os seguintes atributos: file, contentType e fileName para que o WebWork identifique que será realizado o upload.

    Segundo passo: configurar o arquivo webwork.properties

    webwork.multipart.parser=jakarta
    webwork.multipart.saveDir=C:/uploads/

    Ao configurar o parser como jakarta, definimos que o upload será feito através do Commons FileUpload .

    Terceiro passo: criar o formulário de upload
    <ww:form  method="POST" action="upload.action" enctype="multipart/form-data">
       <ww:file name="upload"/>
       <ww:submit>
    </ww:form>
    Para construir o formulário, utilizamos a tag <ww:form>. Para gerar o campo de upload,
     utilizamos a tag <ww:file> e para submeter o formulário, utilizamos a tag <ww:submit>.

    Quarto passo: configurar a action no arquivo xwork.xml
    <action name="upload" class="br.com.action.UploadAction">
         <interceptor-ref name="fileUpload"/>
         <interceptor-ref name="basicStack"/>
         <result name="success">success_upload.jsp</result>
         <result name="input">input_upload.jsp</result>
    </action>
    Para configurarmos o upload, basta referenciar o interceptor fileUpload na declaração da action.

    A partir dessa configuração poderíamos realizar o upload sem grandes problemas, só que o interceptor fileUpload realiza uma limpeza nos arquivos e por consequência todos os arquivos que sofreram upload serão excluídos. Para contornar isso, podemos copiar o upload para um diretório específico.

    Retire a seguinte linha do arquivo webwork.properties:

    webwork.multipart.saveDir=C:/uploads/

    E crie o seguinte método que é responsável por copiar o arquivo para um diretório:
    public void copyFile(File in, File out) throws IOException {
    FileChannel sourceChannel = new FileInputStream(in).getChannel();
    FileChannel destinationChannel = new FileOutputStream(out).getChannel();
    sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel);
    sourceChannel.close();
    destinationChannel.close();
    }
    E para utilizar esse método na action:
    public class UploadAction extends ActionSupport {

    private File file;
    private String contentType;
    private String filename;

    public void setUpload(File file) {
    this.file = file;
    }
    public void setUploadContentType(String contentType) {
    this.contentType = contentType;
    }
    public void setUploadFileName(String filename) {
    this.filename = filename;
    }

    public String execute() throws Exception {
    if (file == null) {
    return INPUT;
    }
    copyFile(file, new File("C:/uploads/" + filename));
    return SUCCESS;
    }

    public static void copyFile(File in, File out) throws IOException {
    FileChannel sourceChannel = new FileInputStream(in).getChannel();
    FileChannel destinationChannel = new FileOutputStream(out).getChannel();
    sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel);
    sourceChannel.close();
    destinationChannel.close();
    }

    }
    Não se esqueça de colocar o jar do Commons FileUpload no classpath !

    java.lang.OutOfMemoryError: PermGen space

    Continuo em busca de uma solução para esse memory leak. Memory leak em java pode ser causado por um objeto que não é coletado depois que não é mais necessário ou não está mais ativo. Com isso, a performance do computador é prejudicada, pois há uma redução na quantidade de memória disponível.

    Ao ler os posts atualizados do Bloglines me deparei com o seguinte post: debugging PermGen OutOfMemoryError problems in windows

    Nesse post o autor Rich Unger dá dicas de como debugar esse tipo de bug que é tão difícil de reproduzir. No post, o autor faz referência ao seguinte post do autor Gregg Sporar, que define os diferentes tipos de memory leaks que podem ocorrem em aplicações Java.

    http://weblogs.java.net/blog/gsporar/archive/2006/09/javazone_sessio.html

    Entre os três tipos, o que mais me interessa no momento é o: Repeatedly deploying my application to Tomcat causes it to run out of perm gen space - is there a problem with perm gen usage in Tomcat.

    Parece que o TomCat possui esses problemas de perm gen mesmo, inclusive existe um cadastro de bug no bugzilla do TomCat 5: http://issues.apache.org/bugzilla/show_bug.cgi?id=33711

    Para saber melhor onde pode estar ocorrendo o vazamento de memória, o autor indica a utilização do JConsole. O JConsole é uma ferramenta que utiliza instrumentação JMX para prover informações sobre performance e consumo de recursos de aplicações que rodam na plataforma Java.

    Iniciando o JConsole
    O JConsole pode ser encontrado em JAVA_HOME/bin, onde JAVA_HOME é o diretório onde o JDK foi instalado. O JConsole pode ser utilizado tanto para monitoramento de aplicações locais quanto aplicações remotas.

    Monitoramento e Gerenciamento Local
    Para habilitar o acesso local ao JMX, precisamos criar a seguinte propriedade quanto iniciarmos a JMV ou aplicação Java:
    com.sun.management.jmxremote
    Por exemplo, para utilizarmos o JConsole com o TomCat devemos executar os seguintes comandos na linha de comando:
    TOMCAT_HOME\bin> set JAVA_OPTS=-Dcom.sun.management.jmxremote
    TOMCAT_HOME\bin> catalina start
    Após executar os comandos acima, inicie o JConsole e note que há uma configuração na aba Local apontando para a classe: org.apache.catalina.startup.BootStrap. Isso indica que o JConsole já pode monitorar o TomCat. Em seguida cliquem em Connect.

    A Interface do JConsole
    A interface do JConsole é composta por seis abas:

    * Summary tab: exibe informações sobre a JVM e valores monitorados.
    * Memory tab: exibe informações sobre o uso de memória.
    * Threads tab: exibe informações sobre o uso de threads.
    * Classes tab: exibe informações sobre o carregamento das classes.
    * MBeans tab: exibe informações sobre MBeans.
    * VM tab: exibe informações sobre a JVM.



    Na aba Memory, podemos encontrar informações sobre o consumo e pools de memória:



    Na aba Classes, podemos encontrar informações sobre o carregamento das classes, incluindo o total de classes carregadas, total de classes não carregadas, etc...



    Até agora encontrei as seguintes possíveis soluções para esse problema:

    * Utilizar a flag -XX:MaxPermSize para aumentar o tamanho de memória disponível (o default é 64M)

    * Migrar para outro WebContainer (Jetty ou Resin)

    * Mudar de implemetação de JDK, utilizar por exemplo a JRockit (Algumas pessoas dizem que após a mudança, esse problema não persiste)

    Fontes:
    http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html
    http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html
    http://java.sun.com/j2se/1.5.0/docs/guide/management/jconsole.html

    Spring 2.0 Final Released

    Foi lançada a versão 2.0 do Spring Framework. Essa versão é lançada após nove meses de desenvolvimento ativo. Segundo os desenvolvedores do Spring, essa versão é a mais simples e poderosa.


    ChangeLog
    Documentação
    Download
    Novidades da versão 2.0