how to install a JDBC driver and configure a datasource in JBoss EAP 6 (possibly valid for EAP 7 as well)

Writeup of what I did December 2016 in order to configure a datasource in JBoss EAP 6. Actually tested and verified in JBoss EAP 6.2 and 6.4

The configuration of a datasource may require two distinct steps:

  1. installation of a module for the JDBC driver (if not already installed)
  2. Steps #1 up to #5 in the list below.
  3. definition of the datasource
  4. Step #6 in the list below.
At the time of this writing I have failed to discover a method that would allow me to ship the JDBC driver inside my WAR (as I can do, e.g., in Tomcat). Apparently the JDBC driver in JBoss has to be installed as a "module" in the server which is unfortunate as it decreases my options in terms of scripting and cannot be captured in source control. There is an answer in SO that asserts that it's possible to define datasources in a standard (container-agnostic) way, but when I tried to implement that solution I failed.

I followed a kind of amalgam between the instructions found here and here. Apparently these instructions are equally applicable to JBoss EAP 6 and/or 7. Furthermore, in my particular case, the database I was trying to connect to was a Sybase ASE 15 (or 16, am not sure at the moment) so the exotic factor is high.

You can checkout this playground project of mine for a solution implementing what is described here.

  1. obtain the JDBC driver's JAR
  2. I obtained the jar with an open-source Sybase JDBC driver via Ivy with the following dependency: <dependency org="net.sourceforge.jtds" name="jtds" rev="1.3.1"/>

    In accordance with what is expected from a JDBC jar, it contains a file java.sql.Driver in the META-INF/services directory:

    $ jar tvf jtds-1.3.1.jar  | grep Driver
      33 Sat Jun 08 18:22:50 EDT 2013 META-INF/services/java.sql.Driver
    … which spells out the class name of the driver, in our case: net.sourceforge.jtds.jdbc.Driver

    NB: I added the dependency in my ivy.xml file only temporarily as the JDBC driver is not bundled with the WAR in this method — instead it is created as a module in JBoss (see below).

  3. created a directory for the module under EAP-6.2.0/jboss-eap-6.2/modules/
  4. mkdir -p net/sourceforge/jtds/jdbc/main
    … and did cd there.

    NB: the main in the above directory path is artificial but it is important that the directory branch ends with main. The remaining levels are taken from the package structure inside the driver's JAR all the way to the sub-package where the JDBC driver class is defined. However, I am not sure one has to go all the way there and whether the directory structure is not just a convention to ensure segregation of modules. In the latter case it may have been equally valid to create the module directory as net/sourceforge (if we are confident we aren't going to host any other modules from net.sourceforge) or even some directory structure with no resemblance to the package names at all.

  5. copy JAR in module directory
  6. I then copied the jtds-1.3.1.jar to the tip of the above directory tree branch (main) created in the above step.
  7. provide module definition file in XML
  8. I created, collocated with the jar, a module.xml file with the following contents: $ cat module.xml <?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.1" name="net.sourceforge.jtds.jdbc"> <resources> <resource-root path="jtds-1.3.1.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> <module name="javax.servlet.api" optional="true"/> </dependencies> </module> NB: the string net.sourceforge.jtds.jdbc in file module.xml has to agree with the directory tree created in step #2 so this is not DRY.
  9. add the driver's definition in the standalone.xml file
  10. Go to configuration directory for the standalone option: EAP-6.2.0/jboss-eap-6.2/standalone/configuration and edit file standalone.xml in order to add another single <driver> element under the branch <datasources>/<drivers>. This is what the <drivers> element looked like when I was done: <drivers> <driver name="h2" module="com.h2database.h2"> <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class> </driver> <driver name="sybasejtds" module="net.sourceforge.jtds.jdbc"> <datasource-class>net.sourceforge.jtds.jdbc.Driver</datasource-class> </driver> </drivers>

    The element for the h2 driver was already there, I just added the one about the sybasejtds driver.

    NB: The driver name sybasejtds is entirely arbitrary and is basically what's going to appear in the JBoss AEP administration GUI (typically at port 9990) when one tries to create a new datasource. It is the module name net.sourceforge.jtds.jdbc that has to agree with step #4 and the module's directory structure as created in step #2.

  11. restart the server and define the datasource
  12. After the above steps, I restarted the server and when I visited the JBoss EAP administrative interface to define a new datasource I saw that the driver was already recognized and available as an option. I then defined the datasource using the administrative GUI and then tested it (using the same GUI).

    NB: the JNDI name is pretty arbitrary, the important connection is the name of the driver sybasejtds which has to agree with step #5.

    The definition of the datasource resulted in further changes in file EAP-6.2.0/jboss-eap-6.2/standalone/configuration/standalone.xml. I could obviously have just elected to define the datasource directly in the XML file (however, the GUIs option to test the connection is nice).

    The <datasource> element that ended up in my standalone.xml (after the datasource was defined from the GUI) looked like the following:

    <datasource jta="false" jndi-name="java:/comp/env/jdbc/sybase/axafusers" pool-name="axafusers" enabled="true" use-ccm="false"> <connection-url>jdbc:jtds:sybase://localhost:12501/axafusers</connection-url> <driver-class>net.sourceforge.jtds.jdbc.Driver</driver-class> <driver>sybasejtds</driver> <security> <user-name>user</user-name> <password>secret</password> </security> <validation> <validate-on-match>false</validate-on-match> <background-validation>false</background-validation> </validation> <statement> <share-prepared-statements>false</share-prepared-statements> </statement> </datasource>

    NB: The JBoss server is a piece of excrement as attested by the fact that if you decided to comment out a section in the standalone.xml file (using XML comments), e.g. to try something out — hoping to be able to revert back to it after the test — when the server restarts it's going to delete that element. So to test always make a separate copy of standalone.xml. I've also noticed some random changes in the standalone.xml file which led me to believe that this piece of human waste is reading the file and the writing it back to file based on a parsed representation of the XML (which would explain why it deletes comments).