## How to deploy to JBoss EAP 7 with Gradle, Cargo, and Jenkins

It took me quite a while to get my Java EE 7 application automatically deployed to a target JBoss EAP 7 server from within Jenkins using Gradle as the build tool and Cargo for managing the deployment. So here’s my final solution for you to use! 😉

dependencies {
}

apply plugin: 'com.bmuschko.cargo'

dependencies {
cargo "org.codehaus.cargo:cargo-core-uberjar:1.5.0",
"org.codehaus.cargo:cargo-ant:1.5.0",
"org.wildfly:wildfly-controller-client:8.2.1.Final"
}

cargo {
containerId = 'wildfly10x'

deployable {
context = 'MyContext'
}

remote {
hostname = '10.1.1.1'

containerProperties {
property 'cargo.jboss.management-http.port', 9990
}
}
}

Jenkinsfile

stage("Deployment") {
}

## Deploying to JBoss EAP 7 is the same as deploying to Wildfly 10

First of all, there’s no Cargo containerId for JBoss EAP 7. However, you can use Wildfly 10 instead, as you can read here: Codehaus Cargo – WildFly 10.x:

The WildFly 10.x container can be used with the JBoss Enterprise Application Platform (EAP) version 7; i.e. the version released in May 2016

## Finding the right versions of Cargo and its Gradle plugin

You need to use the right versions of Cargo and the Cargo Gradle plugin. I’ve found that version 2.2.3 of the Gradle plugin and version 1.5.0 of Cargo itself work fine with Wildfly 10/JBoss EAP 7 (see Execution failed for task ‘:cargoRunLocal’. #152). The latest versions as of this writing of Cargo (1.6.6) and the plugin (2.3) also work in my environment.

If the versions don’t work correctly, you might get an error like this:

FAILURE: Build failed with an exception.

* What went wrong:
> org.codehaus.cargo.container.ContainerException: Cannot create configuration.
There's no registered configuration for the parameters (container [id = [wildfly10x],
type = [remote]], configuration type [runtime]). Actually there are no valid types
registered for this configuration. Maybe you've made a mistake spelling it?

## Deploying to JBoss EAP 7 with the Wildfly Controller Client

Cargo needs a controller client to be able to deploy artifacts to a remote Wildfly 10/JBoss EAP 7 as you can read here: Codehaus Cargo – JBoss Remote Deployer. I’ve found that version 8.2.1.Final of the Wildfly Controller Client org.wildfly:wildfly-controller-client works fine. However, the latest version of org.wildfly.core:wildfly-controller-client (3.0.10.Final) also works.

You need to add it to cargo.dependencies in your build script as shown above. Otherwise you might end up with an error message like this:

FAILURE: Build failed with an exception.

* What went wrong:
> org.codehaus.cargo.container.ContainerException: Failed to create deployer
with implementation class org.codehaus.cargo.container.wildfly.WildFly10xRemoteDeployer
for the parameters (container [id = [wildfly10x]], deployer type [remote]).

## Changing the JBoss management port

In my case, the target JBoss server uses a different port for remote management. The default is 9990, but I use 19990. Simply adding cargo.port = 19990 to the build file didn’t cut it:

> org.codehaus.cargo.util.CargoException: HTTP request failed, response code: -1,
response message: java.net.ConnectException: Connection refused: connect, response body: null

Starting action 'redeploy' for remote container 'wildfly10x' on 'http://localhost:9990'

It took me a while to find the correct way of telling Cargo to use the custom port. The Cargo documentation (see Codehaus Cargo – JBoss Remote Deployer) states:

WildFly 8.x, 9.x and 10.x use the cargo.jboss.management-http.port port

However, setting this property isn’t as easy as adding cargo.jboss.management-http.port = 19990 to your build file, because this results in:

(cargo.jboss.management - http.port) is a binary expression, but it should be a variable expression

cargo {
jboss {
management-http {
port = 19990
}
}
}

> Could not find method jboss() for arguments [cargo_61gwz9gjyqje40dvlr47klkas$_run_closure3$_closure6@22ff8f9]

Finally, I’ve found the right way of setting the property in this article: Local redeployment #123

containerProperties {
property 'cargo.jboss.management-http.port', 19990
}

However, if you use the newest versions of Cargo and the plugin cargo.port = 19990 seems to work again.

dependencies {
}

apply plugin: 'com.bmuschko.cargo'

dependencies {
cargo "org.codehaus.cargo:cargo-core-uberjar:1.5.0",
"org.codehaus.cargo:cargo-ant:1.5.0",
"org.wildfly.core:wildfly-controller-client:3.0.10.Final"
}

cargo {
containerId = 'wildfly10x'
port = 9990

deployable {
context = 'MyContext'
}

remote {
hostname = '10.1.1.1'
}
}

## How to combine/join file paths in Gradle/Groovy

One might think that joining (or combining) two file paths together with Groovy would be an easy thing to do. I’m used to “nice” methods from Ruby like File.join (see How to do a safe join pathname in ruby?):

File.join("path", "to", "join")

As it turns out, there is no such method in Groovy. However, here are two easy ways to safely combine paths in Groovy (which I use in my Gradle build):

import java.nio.file.Paths // only needed for second example

def dir1 = "/the/path"
def dir2 = "to/join"

println new File(dir1, dir2)
println Paths.get(dir1, dir2)
// -> both print "\the\path\to\join" (on my Windows machine)

## Using Gradle wrapper behind a proxy server with self-signed SSL certificates

Today, I wanted to add a Gradle Wrapper to my Java project but had a few issues. I am behind a proxy and it changes the SSL certificates to be able to scan traffic for viruses.

My first attempt to start gradlew build resulted in:

at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:184)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:668)
at sun.security.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:173)
...

Gradle didn’t use the proxy server and tried to connect to the internet directly. This was solved by setting the proxy server in %GRADLE_USER_HOME%\gradle.properties (see Gradlew behind a proxy):

systemProp.http.proxyHost=192.168.1.1
systemProp.http.proxyPort=80
systemProp.http.proxyUser=userid
systemProp.https.proxyHost=192.168.1.1
systemProp.https.proxyPort=80
systemProp.https.proxyUser=userid

Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
....

The reason for the SSLHandshakeException were the proxy’s selft-signed certificates, that could not be validated. I had to add them to the Java keystore (see Java: Ignore/Trust an invalid SSL cert for https communication and Cacerts default password? -> the default password for the Java keystore is changeit):

"%JAVA_HOME%\bin\keytool" -import -trustcacerts -alias MY_ALIAS -file MY_CERT.crt -keystore "%JAVA_HOME%\jre\lib\security\cacerts"

Now, Gradle was able to connect to gradle.org to download the distribution. However, the proxy server would not let the ZIP file through:

at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1840)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
...

distributionPath=wrapper/dists