Maven - Resources Dinâmicos
Tags: java, maven, build, resources
Published: 2021-04-26 16:59:06

Nossos projetos em Java geralmente possuem vários arquivos de configuração do projeto e do ambiente de execução, como por exemplo a configuração do JPA (persistence.xml), customização de mensagens do JSF ou configuração do JSF (faces-config.xml).

Esses arquivos são os recursos do nosso projeto e geralmente ficam na pasta `main/resources` ou `test/resources`. Normalmente temos uma variação do arquivo para cada ambiente que são, ou não, mantidos juntos ao nosso código fonte no repositório (grande falha de segurança pois estamos deixando dados de acesso ao ambiente de produção à vista) ou mesmo são copiados ou alterados manualmente após o build :s.

O Maven possui um plugin chamado Resources que é responsável pela cópia dos resources do nosso projeto. Por padrão, o plugin apenas copia os arquivos da nossa pasta src (main ou de test) para a pasta de build do projeto (target). No entanto, o plugin Resources consegue fazer uso de outro plugin do Maven para efetuar um processamento do arquivo, permitindo assim deixarmos algumas partes dele dinâmicas.

Esse plugin é o Maven Filtering, ele nos permite definir nos arquivos de recursos varáveis que possam ser substituídas no momento do build do nosso projeto. Por exemplo, no nosso arquivo de configuração do JPA poderíamos utilizar uma variável que contém o nome do Data Source que iremos utilizar, e para cada ambiente podemos subsituir essa variável com o valor adequado. Isso é interessante caso você tenha um pipeline em um CI (Continuous Integration), pois nele você pode definir o nome do Data Source de Teste através do script de build de teste.

Abaixo segue um exemplo do persistence.xml que contém uma variável datasource.name que será utilizada dinamicamente de acordo com o script de build.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="EffectiveJavaEE" transaction-type="JTA">
    <jta-data-source>${datasource.name}</jta-data-source>
    <properties>
      <property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />
    </properties>
  </persistence-unit>
</persistence>
```

Como pode ver, uma variável é definida entre `${}`, assim como as Expression Language do JSP.

Para ativar o Filtering durante o build, precisamos adicionar no nosso POM.xml a seção build abaixo.

```xml
<build>
  <resources>
    <resource>
      <directory>src/main/resources/META-INF</directory>
      <filtering>true</filtering>
    </resource>
  </resources>
</build>
```

Dentro de resources, podemos definir um arquivo ou uma pasta com arquivos que serão processadas e também ativamos o Filtering através da tag filtering.

Os valores dessas variáveis podem ser definida de várias formas:

Arquivos properties no formato: `<variável>=<valor>`
Valores definidos na seção `<build>/<filters>` do nosso POM.xml
Propriedades definidas nas seções `<properties>` do nosso POM.xml
Propriedades passadas na execução do Maven (flag -D) no formato `<variável>=<valor>`
Abaixo segue um exemplo de um script que faz o build do nosso projeto passando um Data Source (poderia ser colocado no pipeline do nosso Jenkins).

mvn clean install `-Ddatasource.name=java:/ds/BancoDeTestes`
Em negrito, segue a nossa variável definida no nosso persistence.xml que após o build terá o seguinte resultado:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
 <persistence-unit name="EffectiveJavaEE" transaction-type="JTA">
   <jta-data-source>java:/ds/BancoDeTestes</jta-data-source>
   <properties>
     <property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />
   </properties>
 </persistence-unit>
</persistence>
```

Com isso, podemos ver o quão poderoso o Maven pode ser e o quanto ele pode facilitar nossa vida. Ao invés de precisarmos sempre ter que editar o build gerado ou ter vários arquivos, um para cada ambiente, podemos simplesmente passar como argumento no build ou um arquivo com nossos valores.

Alguns exemplos plausíveis de uso seria no buid do projeto onde poderíamos setar dinâmicamente o IP ou nome do nosso container Docker que contém nosso banco de dados para testes, poderíamos setar o IP no arquivo standalone.xml do nosso Wildfly ou mesmo no script que adiciona nosso datasource nele.