Kohei Nozaki's blog 

Filtering environment specific configuration files


Posted on Tuesday Mar 04, 2014 at 04:45PM in Technology


Environment

  • Apache Maven 3.1.1
  • Jenkins 1.551
  • Eclipse Kepler SR1
  • Oracle JDK7u51
  • PostgreSQL 9.2.4
  • OS X 10.9.2

Requirement

  • I'm searching an appropriate way to define environment specific configuration.
  • I don't want to create separate files for each environment.
  • I don't want to define environment specific information on pom.xml.

Where to define?

  • There are some candidates for achieve it with Maven.
    • Maven Properties
      • Maven can reference it as ${name}.
    • Java System Properties
      • Maven can reference it as ${name}.
    • Environment Variables
      • Maven can reference it as ${env.name}.

Maven Properties

  • User-local properties are can be defined on ~/.m2/settings.xml
  • It's easy to define on Jenkins jobs through configuration of MAVEN_OPTS.
    • We can specify it like: “-Dname=value”
  • We have to take care on Eclipse to make sure select a profile explicitly.
    • activeByDefault won't work on some cases[8].
  • I go with this way at this time.

Java System Properties

  • We need to define it through arguments of java command.
  • It's annoying to define on Eclipse.
    • I can't found any way on define globally for Run Configuration.
    • Thus, I have to configure it for each programs. It's pretty annoying.
  • It's easy to define it on Jenkins jobs through configuration of MAVEN_OPTS.
    • We can specify it like: “-Dname=value”

Environment Variables

  • We need to define it through platform-specific way.
  • But any programs can reference it through cross-platform way.
  • I guess it's more cross-platform way than Java System Properties.
  • We need a plugin[2] for Jenkins to define environment variables in jobs.
  • I guess it's not bad to achieve it.
  • But it's might not a good idea to storing security informations such as password.

Sample

  • This sample executes simple SQL which acquires the name of connected database.
  • Assume PostgreSQL is running at localhost:5432 and database named “kyle”, “testdb”, “testdb001” are exists.

pom.xml

<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.nailedtothex</groupId>
    <artifactId>mavenprops</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.3-1100-jdbc41</version>
        </dependency>
    </dependencies>

</project>

~/.m2/settings.xml

  • This defines variables of the development environment with Eclipse.
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <profiles>
        <profile>
            <id>development</id>
            <properties>
                <hogeApp.jdbc.url>jdbc:postgresql://localhost:5432/kyle</hogeApp.jdbc.url>
                <hogeApp.jdbc.user>kyle</hogeApp.jdbc.user>
                <hogeApp.jdbc.password>***</hogeApp.jdbc.password>
            </properties>
        </profile>
    </profiles>
</settings>

Activate the profile on Eclipse explicitly

  1. Right-click the project - Maven - Select Maven Profiles

  2. Check “development” - OK

main/resources/jdbc.properties

url=${hogeApp.jdbc.url}
user=${hogeApp.jdbc.user}
password=${hogeApp.jdbc.password}

Main.java

package mavenprops;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

public class Main {

    public static void main(String[] args) throws Exception {
        Properties info = new Properties();
        try (InputStream is = Main.class.getResourceAsStream("/jdbc.properties")) {
            info.load(is);
        }

        try (Connection cn = DriverManager.getConnection(info.getProperty("url"), info);
                Statement st = cn.createStatement();
                ResultSet rs = st.executeQuery("select current_database()")) {
            rs.next();
            System.out.println("current_database(): " + rs.getString(1));
        }
    }
}

Run

Run on Eclipse

current_database(): kyle
  • The database specified in ~/.m2/settings.xml is shown.

Run from command-line

