Kohei Nozaki's blog 

Switching environment specific configuration files


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


  • In my last posting Treating environment specific configurations with Maven filtering, I said that I don't want to create separate files for each environment.
  • But it is still needed by some cases.
    • Such as web.xml, logback.xml is too long for treat with Maven properties at some cases.
  • So I'm going to find a way to achieve it.

Environment

  • Apache Maven 3.1.1
  • Jenkins 1.551
  • WildFly 8.0.0.Final
  • Eclipse Kepler SR1
  • Oracle JDK7u51
  • OS X 10.9.2

Preparation

~/.m2/settings.xml

<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.environmentId>dev</hogeApp.environmentId>
            </properties>
        </profile>
    </profiles>
</settings>

Explicit selection of the Maven Profile is mandatory.

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

  2. Check “development” - OK

Sample project

Project structure

kyle-no-MacBook:switch kyle$ tree src
src
├── main
│   ├── java
│   │   └── org
│   │       └── nailedtothex
│   │           └── sw
│   │               └── MainServlet.java
│   ├── resources
│   │   ├── _dev
│   │   │   └── env-specific.properties
│   │   ├── _it
│   │   │   └── env-specific.properties
│   │   └── common.properties
│   └── webapp
│       ├── WEB-INF
│       │   ├── index.jsp
│       │   └── lib
│       ├── _dev
│       │   └── WEB-INF
│       │       └── web.xml
│       └── _it
│           └── WEB-INF
│               └── web.xml
└── test
    ├── java
    │   └── org
    │       └── nailedtothex
    │           └── sw
    │               └── MainServletIT.java
    └── resources
        ├── _dev
        │   └── test-env-specific.properties
        ├── _it
        │   └── test-env-specific.properties
        └── test-common.properties
  • We can place environment specific files in the folders named such as “_dev” or “_it”.
  • Common resources among environments are can be placed on the regular place.
    • /webapp/WEB-INF/index.jsp and /src/main/resources/common.properties are regarded as common resources.
    • So they will be included for every environment.
  • This mechanism supports both of /src/main/resources and /src/webapp, and /src/test/resources too.
  • MainServet acquires all of properties, then dispatch to /WEB-INF/index.jsp, and return variables to the client.

Produced artifact by standalone Maven

kyle-no-MacBook:switch kyle$ mvn clean package -P development >/dev/null; unzip -l target/switch.war
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
Archive:  target/switch.war
  Length     Date   Time    Name
 --------    ----   ----    ----
        0  03-05-14 11:12   META-INF/
      129  03-05-14 11:12   META-INF/MANIFEST.MF
        0  03-05-14 11:12   WEB-INF/
        0  03-05-14 11:12   WEB-INF/classes/
        0  03-05-14 11:12   WEB-INF/classes/org/
        0  03-05-14 11:12   WEB-INF/classes/org/nailedtothex/
        0  03-05-14 11:12   WEB-INF/classes/org/nailedtothex/sw/
       64  03-05-14 11:12   WEB-INF/classes/common.properties
       75  03-05-14 11:12   WEB-INF/classes/env-specific.properties
     2479  03-05-14 11:12   WEB-INF/classes/org/nailedtothex/sw/MainServlet.class
      158  03-04-14 22:41   WEB-INF/index.jsp
      470  03-04-14 22:31   WEB-INF/web.xml
     2433  03-05-14 10:15   META-INF/maven/org.nailedtothex/switch/pom.xml
      116  03-05-14 11:12   META-INF/maven/org.nailedtothex/switch/pom.properties
 --------                   -------
     5924                   14 files
kyle-no-MacBook:switch kyle$ 

Resources

Whole resources are available in GitHub.

Output of MainServlet on development environment

  • This is output of when I deployed the application to WildFly through Eclipse.
kyle-no-MacBook:switch kyle$ curl http://localhost:8080/switch/
This value came from context-param defined in /src/main/webapp/_dev/WEB-INF/web.xml
This value came from /src/main/resources/common.properties
This value came from /src/main/resources/_dev/env-specific.properties
kyle-no-MacBook:switch kyle$ 

Test execution from command-line

  • Ensure WildFly is stopped before execute the command.
