Sharing configuration files from a Maven Parent Project

Okay this post is probably not much news for people who know Maven in and out. I am planning to use this as a reference for myself, in the case that I have to solve a similar problem again in the future. The current project I am working with, is set up as a Maven multi module project. There is a parent pom which is set to pom-packaging. There are several child modules, set to either jar- or war-packaging. Within the pom.xml file of the parent project, we use the pluginManagement section to define plugins that should be available to the child modules. The pluginManagement mechanism is an excellent way to avoid the DRY problem and not to duplicate Maven configuration within the inheriting projects.

In most cases configuring plugins within the pluginManagement section is straight forward. It can however get a bit problematic if the plugin depends on (or is reading from external) configuration files. Lets have a look at one example from this parent project of ours.


<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.package</groupId>
<artifactId>project-parent</artifactId>
<packaging>pom</packaging>
<version>0.1-SNAPSHOT</version>

<modules>
<module>child-a</module>
<module>child-b</module>
<module>child-c</module>
</modules>

<properties>
<version.mysql.connector>5.1.12</version.mysql.connector>
</properties>

<build>

<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sql-maven-plugin</artifactId>
<version>1.4</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${version.mysql.connector}</version>
</dependency>
</dependencies>
<configuration>
<driver>com.mysql.jdbc.Driver</driver>
<url>jdbc:mysql://localhost/</url>
<username>xyz</username>
<password>xyz</password>
</configuration>

<executions>
<execution>
<id>drop-and-recreate-db</id>
<phase>process-test-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<autocommit>true</autocommit>
<srcFiles>
<srcFile>
${project.build.directory}/sql/schema/user.sql
</srcFile>
<srcFile>
${project.build.directory}/sql/schema/core.sql
</srcFile>
<srcFile>
${project.build.directory}/sql/schema/game.sql
</srcFile>
</srcFiles>
<onError>abort</onError>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>

</build>
</project>


Here we use the sql-maven-plugin to setup the database before tests are being run. The sql-maven-plugin will execute a bunch of *.sql files which are stored in a subfolder in the parent project. As you deploy the parent project to your repository, these files won't be published along with the pom.xml as the packaging is set to pom-packaging. Therefore, if you run the inherited sql-maven-plugin the *.sql files will not be available and the plugin will fail. This will certainly be a problem if your continuous integration server has a build plan for each Maven child module and not a single build plan for the entire project.

To overcome this problem, there are 2 things you have to do. First, the parent project needs to publish the *.sql files (or other static files which are needed) to your repository, so that the inheriting modules have access to these files. For this to work, we use the maven-assembly-plugin like this:


<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

... as before ...

<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<inherited>false</inherited>
<configuration>
<descriptors>
<descriptor>
${project.basedir}/assembly/zip.xml
</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>

<pluginManagement>
... as before ...
</pluginManagement>

</build>
</project>


Note that the maven-assembly-plugin in this case is not configured within the pluginManagement section of the parent pom, as we don't want to make this functionality available to child modules. In the configuration you can see that the plugin is set up to be executed during the package phase and that the plugin configuration is defined in the zip.xml file. This zip.xml file looks like this:


<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>sql-files</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}/sql/schema</directory>
<outputDirectory/>
<includes>
<include>**/*</include>
</includes>
</fileSet>
</fileSets>
</assembly>


This configuration will create a zip-file of all *.sql files found in ${project.basedir}/sql/schema and publish this zip-file along with the pom.xml when mvn deploy is executed. The id of this configuration is "sql-files". This id will be used as a suffix and become part of the filename of the zip-file.

Now that we publish the zip-file to the repository, we need a way for the child modules to grab and extract the zip-file before the maven-sql-plugin is executed. This is where the maven-dependency-plugin comes in handy. Again, the maven-dependency-plugin is configured in the pluginManagement section of the parent pom.xml, as this time we want to inherit the functionality to child modules. Here is what the configuration of the maven-dependency-plugin looks like:


<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

... as before ...

<build>
<plugins>
... as before ...
</plugins>

<pluginManagement>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>unpack-sql-files</id>
<phase>process-test-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.package</groupId>
<artifactId>project-parent</artifactId>
<version>
${parent.version}
</version>
<type>zip</type>
<classifier>sql-files</classifier>
<overWrite>true</overWrite>
<outputDirectory>
${project.build.directory}/sql/schema
</outputDirectory>
<includes>**/*.sql</includes>
</artifactItem>
</artifactItems>
<includes>**/*</includes>
<overWriteReleases>true</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</execution>
</executions>
</plugin>

... as before ...

</pluginManagement>

</build>
</project>


The plugin (if a child module decides to use this) will be executed during the process-test-resources phase of the build. We are getting the zip file by specifying the groupId, artifactId, version and the type. Also the classifier value must match the id which we used earlier in the zip.xml file for configuring the maven-assembly-plugin. The zip-file is extracted to ${project.build.directory}/sql/schema and we are only extracting files having the *.sql extension (well there shouldn't be any other files but ok). This concludes what needs to be done to extract the zip-file and child modules are now ready to use the extracted files. Here is a snippet from a pom.xml file in a Maven child module. This is everything needed to run the sql-maven-plugin defined in the parent pom and extract the required configuration files upfront.


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.package</groupId>
<artifactId>project-parent</artifactId>
<version>0.1-SNAPSHOT</version>
</parent>

<artifactId>child-a</artifactId>
<packaging>war</packaging>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sql-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>


For the sake of completeness, once again the full parent pom.xml file.


<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.package</groupId>
<artifactId>project-parent</artifactId>
<packaging>pom</packaging>
<version>0.1-SNAPSHOT</version>

<modules>
<module>child-a</module>
<module>child-b</module>
<module>child-c</module>
</modules>

<properties>
<version.mysql.connector>5.1.12</version.mysql.connector>
</properties>

<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<inherited>false</inherited>
<configuration>
<descriptors>
<descriptor>
${project.basedir}/assembly/zip.xml
</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>

<pluginManagement>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>unpack-sql-files</id>
<phase>process-test-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.package</groupId>
<artifactId>project-parent</artifactId>
<version>
${parent.version}
</version>
<type>zip</type>
<classifier>sql-files</classifier>
<overWrite>true</overWrite>
<outputDirectory>
${project.build.directory}/sql/schema
</outputDirectory>
<includes>**/*.sql</includes>
</artifactItem>
</artifactItems>
<includes>**/*</includes>
<overWriteReleases>true</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sql-maven-plugin</artifactId>
<version>1.4</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${version.mysql.connector}</version>
</dependency>
</dependencies>
<configuration>
<driver>com.mysql.jdbc.Driver</driver>
<url>jdbc:mysql://localhost/</url>
<username>xyz</username>
<password>xyz</password>
</configuration>

<executions>
<execution>
<id>drop-and-recreate-db</id>
<phase>process-test-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<autocommit>true</autocommit>
<srcFiles>
<srcFile>
${project.build.directory}/sql/schema/user.sql
</srcFile>
<srcFile>
${project.build.directory}/sql/schema/core.sql
</srcFile>
<srcFile>
${project.build.directory}/sql/schema/game.sql
</srcFile>
</srcFiles>
<onError>abort</onError>
</configuration>
</execution>
</executions>
</plugin>
</pluginManagement>

</build>
</project>

2 Kommentare:

Unknown hat gesagt…

Given so much information in it. its very useful .perfect explanation about java code spliter.Thanks for your valuable information.
best java institute in chennai | java training in chennai

rmouniak hat gesagt…

Thanks for sharing this amazing blog


Java Online Training