Deploying Data Source Configuration
Originally published on 14 Jun 2017
Last updated on 06 Jan 2020
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>
If we now start up Payara Micro as follows, we can control the DB (catalog) where we connect to from the commandline:
java -Ddb=foo -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
If we look at the logs again, we'll now see "h2-foo"
being printed.
Defining a data source this way is not perfect yet, as unlike the deployment of a resource connector (.rar), the class loader for an application is often isolated. So though the resource is indeed globally defined, the classes the resource makes use of are not. Hopefully the technique demonstrated here can still be useful for some cases as-is, while better solutions may be presented in the future.
Related Posts
The Payara Monthly Catch - November 2024
Published on 28 Nov 2024
by Chiara Civardi
0 Comments
Jakarta EE Media & Community Challenge - Winning Entries: Part 3
Published on 25 Nov 2024
by Chiara Civardi
0 Comments
The Jakarta EE Media and Community Challenge initiated by Payara celebrates the innovation and creativity that thrives within the Jakarta EE community. Designed as a platform to inspire, educate and showcase collaboration, the competition ...