kyle-no-MacBook:switch kyle$ mvn verify -P development,test-with-wildfly
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building switch 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- properties-maven-plugin:1.0-alpha-2:read-project-properties (default) @ switch ---
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ switch ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ switch ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ switch ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ switch ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.16:test (default-test) @ switch ---
[INFO] 
[INFO] --- maven-war-plugin:2.4:war (default-war) @ switch ---
[INFO] Packaging webapp
[INFO] Assembling webapp [switch] in [/Users/kyle/gits1/switch/switch/target/switch]
[INFO] Processing war project
[INFO] Copying webapp webResources [/Users/kyle/gits1/switch/switch/src/main/webapp/_dev] to [/Users/kyle/gits1/switch/switch/target/switch]
[INFO] Copying webapp resources [/Users/kyle/gits1/switch/switch/src/main/webapp]
[INFO] Webapp assembled in [36 msecs]
[INFO] Building war: /Users/kyle/gits1/switch/switch/target/switch.war
[INFO] 
[INFO] --- wildfly-maven-plugin:1.0.1.Final:start (wildfly-run) @ switch ---
[INFO] JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home/jre
[INFO] JBOSS_HOME=/Users/kyle/apps/wildfly-8.0.0.Final

[INFO] Server is starting up.
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
3 05, 2014 12:01:24 午後 org.xnio.Xnio <clinit>
INFO: XNIO version 3.2.0.Final
3 05, 2014 12:01:25 午後 org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.2.0.Final
3 05, 2014 12:01:25 午後 org.jboss.remoting3.EndpointImpl <clinit>
INFO: JBoss Remoting version 4.0.0.Final
12:01:25,334 INFO  [org.jboss.modules] (main) JBoss Modules version 1.3.0.Final
12:01:25,601 INFO  [org.jboss.msc] (main) JBoss MSC version 1.2.0.Final
12:01:25,689 INFO  [org.jboss.as] (MSC service thread 1-6) JBAS015899: WildFly 8.0.0.Final "WildFly" starting
12:01:25,696 DEBUG [org.jboss.as.config] (MSC service thread 1-6) Configured system properties:
    awt.toolkit = sun.lwawt.macosx.LWCToolkit
    file.encoding = UTF-8

*SNIP*