kyle-no-MacBook:mavenprops kyle$ mvn clean compile exec:java -Dexec.mainClass="mavenprops.Main" -DhogeApp.jdbc.url=jdbc:postgresql://localhost:5432/testdb -DhogeApp.jdbc.user=kyle -DhogeApp.jdbc.password=***
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building mavenprops 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ mavenprops ---
[INFO] Deleting /Users/kyle/Documents/workspace/mavenprops/target
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ mavenprops ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ mavenprops ---
[INFO] Compiling 1 source file to /Users/kyle/Documents/workspace/mavenprops/target/classes
[INFO] 
[INFO] >>> exec-maven-plugin:1.2.1:java (default-cli) @ mavenprops >>>
[INFO] 
[INFO] <<< exec-maven-plugin:1.2.1:java (default-cli) @ mavenprops <<<
[INFO] 
[INFO] --- exec-maven-plugin:1.2.1:java (default-cli) @ mavenprops ---
current_database(): testdb
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.333s
[INFO] Finished at: Tue Mar 04 18:25:25 JST 2014
[INFO] Final Memory: 13M/245M
[INFO] ------------------------------------------------------------------------
kyle-no-MacBook:mavenprops kyle$ 
  • The database specified at the command-line arguments is shown.
kyle-no-MacBook:mavenprops kyle$ cat target/classes/jdbc.properties 
url=jdbc:postgresql://localhost:5432/testdb
user=kyle
password=***
  • Filter worked as expectedly.

How to apply this method on Jenkins job

  • We can specify the variables on the configure of the job like this:

Build log

<===[JENKINS REMOTING CAPACITY]===>channel started
log4j:WARN No appenders could be found for logger (org.apache.commons.beanutils.converters.BooleanConverter).
log4j:WARN Please initialize the log4j system properly.
Executing Maven:  -B -f /Users/Shared/Jenkins/Home/jobs/MavenProps/workspace/mavenprops/pom.xml clean compile exec:java
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building mavenprops 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ mavenprops ---
[INFO] Deleting /Users/Shared/Jenkins/Home/jobs/MavenProps/workspace/mavenprops/target
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ mavenprops ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ mavenprops ---
[INFO] Compiling 1 source file to /Users/Shared/Jenkins/Home/jobs/MavenProps/workspace/mavenprops/target/classes
[INFO] 
[INFO] >>> exec-maven-plugin:1.2.1:java (default-cli) @ mavenprops >>>
[WARNING] Failed to getClass for org.codehaus.mojo.exec.ExecJavaMojo
[INFO] 
[INFO] <<< exec-maven-plugin:1.2.1:java (default-cli) @ mavenprops <<<
[INFO] 
[INFO] --- exec-maven-plugin:1.2.1:java (default-cli) @ mavenprops ---
current_database(): testdb001
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.472s
[INFO] Finished at: Tue Mar 04 19:08:39 JST 2014
[INFO] Final Memory: 15M/245M
[INFO] ------------------------------------------------------------------------
[JENKINS] Archiving /Users/Shared/Jenkins/Home/jobs/MavenProps/workspace/mavenprops/pom.xml to org.nailedtothex/mavenprops/0.0.1-SNAPSHOT/mavenprops-0.0.1-SNAPSHOT.pom
channel stopped
Finished: SUCCESS
  • The database specified at configured in the job is shown.

jdbc.properties on the workspace of Jenkins

  • Filter worked expectedly.

References

  1. フィルタリング
  2. EnvInject Plugin - Jenkins - Jenkins Wiki
  3. Setting the system-wide PATH environment variable in Mavericks - Ask Different
  4. HowTo: Set an Environment Variable in Mac OS X - /etc/launchd.conf - Dowd and Associates
  5. Maven Settings Example - Users | Community
  6. maven-war-pluginで環境ごとの設定ファイルを管理してみた - Challenge Java EE !
  7. I can't get maven to use properties defined in ~/.m2/settings.xml? - Stack Overflow
  8. Happy Wide Grove: Eclipse+maven+m2e+JavaFX2



No one has commented yet.

Leave a Comment

HTML Syntax: NOT allowed