Olá pessoal. Sempre quando começo um novo projeto que tenho que usar relatórios, eu procuro sempre automatizar o processo de compilação dos mesmos. Para quem não sabe, o NetBeans utiliza o Apache Ant (parecido com o make do C/C++) para executar o build do projeto, ou seja, é o Ant que faz a mágica de compilar os arquivos .java, copiar determinados arquivos para algum diretório, criar o pacote de distribuição e assim por diante. Além do comportamento padrão do Ant para cada tipo de projeto, podemos inserir trechos de código no arquivo de build para que tarefas personalizadas possam ser executadas durante o processo de build.

Sendo assim, hoje vou ensinar como personalizar esse arquivo de build de forma a fazer com que sempre que nosso projeto for executado, sejam compilados os arquivos de código fonte dos relatórios (.jrxml), fazendo com que nosso projeto SEMPRE contenha a versão compilada que corresponde a última versão da definição dos relatórios. Com isso, evitamos ter que ficar compilando manualmente os relatórios a cada vez que alterarmos um arquivo.

Vou usar como base o projeto finalizado na Parte 4 do tutorial sobre relatórios. Clique aqui para fazer o download do projeto. Como nosso projeto é desktop, vou abordar com mais detalhes a personalização do arquivo de build para esse tipo de projeto, mas no final do tutorial eu vou postar o trecho de código para o arquivo de build de um projeto Web. Então vamos lá!

Primeiramente, abra o projeto no NetBeans. Ao abri-lo, verifique que por padrão a aba “Projects” tomará o foco. Ao lado desta aba, existe a aba “Files”. Nessa aba é mostrada a estrutura real do projeto, ou seja, a estrutura de diretórios e arquivos que ficam armazenada no seu computador, enquanto na aba “Projects” é mostrada uma estrutura abstrata do projeto que esconde os detalhes da estrutura real. Veja a Figura abaixo.

Figura 1

Estrutura real do projeto

Note que destaquei dois arquivos na estrutura. O arquivo build-impl.xml é gerado automaticamente pela IDE, então mesmo que você o altere ela vai regerá-lo sempre. Sendo assim, nunca mexa nesse arquivo. Use-o para ver como o início do processo de build padrão funciona. O outro arquivo destacado, o build.xml, é o arquivo que podemos alterar para inserir nossas tarefas de build personalizadas. Durante o processo de build, o Ant copia os targets configurados no build-impl.xml para o build.xml, para então executar o arquivo de build.

Recomendo que vocês leiam todos os comentários que são criados dentro do build.xml. Neles vocês terão uma ideia de como o processo funciona. Notem que logo no início, são listados vários targets que podemos personalizar: -pre-init, -post-init, -pre-compile, etc. O nome de cada target é auto-explicativo, além é claro de ter o comentário explicando quanto eles são executados. Falei dos targets várias vezes, mas ainda não expliquei o que eles são. Um target é como se fosse um “passo” no processo de build. Você pode ter um ou vários passos durante o processo de build e cada passo pode depender de um ou vários passos que foram executados anteriormente. Por exemplo, um target que faz o empacotamento do projeto em um .jar, depende do target que faz a compilação dos arquivos .java.

No nosso arquivo de build, nós vamos inserir tarefas dentro do target “-post-compile”, ou seja, o target que é executado depois que os arquivos .java do projeto são compilados. Segue o código do build.xml comentado.