12:01:27,910 INFO  [org.jboss.as.server] (ServerService Thread Pool -- 29) JBAS018559: Deployed "switch.war" (runtime-name : "switch.war")
12:01:27,911 INFO  [org.jboss.as.server] (ServerService Thread Pool -- 29) JBAS018559: Deployed "mavenprops.war" (runtime-name : "mavenprops.war")
12:01:27,920 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015961: Http management interface listening on http://127.0.0.1:9990/management
12:01:27,920 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015951: Admin console listening on http://127.0.0.1:9990
12:01:27,921 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015874: WildFly 8.0.0.Final "WildFly" started in 2929ms - Started 359 of 419 services (100 services are lazy, passive or on-demand)
[INFO] 
[INFO] >>> wildfly-maven-plugin:1.0.1.Final:deploy (wildfly-run) @ switch >>>
[INFO] 
[INFO] --- properties-maven-plugin:1.0-alpha-2:read-project-properties (default) @ switch ---
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ switch ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ switch ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ switch ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ switch ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.16:test (default-test) @ switch ---
[INFO] Skipping execution of surefire because it has already been run for this configuration
[INFO] 
[INFO] --- maven-war-plugin:2.4:war (default-war) @ switch ---
[INFO] Packaging webapp
[INFO] Assembling webapp [switch] in [/Users/kyle/gits1/switch/switch/target/switch]
[INFO] Processing war project
[INFO] Copying webapp webResources [/Users/kyle/gits1/switch/switch/src/main/webapp/_dev] to [/Users/kyle/gits1/switch/switch/target/switch]
[INFO] Copying webapp resources [/Users/kyle/gits1/switch/switch/src/main/webapp]
[INFO] Webapp assembled in [8 msecs]
[INFO] Building war: /Users/kyle/gits1/switch/switch/target/switch.war
[INFO] 
[INFO] <<< wildfly-maven-plugin:1.0.1.Final:deploy (wildfly-run) @ switch <<<
[INFO] 
[INFO] --- wildfly-maven-plugin:1.0.1.Final:deploy (wildfly-run) @ switch ---
12:01:30,671 INFO  [org.jboss.as.repository] (management-handler-thread - 3) JBAS014900: Content added at location /Users/kyle/apps/wildfly-8.0.0.Final/standalone/data/content/77/69a251de04b468b0d3afc81afe32b2c1b58a63/content
12:01:30,678 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-9) JBAS017535: Unregistered web context: /switch
12:01:30,713 INFO  [org.hibernate.validator.internal.util.Version] (MSC service thread 1-9) HV000001: Hibernate Validator 5.0.3.Final
12:01:30,756 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-16) JBAS015877: Stopped deployment switch.war (runtime-name: switch.war) in 81ms
12:01:30,757 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-12) JBAS015876: Starting deployment of "switch.war" (runtime-name: "switch.war")
12:01:30,785 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-3) JBAS015877: Stopped deployment switch.war (runtime-name: switch.war) in 27ms
12:01:30,786 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-14) JBAS015876: Starting deployment of "switch.war" (runtime-name: "switch.war")
12:01:30,829 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-14) JBAS017534: Registered web context: /switch
12:01:30,871 INFO  [org.jboss.as.server] (management-handler-thread - 3) JBAS018562: Redeployed "switch.war"
12:01:30,871 INFO  [org.jboss.as.server] (management-handler-thread - 3) JBAS018565: Replaced deployment "switch.war" with deployment "switch.war"
[INFO] 
[INFO] --- maven-failsafe-plugin:2.16:integration-test (default) @ switch ---
[INFO] Failsafe report directory: /Users/kyle/gits1/switch/switch/target/failsafe-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
Running org.nailedtothex.sw.MainServletIT
testEnvSpecific: {app.hostname=localhost, wildfly.port.offset=0, wildfly.port.mgmt=9990, wildfly.home=/Users/kyle/apps/wildfly-8.0.0.Final, value=This value came from /src/test/resources/_dev/test-env-specific.properties, app.port=8080}
testCommon: {app.environmentId=dev, app.path=/switch, value=This value came from /src/test/resources/test-common.properties}
test(): environment=dev, url=http://localhost:8080/switch/
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.568 sec - in org.nailedtothex.sw.MainServletIT

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] 
[INFO] --- wildfly-maven-plugin:1.0.1.Final:undeploy (wildfly-stop) @ switch ---
12:01:31,863 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-3) JBAS017535: Unregistered web context: /switch
12:01:31,873 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-8) JBAS015877: Stopped deployment switch.war (runtime-name: switch.war) in 10ms
12:01:31,889 INFO  [org.jboss.as.repository] (management-handler-thread - 4) JBAS014901: Content removed from location /Users/kyle/apps/wildfly-8.0.0.Final/standalone/data/content/77/69a251de04b468b0d3afc81afe32b2c1b58a63/content
12:01:31,889 INFO  [org.jboss.as.server] (management-handler-thread - 4) JBAS018558: Undeployed "switch.war" (runtime-name: "switch.war")
[INFO] 
[INFO] --- wildfly-maven-plugin:1.0.1.Final:shutdown (wildfly-stop) @ switch ---
12:01:31,917 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-16) JBAS010409: Unbound data source [java:jboss/jdbc/JBatchDS]

*SNIP*

12:01:31,950 INFO  [org.jboss.as] (MSC service thread 1-10) JBAS015950: WildFly 8.0.0.Final "WildFly" stopped in 28ms
[INFO] 
[INFO] --- maven-failsafe-plugin:2.16:verify (default) @ switch ---
[INFO] Failsafe report directory: /Users/kyle/gits1/switch/switch/target/failsafe-reports
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 9.541s
[INFO] Finished at: Wed Mar 05 12:01:32 JST 2014
[INFO] Final Memory: 14M/245M
[INFO] ------------------------------------------------------------------------
kyle-no-MacBook:switch kyle$ 

How to apply this method to Jenkins job which executes integration test?

  • We need to specify the profile named “test-with-wildfly”
  • And appropriate environmentId on MAVEN_OPTS.

Test run

  • integration-test phase executed expectedly.
