Maven Dependecy JAR Configuration
Join the DZone community and get the full member experience.
Join For FreeWhen moving to Maven from other frameworks there are many questions arising, such as how to handle the configuration of a dependency artifact.
What will happen, for example, when your dependency has some configuration files? The standard Maven way is to put all the configuration files under src/main/resources. That way, they will be located in the resulting jar in the right place, enabling your application to function properly.But, what if you need those configuration files to be subject to change? In the case that they are located inside the jar, you are stuck with the default configuration without the ability to edit and change the module behavior.
I will offer here a way to enable such jar configuration usage.
Let us say we have a module, packed into Jar called jar-with-conf. This module contains a single class called ConfReader.
This class contains a single static function that retrieves a value from a configuration file, given a key:
public class ConfReader
{
public static String getValue(String key)
{
String val = null;
Configuration config = null;
try
{
config = new PropertiesConfiguration("src/main/config/conf.properties");
}
catch (ConfigurationException e)
{
Logger.error(...)
}
if (config != null)
{
val = config.getString(key);
}
return val;
}
}
Apache commons-configuration is used in this example.
This module has also, a configuration file called conf.properties and it is located at src/main/config:
key1=value1
key2=value2
Now, let us say there is an application that is dependent on jar-with-conf called app-using-jar-with-conf (forgive the names I named - one of the toughest task in computer science, as someone once said). This is the simplest application:
public class UsingDepWithConf
{
public static void main( String[] args )
{
System.out.println("value of key1 is " + ConfReader.getValue("key1"));
System.out.println("value of key2 is " + ConfReader.getValue("key2"));
}
}
Of course, while running this simple main method, getValue() will fail as the configuration file is absent from the jar (we didn't put it under the resources directory).
In order to achieve the above requirements we will create a zip, containing the config directory and deploy it to a Maven repository. The client application will retrieve the zip and extract it to its own directory structure.
- Creating The Zip
We will use maven-assembly-plugin for the job. First let's create an assembly descriptor and call it zip.xml:<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
In plain English we say here we want to create a zip file from the config directory. Next let's configure the pom.xml of jar-with-conf to use this descriptor:
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>bin</id>
<baseDirectory>/</baseDirectory>
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>${basedir}/src/main/config</directory>
</fileSet>
</fileSets>
</assembly><build>
Which means, we want to create a single zip file during the package phase according to the zip.xml assembly file.
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/zip.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build> - Deploy The Zip
Of course, packing the config directory into a zip file will not suffice. There is no way client application can access it. That is exactly the reason we have Maven repositories. We will deploy the zip file alongside the module jar artifact. For that, I'll use maven-deploy-plugin. This plugin's deploy goal is bound when creating a jar artifact to the deploy phase in the default Maven lifecycle. Here, I am going to use a different goal - deploy-file which enables us the deployments of artifacts other than the default ones. Here is a snippet of the deployment task in the pom.xml:<plugin>
In the above snippet, the goal deploy-file is bound to the deploy phase, and in the configuration section, all the relevant information is supplied for successful deployment, like repositoryId (make sure it is configured in your settings.xml file and that you have permissions to deploy to the repository), repository URL and, of course, the new artifact identifier - the trinity of groupId, artifactId and version.
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>deploy-conf-zip</id>
<phase>deploy</phase>
<goals>
<goal>deploy-file</goal>
</goals>
</execution>
</executions>
<configuration>
<repositoryId>snapshots</repositoryId>
<file>${project.build.directory}/${project.artifactId}-${project.version}-bin.zip</file>
<url>http://nexus:8081/nexus/content/repositories/snapshots</url>
<groupId>com.my-company.example</groupId>
<artifactId>jar-with-conf-config</artifactId>
<version>${project.version}</version>
<packaging>zip</packaging>
</configuration>
</plugin> - Using The Jar with the Zip
Now, let's configure an application to be dependent on the jar-with-conf artifact and also retrieve the configuration folder and put it in the right place. The following are snippets from the pom.xml of the application app-using-jar-with-conf: The easy part is the artifact dependency:<dependency>
Next, let's retrieve the second artifact that contains the configuration:
<groupId>com.my-company.example</groupId>
<artifactId>jar-with-conf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>jar</type>
<scope>compile</scope>
</dependency><plugin>
The details of this plugin can be found here. The result of this will be an unpacked config folder under src/main in the app-using-jar-with-conf project. The jar of jar-with-conf is in classpath and its configuration is available for change in the client application.
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.my-company.example</groupId>
<artifactId>jar-with-conf-config</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>zip</type>
<overWrite>false</overWrite>
<outputDirectory>${basedir}</outputDirectory>
</artifactItem>
</artifactItems>
<outputDirectory>${basedir}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
This kind of project setup encourages modularity in big systems. System architects should break the design into self-contained modules with simple and clear functionality and API. Those modules can serve whichever piece of software that is in need of such functionality.
Taken from http://ronenp.wordpress.com/2010/08/12/maven-dependecy-jar-configuration/.
Opinions expressed by DZone contributors are their own.
Comments