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.


Avoiding EJBException wrapping


Posted on Sunday Mar 02, 2014 at 03:33PM in Technology


How to avoid EJBException wrapping.

Environment

  • WildFly 8.0.0.Final
  • Oracle JDK7u51

How?

  • We can avoid EJBException wrapping with @ApplicationException annotation.
  • Also API classes (e.g. NoResultException) can be specified in WEB-INF/ejb-jar.xml.

Project

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>avoidejbexception</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <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>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

Stateless Session Bean

package org.nailedtothex.ex;

import javax.ejb.Stateless;
import javax.persistence.NoResultException;

@Stateless
public class MyEJB {

    public void throwIllegalArgumentException(){
        throw new IllegalArgumentException();
    }

    public void throwNoResultException(){
        throw new NoResultException();
    }

    public void throwMyApplicationException(){
        throw new MyApplicationException();
    }

}

Servlet

package org.nailedtothex.ex;

import java.io.IOException;

import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/*")
public class MyServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Inject
    MyEJB myEJB;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        StringBuilder sb = new StringBuilder();

        try{
            myEJB.throwNoResultException();
        }catch(Exception e){
            sb.append("throwNoResultException() thrown: ").append(e.getClass()).append('\n');
        }

        try{
            myEJB.throwIllegalArgumentException();
        }catch(Exception e){
            sb.append("throwIllegalArgumentException() thrown: ").append(e.getClass()).append('\n');
        }

        try{
            myEJB.throwMyApplicationException();
        }catch(Exception e){
            sb.append("throwMyApplicationException() thrown: ").append(e.getClass());
        }

        System.out.println(sb);
    }
}

MyApplicationException

package org.nailedtothex.ex;

import java.io.Serializable;

import javax.ejb.ApplicationException;

@ApplicationException
public class MyApplicationException extends RuntimeException implements Serializable {

    private static final long serialVersionUID = 1L;

}

/WEB-INF/ejb-jar.xml

<?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>
  • Taken from [1].

Log

16:21:39,152 INFO  [stdout] (default task-13) throwNoResultException() thrown: class javax.persistence.NoResultException
16:21:39,152 INFO  [stdout] (default task-13) throwIllegalArgumentException() thrown: class javax.ejb.EJBException
16:21:39,153 INFO  [stdout] (default task-13) throwMyApplicationException() thrown: class org.nailedtothex.ex.MyApplicationException

Whole Log

16:21:39,146 ERROR [org.jboss.as.ejb3.invocation] (default task-13) JBAS014134: EJB Invocation failed on component MyEJB for method public void org.nailedtothex.ex.MyEJB.throwIllegalArgumentException(): javax.ejb.EJBException: java.lang.IllegalArgumentException
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleExceptionInOurTx(CMTTxInterceptor.java:190) [wildfly-ejb3-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:275) [wildfly-ejb3-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:340) [wildfly-ejb3-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:239) [wildfly-ejb3-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41) [wildfly-ejb3-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:43) [wildfly-ejb3-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:95) [wildfly-ejb3-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64) [wildfly-ejb3-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:59) [wildfly-ejb3-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:55) [wildfly-ejb3-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:64)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:326)
    at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:448)
    at org.jboss.invocation.AccessCheckingInterceptor.processInvocation(AccessCheckingInterceptor.java:61)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:326)
    at org.jboss.invocation.PrivilegedWithCombinerInterceptor.processInvocation(PrivilegedWithCombinerInterceptor.java:80)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
    at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:185)
    at org.jboss.as.ee.component.ViewDescription$1.processInvocation(ViewDescription.java:182)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
    at org.jboss.as.ee.component.ProxyInvocationHandler.invoke(ProxyInvocationHandler.java:73)
    at org.nailedtothex.ex.MyEJB$$$view1064.throwIllegalArgumentException(Unknown Source) [classes:]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_51]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_51]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_51]
    at java.lang.reflect.Method.invoke(Method.java:606) [rt.jar:1.7.0_51]
    at org.jboss.weld.util.reflection.Reflections.invokeAndUnwrap(Reflections.java:401) [weld-core-impl-2.1.2.Final.jar:2014-01-09 09:23]
    at org.jboss.weld.bean.proxy.EnterpriseBeanProxyMethodHandler.invoke(EnterpriseBeanProxyMethodHandler.java:99) [weld-core-impl-2.1.2.Final.jar:2014-01-09 09:23]
    at org.jboss.weld.bean.proxy.EnterpriseTargetBeanInstance.invoke(EnterpriseTargetBeanInstance.java:56) [weld-core-impl-2.1.2.Final.jar:2014-01-09 09:23]
    at org.jboss.weld.bean.proxy.InjectionPointPropagatingEnterpriseTargetBeanInstance.invoke(InjectionPointPropagatingEnterpriseTargetBeanInstance.java:65) [weld-core-impl-2.1.2.Final.jar:2014-01-09 09:23]
    at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:100) [weld-core-impl-2.1.2.Final.jar:2014-01-09 09:23]
    at org.nailedtothex.ex.MyEJB$Proxy$_$$_Weld$EnterpriseProxy$.throwIllegalArgumentException(Unknown Source) [classes:]
    at org.nailedtothex.ex.MyServlet.doGet(MyServlet.java:30) [classes:]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:687) [jboss-servlet-api_3.1_spec-1.0.0.Final.jar:1.0.0.Final]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [jboss-servlet-api_3.1_spec-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
    at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:113) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.security.handlers.AuthenticationCallHandler.handleRequest(AuthenticationCallHandler.java:52) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:70) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
    at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:240) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:168) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:687) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_51]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_51]
    at java.lang.Thread.run(Thread.java:744) [rt.jar:1.7.0_51]
Caused by: java.lang.IllegalArgumentException
    at org.nailedtothex.ex.MyEJB.throwIllegalArgumentException(MyEJB.java:10) [classes:]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_51]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_51]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_51]
    at java.lang.reflect.Method.invoke(Method.java:606) [rt.jar:1.7.0_51]
    at org.jboss.as.ee.component.ManagedReferenceMethodInterceptor.processInvocation(ManagedReferenceMethodInterceptor.java:52)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.WeavedInterceptor.processInvocation(WeavedInterceptor.java:53)
    at org.jboss.as.ee.component.interceptors.UserInterceptorFactory$1.processInvocation(UserInterceptorFactory.java:63)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:407)
    at org.jboss.as.weld.ejb.Jsr299BindingsInterceptor.doMethodInterception(Jsr299BindingsInterceptor.java:82) [wildfly-weld-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.as.weld.ejb.Jsr299BindingsInterceptor.processInvocation(Jsr299BindingsInterceptor.java:93) [wildfly-weld-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.as.ee.component.interceptors.UserInterceptorFactory$1.processInvocation(UserInterceptorFactory.java:63)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.WeavedInterceptor.processInvocation(WeavedInterceptor.java:53)
    at org.jboss.as.ee.component.interceptors.UserInterceptorFactory$1.processInvocation(UserInterceptorFactory.java:63)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.invocationmetrics.ExecutionTimeInterceptor.processInvocation(ExecutionTimeInterceptor.java:43) [wildfly-ejb3-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.jpa.interceptor.SBInvocationInterceptor.processInvocation(SBInvocationInterceptor.java:47)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:407)
    at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:46) [weld-core-impl-2.1.2.Final.jar:2014-01-09 09:23]
    at org.jboss.as.weld.ejb.EjbRequestScopeActivationInterceptor.processInvocation(EjbRequestScopeActivationInterceptor.java:83) [wildfly-weld-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ee.concurrent.ConcurrentContextInterceptor.processInvocation(ConcurrentContextInterceptor.java:45) [wildfly-ee-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.InitialInterceptor.processInvocation(InitialInterceptor.java:21)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
    at org.jboss.as.ee.component.interceptors.ComponentDispatcherInterceptor.processInvocation(ComponentDispatcherInterceptor.java:53)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.NonPooledEJBComponentInstanceAssociatingInterceptor.processInvocation(NonPooledEJBComponentInstanceAssociatingInterceptor.java:59) [wildfly-ejb3-8.0.0.Final.jar:8.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:273) [wildfly-ejb3-8.0.0.Final.jar:8.0.0.Final]
    ... 70 more

16:21:39,152 INFO  [stdout] (default task-13) throwNoResultException() thrown: class javax.persistence.NoResultException
16:21:39,152 INFO  [stdout] (default task-13) throwIllegalArgumentException() thrown: class javax.ejb.EJBException
16:21:39,153 INFO  [stdout] (default task-13) throwMyApplicationException() thrown: class org.nailedtothex.ex.MyApplicationException
  • Stacktraces of application exception were not logged.

Specifying java.lang.RuntimeException as an application exception in ejb-jar.xml

log

16:26:13,256 INFO  [stdout] (default task-12) throwNoResultException() thrown: class javax.persistence.NoResultException
16:26:13,256 INFO  [stdout] (default task-12) throwIllegalArgumentException() thrown: class java.lang.IllegalArgumentException
16:26:13,256 INFO  [stdout] (default task-12) throwMyApplicationException() thrown: class org.nailedtothex.ex.MyApplicationException
  • Seems to be working.

Specifying java.lang.Exception as an application exception in ejb-jar.xml

log

16:26:54,294 INFO  [stdout] (default task-1) throwNoResultException() thrown: class javax.ejb.EJBException
16:26:54,294 INFO  [stdout] (default task-1) throwIllegalArgumentException() thrown: class javax.ejb.EJBException
16:26:54,294 INFO  [stdout] (default task-1) throwMyApplicationException() thrown: class org.nailedtothex.ex.MyApplicationException
  • Not working?

References

  1. EJB steals JPA's exceptions? | Community
  2. java - EJB 3.1 application deployed as WAR-only: What about ejb-jar.xml? - Stack Overflow
  3. java - How to include ejb-jar.xml in .war - Stack Overflow
  4. Deployment Descriptors used In WildFly - WildFly 8 - Project Documentation Editor


Deploying with Jenkins Publish Over SSH Plugin


Posted on Friday Feb 28, 2014 at 09:28AM in Jenkins


Environment

  • WildFly 8.0.0.Final
  • Publish Over SSH Plugin 1.11
  • Jenkins 1.551
  • OS X 10.9.2

Requirements

  • Resources are available in git repository
  • The job is parametarized and can specify the tag to be processed
  • The job will build a WAR and deploy it to the remote application server through ssh

Install the plugin

  • Install “Publish Over SSH Plugin 1.11” at Plug-in page.

Create a key-pair

kyle-no-MacBook:~ jenkins$ whoami
jenkins
kyle-no-MacBook:~ jenkins$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/Shared/Jenkins/.ssh/id_rsa): 
Created directory '/Users/Shared/Jenkins/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /Users/Shared/Jenkins/.ssh/id_rsa.
Your public key has been saved in /Users/Shared/Jenkins/.ssh/id_rsa.pub.
The key fingerprint is:
[...] 
The key's randomart image is:
[...]
kyle-no-MacBook:~ jenkins$ ls -l .ssh
total 16
-rw-------  1 jenkins  jenkins  1679 Feb 28 11:55 id_rsa
-rw-r--r--  1 jenkins  jenkins   411 Feb 28 11:55 id_rsa.pub
kyle-no-MacBook:~ jenkins$ 

Put the public-key to the server

kyle-osxserver:.ssh kyle$ cat >> authorized_keys << EOF
> ssh-rsa [...] jenkins@kyle-no-MacBook.local
> EOF

Configure

  1. Click “Manage Jenkins”
  2. Click “Configure System”
  3. Go to “Publish over SSH” section
  4. Enter “/Users/Shared/Jenkins/.ssh/id_rsa” to “Path to Key”
  5. Click “Add” at “SSH Servers”
  6. Enter any logical name to “Name”
  7. Enter IP Address or Hostname of the server to “Hostname”
  8. Enter the user name to login to “Username”
  9. Enter any directory to “Remote Directory”
  10. Click “Test Configuration”
  11. Click “Save” at bottom of the page

Create a job

  1. Create or copy a job that can build the WAR correctly.
  2. As I wrote in How to specify a Git tag to be processed, make a job to can specify a tag to be processed.
  3. Click “Add post-build action”
  4. Click “Send build artifacts over SSH”
  5. Enter “Source files”
  6. Enter “Remove prefix”
  7. Enter “Exec command”

WildFly deploy command example:

/Users/kyle/wildfly-8.0.0.Final/bin/jboss-cli.sh --connect --controller=localhost:49990 --command="deploy hoge-0.0.1-SNAPSHOT.war --force"

Create a tag

kyle-no-MacBook:stock kyle$ git tag v0.1
kyle-no-MacBook:stock kyle$ git tag
v0.1
kyle-no-MacBook:stock kyle$ git show v0.1
commit 87a93c8039bd77b8eb8cbf8fbb522705c6451f1e
[...]

Run

Run the job that created with the parameter of name of tag.

  1. Click “Build with Parameters”

  2. Select a tag to be processed and Click “Build”

Log

...
[JENKINS] Archiving /Users/Shared/Jenkins/Home/jobs/HogeDeploy/workspace/hoge/pom.xml to org.nailedtothex/hoge/0.0.1-SNAPSHOT/hoge-0.0.1-SNAPSHOT.pom
[JENKINS] Archiving /Users/Shared/Jenkins/Home/jobs/HogeDeploy/workspace/hoge/target/hoge-0.0.1-SNAPSHOT.war to org.nailedtothex/hoge/0.0.1-SNAPSHOT/hoge-0.0.1-SNAPSHOT.war
channel stopped
SSH: Connecting from host [kyle-no-MacBook.local]
SSH: Connecting with configuration [osxserver] ...
SSH: EXEC: STDOUT/STDERR from command [/Users/kyle/wildfly-8.0.0.Final/bin/jboss-cli.sh --connect --controller=localhost:49990 --command="deploy /Users/kyle/hoge-0.0.1-SNAPSHOT.war --force"] ...
SSH: EXEC: completed after 4,357 ms
SSH: Disconnecting configuration [osxserver] ...
SSH: Transferred 1 file(s)
Email was triggered for: Always
Sending email for trigger: Always
Sending email to: kyle@example.com
Finished: SUCCESS

References

  1. Publish Over - Jenkins - Jenkins Wiki
  2. jenkinsによるWebSphereへのEARファイルデプロイ - 遅れてやってきたプログラマーの小言
  3. Jenkins、Webから再起動する
  4. Git - タグ
  5. Deploy to WildFly using jboss-cli (Tech Tip #11) | Miles to go 2.0 … | Planet JBoss Community