[INFO] --- maven-failsafe-plugin:2.16:integration-test (default) @ switch ---
[INFO] Failsafe report directory: /Users/Shared/Jenkins/Home/jobs/Switch/workspace/switch/target/failsafe-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running org.nailedtothex.sw.MainServletIT
testEnvSpecific: {app.hostname=localhost, wildfly.port.offset=40000, wildfly.port.mgmt=49990, wildfly.home=/Users/Shared/Jenkins/wildfly-8.0.0.Final, value=This value came from /src/test/resources/_it/test-env-specific.properties, app.port=48080}
testCommon: {app.environmentId=it, app.path=/switch, value=This value came from /src/test/resources/test-common.properties}
test(): environment=it, url=http://localhost:48080/switch/
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.738 sec - in org.nailedtothex.sw.MainServletIT

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

Remarks

  • I don't know whether it is good idea for any cases because we easily misses to keep these platform specific files correctly.
    • Sometimes we forget about these files need to be edited or created.
  • So, I guess that we are better to apply this method for few numbers of resources that really required this way.

Unresolved issues

  • Eclipse produces the package contains unnecessary resources.
  • It seems to that exclusions are ignored.
  • I guess this is not a problem for most cases, because correct environment specific resources are included.
kyle-no-MacBook:switch kyle$ unzip -l ~/apps/wildfly-8.0.0.Final/standalone/deployments/switch.war
Archive:  /Users/kyle/apps/wildfly-8.0.0.Final/standalone/deployments/switch.war
  Length     Date   Time    Name
 --------    ----   ----    ----
      222  03-05-14 11:25   META-INF/maven/org.nailedtothex/switch/pom.properties
     4476  03-05-14 11:25   META-INF/maven/org.nailedtothex/switch/pom.xml
      470  03-05-14 11:25   WEB-INF/web.xml
      105  03-05-14 11:23   META-INF/MANIFEST.MF
     2186  03-05-14 10:15   WEB-INF/classes/org/nailedtothex/sw/MainServlet.class
       64  03-05-14 10:15   WEB-INF/classes/common.properties
       75  03-05-14 10:15   WEB-INF/classes/env-specific.properties
       75  03-05-14 09:46   WEB-INF/classes/_dev/env-specific.properties
      158  03-04-14 22:41   WEB-INF/index.jsp
       74  03-04-14 22:34   WEB-INF/classes/_it/env-specific.properties
      433  03-04-14 22:14   _dev/WEB-INF/web.xml
        0  03-04-14 22:04   META-INF/
        0  03-04-14 22:04   META-INF/maven/
        0  03-04-14 22:04   META-INF/maven/org.nailedtothex/
        0  03-04-14 22:04   META-INF/maven/org.nailedtothex/switch/
        0  03-05-14 09:48   WEB-INF/
        0  03-04-14 22:34   WEB-INF/classes/
        0  03-04-14 22:04   WEB-INF/classes/org/
        0  03-04-14 22:04   WEB-INF/classes/org/nailedtothex/
        0  03-04-14 22:04   WEB-INF/classes/org/nailedtothex/sw/
        0  03-04-14 22:34   WEB-INF/classes/_dev/
        0  03-04-14 22:13   _dev/
        0  03-04-14 22:13   _dev/WEB-INF/
        0  03-04-14 22:34   WEB-INF/classes/_it/
        0  03-05-14 09:48   WEB-INF/lib/
 --------                   -------
     8338                   25 files
kyle-no-MacBook:switch kyle$ 

References

  1. Maven War plugin - Adding and Filtering External Web Resources
  2. maven 2 - maven2: excluding directory from WAR - Stack Overflow
  3. maven-war-pluginでファイルの除外やweb.xmlの指定など:Javaってまだいけますか
  4. Configure a Maven project for multiple target environments | Vino.java
  5. maven - Eclipse and m2e: how to automatically exclude a resource folder from JAR? - Stack Overflow
  6. Bug 388683 – maven-surefire-plugin SystemPropertyVariables ignored
  7. Properties Maven Plugin - Introduction


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


Comparison of 2 ways of integration testing: Arquillian and Remote EJB


Posted on Tuesday Mar 04, 2014 at 06:51AM in Technology


Arquillian

Pros

  • It enables us to testing of all kind of beans or methods.
    • CDI Managed Beans
    • EJBs that have only no interface view or local interface
    • Methods what returns/receives object which not serializable
    • everything
  • There are many various ways of manipulating testing package.
    • e.g. adding data source definition or persistence descriptor (persistence.xml) for testing purpose is easy because of useful ShrinkWrap.
  • We can keep the package for testing deployment smaller.
    • We can create smaller deployment package which contains only necessary resources for each test case.

