Migrando para o Maven
1 Comentários Publicado por Guilherme em segunda-feira, outubro 23, 2006 at 1:25 PM.
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:
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:
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:
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...).Gerenciamento do projeto Gerencimento de dependências
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:
Se você está cansado do ANT e está procurando uma boa ferramenta para controlar o seu projeto, o Maven é uma mão na roda!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
Quem tem medo das exceções
0 Comentários Publicado por Guilherme em segunda-feira, outubro 16, 2006 at 6:42 PM.
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
Unchecked exceptions
Error
Para indicar as exceções que um método pode lançar, utilizamos a palavra-chave throws:Para informar a JVM qual código executar quando uma determinada exceção ocorrer, utilizamos as palavras-chave try e catch:Dicas: As checked exceptions forçam o desenolvedor a manipular os possíveis erros, então nunca faça isso:Dessa forma você está omitindo a exceção e nem mesmo poderá ver a pilha de erros.
Nunca faça:ouDessa forma você não conseguirá rastrear onde está a possível causa do erro. Sempre utilize o método printStackTrace() da classe Throwable: Ao utilizar o método printStackTrace(), preservamos a pilha de erros e tornamos mais fácil encontrar o local que originou o erro.
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çõesPara indicar as exceções que um método pode lançar, utilizamos a palavra-chave throws:
public void foo() throws MinhaException {
//
}
try {
// bloco onde podem ocorrer exceções
} catch (MinhaException exception) {
// tratar exceção
}
public void foo() {
try {
// algum código que possa lancar uma exceção
} catch (Exception exception) {
}
}
Nunca faça:
try {
// algum código que possa lancar uma exceção
} catch (Exception exception) {
System.out.println(exception);
}
try {
// algum código que possa lancar uma exceção
} catch (Exception exception) {
System.out.println(exception.getMessage());
}
try {
// algum código que possa lancar uma exceção
} catch (Exception exception) {
exception.printStackTrace();
}
Upload com WebWork
5 Comentários Publicado por Guilherme em terça-feira, outubro 10, 2006 at 8:09 AM.
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 actionNa 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
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
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:E para utilizar esse método na action:Não se esqueça de colocar o jar do Commons FileUpload no classpath !
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;
}
}
}
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,<ww:file name="upload"/>
<ww:submit>
</ww:form>
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.<interceptor-ref name="fileUpload"/>
<interceptor-ref name="basicStack"/>
<result name="success">success_upload.jsp</result>
<result name="input">input_upload.jsp</result>
</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();
}
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();
}
}
java.lang.OutOfMemoryError: PermGen space
7 Comentários Publicado por Guilherme em sábado, outubro 07, 2006 at 3:33 PM.
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:
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
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.TOMCAT_HOME\bin> catalina start
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
0 Comentários Publicado por Guilherme em terça-feira, outubro 03, 2006 at 12:16 PM.

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