Since Java EE 6 it's possible to define data sources in a portable way.

This does mean though that the data source is embedded in the application archive. For some use cases, this is exactly what's needed, but for others it may not be ideal.

The alternatives are typically defining a data source on the Java EE server itself, using an admin console or CLI of some kind.

These alternatives do typically require a different syntax to be used, which can be problematic if the data source is often moved in and out of the application. They also require a vendor specific syntax, which in turn can be problematic if application servers from different vendors have to be supported.

A somewhat obscure feature of Java EE data source definitions allows for another variant; deploying an application archive (e.g. a .war) containing only a data source definition and its driver and making that data source available to a second application. This is made possible since the valid JNDI locations for registering the data source includes java:global, which is the special server wide namespace.

To demonstrate this with some example code, we first create a Maven project with only a single web.xml as follows:

<? xml version = "1.0" encoding = "UTF-8" ?> < web - app xmlns = "http://xmlns.jcp.org/xml/ns/javaee" xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi: schemaLocation = "http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version = "3.1" > < data - source > < name > java: global / datasource </ name > < class - name > org . h2 . jdbcx . JdbcDataSource </ class - name > < url > jdbc:h2:mem: test </ url > </ data - source > </ web - app >

And the following 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 > fish . example </ groupId > < artifactId > datasource </ artifactId > < version > 1 </ version > < packaging > war </ packaging > < build > < finalName > datasource </ finalName > </ build > < properties > < project . build . sourceEncoding > UTF - 8 </ project . build . sourceEncoding > < project . reporting . outputEncoding > UTF - 8 </ project . reporting . outputEncoding > </ properties > < dependencies > < dependency > < groupId > com . h2database </ groupId > < artifactId > h2 </ artifactId > < version > 1.4 . 195 </ version > </ dependency > </ dependencies > </ project >

We then build and install this as usual using mvn clean install.

Next, we build a simple application that consumes this data source, which we call datasource-consumer. It only contains a single java file:

@Startup @Singleton public class StartupService { @Resource private DataSource dataSource ; @PostConstruct public void init () { try ( Connection connection = dataSource . getConnection ()) { out . println ( connection . getMetaData (). getDatabaseProductName () + "-" + connection . getCatalog () ); } catch ( SQLException e ) { e . printStackTrace (); } } }

And the following 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 > fish . example </ groupId > < artifactId > datasource - consumer </ artifactId > < version > 1 </ version > < packaging > war </ packaging > < build > < finalName > datasource - consumer </ finalName > </ build > < properties > < project . build . sourceEncoding > UTF - 8 </ project . build . sourceEncoding > < project . reporting . outputEncoding > UTF - 8 </ project . reporting . outputEncoding > < maven . compiler . source > 1.8 </ maven . compiler . source > < maven . compiler . target > 1.8 </ maven . compiler . target > </ properties > < dependencies > < dependency > < groupId > javax </ groupId > < artifactId > javaee - api </ artifactId > < version > 7.0 </ version > < scope > provided </ scope > </ dependency > < dependency > < groupId > com . h2database </ groupId > < artifactId > h2 </ artifactId > < version > 1.4 . 195 </ version > </ dependency > </ dependencies > </ project >

We subsequently deploy both the "resource providing app" and the "resource consuming app" via Payara Micro as follows: java -jar payara-micro.jar --deploy ~/.m2/repository/fish/example/datasource/1/datasource-1.war --deploy ~/.m2/repository/fish/example/datasource-consumer/1/datasource-consumer-1.war And lo and behold, during startup we see " h2-test" being printed in the log. Having a separately deployable data source means we can configure the data source outside the application, but still use only Java EE APIs and descriptors. If we do venture a bit back into the vendor specific realm, we can even add another layer to the configurability by using placeholders in the deployment descriptors using the somewhat common ${} syntax. For example:

<? xml version = "1.0" encoding = "UTF-8" ?> < web - app xmlns = "http://xmlns.jcp.org/xml/ns/javaee" xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi: schemaLocation = "http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version = "3.1" > < data - source > < name > java: global / datasource </ name > < class - name > org . h2 . jdbcx . JdbcDataSource </ class - name > < url > jdbc:h2:mem: $ { db }</ url > </ data - source > </ web - app >