Cons

  • It needs deployment for each test execution.
    • It brings longer deployment time for some cases. if you can keep test packages smaller or you can use faster embedded containers, you might think that it's not problem at all.
    • When I want to execute all of test classes, It will execute deployment many times (same as numbers of test classes). I guess it's inefficient.
    • Also there are some ways to avoid it such as creating delegate test classes, but I think it's annoying.
  • It takes some times for making test package.
    • It gives us great ability to manipulate test package with ShrinkWrap, but it takes some time for making test package. it needs to make WAR or EAR through scanning all necessary classes and dependencies (jar files), for each test execution.
  • Dependency resolving is annoying.
    • We can manipulate what testing package contains completely with Arquillian, but I guess it's annoying for some cases.
    • I have tried to resolve dependencies through Arquillian's Maven Plug-in API, but sometimes I got unexpected result which different with standalone Maven (such as exclusion, etc), and resolving is need to be executed for each test execution.
  • We have to include testing dependencies such as Mockito or DBUnit on the deployment.
    • I know it's not a problem for many cases, I just feel it is not likely to me. I guess that these are not required on the server-side.

Remote EJB

Pros

  • We can control the time of deployment completely.
    • We can execute many test classes for deployment only once.
    • It reduces many deployment time and test execution time for some cases.
  • We can do testing against pure production resources.
  • We don't need to another preparation of testing packages through resolving resources and dependencies.
  • It depends on only more simply and standardized technologies.
    • We don't need to mark @RunWith(Arquillian.class) on test classes.
    • All we need is just lookup the remote bean on the method marked @Before, and invoke target method.

Cons

  • Testable resources are limited on EJBs that have remote interface.
    • We can't test CDI Managed Beans on this way.
  • All of method parameters and return object are need to be serializable.
    • Also larger serializable objects in the test would make testing performance worse.
  • We have to create remote interfaces for beans that needs to be tested.
    • It's annoying, and remote interfaces are unnecessary for production environment at some occasions.
  • EJBs are considered as heavier than CDI Managed Beans.
  • Performance of remote EJB lookups may vary between environments.
    • I experienced that it takes 1 second or more with GlassFish3.
    • Now I'm using WildFly 8.0.0Final, it takes only some milli-seconds.
  • We have to deploy the whole application package for every testing.
    • Larger application needs more time for deployment.
    • So, we have to keep the size of projects at appropriate size.

Conclusion and how to overcome cons

  • I prefer Remote EJB at present time.
  • Annoying preparation of remote interfaces are not pain as much to me.
    • we can make remote interfaces this way, it needs only small amount of additional code:
public interface BusinessDayUtil {

    boolean isBusinessDay(Date date);

    Date addDays(Date date, int days);

    @javax.ejb.Remote
    interface Remote extends BusinessDayUtil {
    }

    @javax.ejb.Local
    interface Local extends BusinessDayUtil {
    }
}
  • Implementation class:
@Stateless
public class BusinessDayUtilImpl implements BusinessDayUtil.Local, BusinessDayUtil.Remote {
...
  • And we can inject the bean through local-view easily:
public class MyJobOperatorImpl implements JobOperator {

    @Inject
    BusinessDayUtil.Local businessDayUtil;
...
  • We don't want to EJBs to wrapping Exceptions with EJBException at some occasions.
    • It can avoid on application classes with annotate @ApplicationException
    • Also can achieve on API classes through placement of ejb-jar.xml.
    • I know it's a sidetracking topic, but I wrote for just a note for me.
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" version="3.1"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd">
    <assembly-descriptor>
        <application-exception>
            <exception-class>javax.persistence.NoResultException</exception-class>
            <rollback>true</rollback>
        </application-exception>
    </assembly-descriptor>
</ejb-jar>
  • Making all of arguments and return object serializable is impossible at some occasions.
    • Such as use of InputStream or OutputStream
    • But I guess we can take the old way which stick with plain JUnit testing with mocking frameworks, at such occasions.
CAUTION: invoking EJBs via local interface will call by reference but invoking via remote interface will call by value. you will get serious problems that different behavior between invoking local and remote interfaces. consider keep using remote interface on production (with accepting some performance degradation) or using modern testing framework such as Arquillian if necessary.