Deploying Grails 3.2 to JBoss 7.1 EAP

10 Nov 2016

Tags: Grails, Deployment

Following on from our post describing how to deploy Grails 3 to JBoss 6.4 EAP, I recently undertook a new adventure to deploy Grails 3.2.3 to JBoss 7.1 EAP.

Like every new version of JBoss there are dependency challenges and tweaks to overcome in order to get to the point where you can deploy an application.

Configuring Gradle

After you have created a Grails application using the grails create-app command the first thing that needs to be done is to modify the dependencies to versions compatible with JBoss 7.1.

JBoss 7.1 is based on Servlet 3.0 and earlier versions of the Bean Validation API. This means that you need to use Tomcat 7, which is based on Servlet 3.0, which you can do by specifying the Tomcat version in build.gradle:

ext['tomcat.version'] = '7.0.72'

The above uses Spring Boot’s ability to override the default versions of the org.springframework.boot:spring-boot-starter-tomcat dependency. Speaking of the spring-boot-starter-tomcat dependency, you need to make it provided:

provided "org.springframework.boot:spring-boot-starter-tomcat"

Since the classes within the Tomcat JARs are already provided by Tomcat these should not be included in the WAR. Next you should also specify the Servlet 3.0 API as provided:

provided "javax.servlet:javax.servlet-api:3.0.1"

This does two things, firstly it ensures the Servlet API dependencies are not in the WAR and secondly it forces Grails to use Servlet 3.0 instead of the default 3.1.

The next challenge is the Bean Validation API, in earlier versions of JBoss it was possible to exclude the validation module and ship with a custom version of the Bean Validation API, this no longer seems to be possible with JBoss 7 so you have to downgrade the version of Hibernate Validator used by Grails:

compile "org.hibernate:hibernate-validator:4.3.2.Final"

The JAXB dependency also seems be a required dependency of JBoss 7 so you have to add that:

runtime 'javax.xml.bind:jaxb-api:2.2.12'

Finally, generally with JBoss 7 you should deploy with a JNDI datasource so you should make the database driver dependency you are using provided scope. For example for MySQL:

provided "mysql:mysql-connector-java"

JBoss Deployment Descriptors

The next step to getting JBoss configured correctly is to provide a src/main/webapp/WEB-INF/jboss-deployment-structure.xml file, the contents of which should look like the following:

<?xml version='1.0' encoding='UTF-8'?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.1">
    <deployment>
        <exclusions>
            <module name="org.jboss.logging" />
            <module name="org.hibernate" />
            <module name="org.hibernate.validator" />
        </exclusions>
    </deployment>
</jboss-deployment-structure>

The reason for this is to isolate and exclude dependencies you don’t want to inherit from JBoss 7. I also recommend disabling Spring Boot re-packaging of the WAR file if you don’t plan to run as a standalone WAR. You can do that by adding the following to build.gradle:

bootRepackage.enabled = false

JNDI DataSource Configuration

To configure a JNDI datasource you should first define the production data source as using JNDI:

environments:
    development:
        dataSource:
            dbCreate: create-drop
            url: jdbc:h2:mem:devDb
    test:
        dataSource:
            dbCreate: update
            url: jdbc:h2:mem:testDb
    production:
        dataSource:
            jndiName: "java:jboss/datasources/MyDataSource"
            dbCreate: none   

Note that you typically do not want Grails to create the schema for you so we set dbCreate to none. You can then run grails schema-export to generate a build/ddl.sql file that you can use to create the database in your production environment.

On the JBoss side if you are using standalone deployment, you need to modify the standalone/configuration/standalone.xml file to configure your JNDI datasource. For example for MySQL adding the following section within the <datasources> block will do:

    <datasource jndi-name="java:jboss/datasources/MyDataSource" pool-name="MyDataSource">
        <connection-url>jdbc:mysql://localhost:3306/my-database</connection-url>
        <driver>com.mysql</driver>
        <transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation>
        <pool>
            <min-pool-size>10</min-pool-size>
            <max-pool-size>100</max-pool-size>
            <prefill>true</prefill>
        </pool>
        <security>
            <user-name>root</user-name>
        </security>
        <statement>
            <prepared-statement-cache-size>32</prepared-statement-cache-size>
            <share-prepared-statements>true</share-prepared-statements>
        </statement>
    </datasource>

Deploying the Application

Once you have prepared your application for deployment to deploy the app you can run gradle assemble to build a WAR file and then copy the generated WAR file located in build/libs to JBoss 7’s standalone/deployments directory and then run bin/standalone.sh.

Note that if you receive an exception that looks like the following:

16:45:35,789 WARN  [org.jboss.as.ee] (MSC service thread 1-6) JBAS011006: Not installing optional component org.springframework.web.context.request.async.StandardServletAsyncWebRequest due to exception: org.jboss.as.server.deployment.DeploymentUnitProcessingException: JBAS011054: Could not find default constructor for class org.springframework.web.context.request.async.StandardServletAsyncWebRequest
    at org.jboss.as.ee.component.ComponentDescription$DefaultComponentConfigurator.configure(ComponentDescription.java:606)

This is apparently normal behaviour and can be safely ignored.

This is WAY too hard

I agree. Deploying to “enterprise” containers is not fun. It can, however, be a requirement where you work. In order to simplify these steps I have created a JBoss 7 profile for Grails that tries to encapsulate all these changes. Simply run:

grails create-app myapp --profile org.grails.profiles:web-jboss7:1.0.0.RC1

This will create an application in the myapp directory with all the changes necessary apart from preparing the JNDI datasource. Hopefully the profile encourages more JBoss 7 folks to give Grails a try. Happy deploying!

Published on 10 Nov 2016