build.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- Documentação (omitida) -->
<project name="TutorialRelatorios" default="default" basedir=".">
    <description>Builds, tests, and runs the project TutorialRelatorios.</description>
    <import file="nbproject/build-impl.xml"/>
    <!--

        Documentação (omitida)

    -->

    <!-- configurando o target -post-compile, que é executado depois
         da compilação dos arquivos .java do projeto-->
    <target name="-post-compile">

        <!-- Compilação das definições dos relatórios -->
        <!-- a tarefa "echo" do Ant mostra uma mensagem na saída -->
        <echo>Iniciando compilação das definições de relatórios...</echo>

        <!-- Define o classpath usado para a compilação dos relatórios -->

        <!-- A tarefa "path" do Ant define um caminho com id de "jrc.classpath"
             que indica um conjunto de arquivos (fileset) que correspondem
             a todos os .jars (que serão usados na compilação) localizados no
             diretório ${build.dir}/../lib/JasperReports-3.7.5.

             Quando o build for executado, a propriedade ${build.dir} será
             substituida por C:\<caminho>\TutorialRelatorios\build,
             sendo assim estamos acessando o diretório
             C:\<caminho>\TutorialRelatorios\lib\JasperReports-3.7.5, que no nosso
             projeto armazena todos os .jars utilizados pelo JasperReports.

             Para entender o que está acontecendo, sempre verifique a estrutura
             do projeto (na aba File). -->
        <path id="jrc.classpath">
            <fileset dir="${build.dir}/../lib/JasperReports-3.7.5"
                     includes="*.jar"/>
        </path>

        <!-- Definimos então uma tarefa customizada do Ant, chamada "jrc",
             que é implementada na classe net.sf.jasperreports.ant.JRAntCompileTask,
             que por sua vez é usada para compilar arquivos .jrxml

             Note que é necessário configurar o classpath para o Ant
             saber onde a classe está definida, além das possíveis dependências
             que ela utiliza. O classpath vem da tarefa "path" que configuramos
             anteriormente, ou seja, todos os .jars do diretório
             C:\<caminho>\TutorialRelatorios\lib\JasperReports-3.7.5 -->
        <taskdef name="jrc"
                 classname="net.sf.jasperreports.ant.JRAntCompileTask">
            <classpath refid="jrc.classpath"/>
        </taskdef>

        <!-- Quando testamos nossos relatórios, eles são compilados, gerando
             arquivos .jasper. O problema é as vezes nós alteramos o arquivo fonte
             e esquecemos de compilar. Sendo assim, caso existam definições de
             relatórios compiladas (que podem corresponder à versões antigas dos .jrxml's),
             a tarefa "delete" do Ant (definida abaixo) apaga todos os arquivos .jasper do diretório
             ${build.classes.dir} (C:\<caminho>\TutorialRelatorios\build\classes), ou seja,
             onde os arquivos .jasper são copiados durante o processo de build normal.
             -->
        <delete>
            <fileset dir="${build.classes.dir}" includes="*.jasper"/>
        </delete>

        <!-- Por fim, compilamos as definições de relatórios (.jrxmls contidos no diretório
             "relatorios") do nosso projeto, sendo que os arquivos compilados (.jasper)
             são gerados no diretório ${build.classes.dir}, ou seja, em
             C:\<caminho>\TutorialRelatorios\build\classes. Note que usamos a tarefa "jrc" que definimos
             acima e precisamos passar novamente o classpath definido na tarefa "path". -->
        <jrc srcdir="relatorios"
             destdir="${build.classes.dir}">
            <classpath
                refid="jrc.classpath"/>
            <include
                name="*.jrxml"/>
        </jrc>

        <!-- Legal, terminou o processo, definições compiladas -->
        <echo>Compilação das definições de relatórios finalizada!</echo>

    </target>

</project>

Sendo assim, copie o target listado acima para dentro do seu build.xml e salve o arquivo. Dê um “Clean and Build” no projeto (volte para a aba “Projects”, botão direito no projeto, “Clean and Build”), ou então clique no botão com um martelo e uma vassoura na barra de tarefas. Se tudo deu certo, a saída do NetBeans vai ser essa aqui:

init:
deps-clean:
Updating property file: C:\<caminho>\TutorialRelatorios\build\built-clean.properties
Deleting directory C:\<caminho>\TutorialRelatorios\build
clean:
init:
deps-jar:
Created dir: C:\<caminho>\TutorialRelatorios\build
Updating property file: C:\<caminho>\TutorialRelatorios\build\built-jar.properties
Created dir: C:\<caminho>\TutorialRelatorios\build\classes
Created dir: C:\<caminho>\TutorialRelatorios\build\empty
Compiling 4 source files to C:\<caminho>\TutorialRelatorios\build\classes
Copying 5 files to C:\<caminho>\TutorialRelatorios\build\classes
Iniciando compilação das definições de relatórios...
Compiling 5 report design files.
log4j:WARN No appenders could be found for logger (net.sf.jasperreports.engine.xml.JRXmlDigesterFactory).
log4j:WARN Please initialize the log4j system properly.
File : C:\<caminho>\TutorialRelatorios\relatorios\ClientesPorNome.jrxml ... OK.
File : C:\<caminho>\TutorialRelatorios\relatorios\ClientesCollectionDS.jrxml ... OK.
File : C:\<caminho>\TutorialRelatorios\relatorios\LocacoesPorClientes_Locacoes.jrxml ... OK.
File : C:\<caminho>\TutorialRelatorios\relatorios\LocacoesPorClientes.jrxml ... OK.
File : C:\<caminho>\TutorialRelatorios\relatorios\Clientes.jrxml ... OK.
Compilação das definições de relatórios finalizada!
compile:
Created dir: C:\<caminho>\TutorialRelatorios\dist
Copy libraries to C:\<caminho>\TutorialRelatorios\dist\lib.
Building jar: C:\<caminho>\TutorialRelatorios\dist\TutorialRelatorios.jar
To run this application from the command line without Ant, try:
java -jar "C:\<caminho>\TutorialRelatorios\dist\TutorialRelatorios.jar"
jar:
BUILD SUCCESSFUL (total time: 7 seconds)

Ou seja, ao executar o build no projeto, os arquivos .java são compilados e então cada arquivo .jrxml é compilado, gerando um .jasper em “C:\<caminho>\TutorialRelatorios\build\classes”, que no caso é a raiz do pacote do nosso projeto. Note que desta forma, sempre teremos os arquivos .jasper que correspondem às ultimas versões das definições dos relatórios. A seguir está listado o target que faz o mesmo processo para o nosso projeto Web feito na Parte 5 do tutorial. Caso queira, clique aqui para fazer o download do projeto.

build.xml (projeto Web)

<target name="-pre-dist">

    <!-- Compilação das definições dos relatórios -->
    <echo>Iniciando compilação das definições de relatórios...</echo>

    <!-- Define o classpath usado para a compilação dos relatórios -->
    <path id="jrc.classpath">
        <fileset dir="${build.classes.dir}/../lib"
                 includes="*.jar"/>
    </path>

    <!-- Define a tarefa customizada do Ant que compila
         as definições dos relatórios-->
    <taskdef name="jrc"
             classname="net.sf.jasperreports.ant.JRAntCompileTask">
        <classpath refid="jrc.classpath"/>
    </taskdef>

    <!-- Compila as definições .jrxml ==> .jasper -->
    <jrc srcdir="relatorios"
         destdir="${build.classes.dir}">
        <classpath
            refid="jrc.classpath"/>
        <include
            name="*.jrxml"/>
    </jrc>

    <echo>Compilação das definições de relatórios finalizada!</echo>

</target>

Note que o target listado acima difere um pouco do primeiro que listei (tipo do target e parte do classpath). Como exercício, tente entender porque o código é diferente e se ele pode ficar igual ou mais parecido ao primeiro target que foi mostrado. Faça mudanças no arquivo para poder entender melhor o que acontece. Os scripts que mostrei são apenas uma sugestão. Se você quiser inserir outras tarefas do Ant no build do seu projeto, dê uma olhada no manual: http://ant.apache.org/manual/index.html. Outro detalhe é que vocês conseguirão adaptar esse script para qualquer projeto, mesmo que a estrutura dele seja diferente dos projetos que criamos no tutorial.

Então é isso pessoal, espero que tenham gostado. No próximo tutorial vamos aprender os primeiros passos para trabalhar com a biblioteca JavaScript jQuery. Abraço!