Most servers these days, even when not applying a microservice architecture, host just one application. And most new applications connect to just a single database. Still a lot of time, both in development and deployment, is often spent configuring how your application connects to your relational database.
Java EE 7 introduced a concept of default DataSource, which can simplify the setup in both development and deployment. Using it, you can accomplish a situation where you use exactly the same war file during development and deployment. Let’s see how you can use this approach with a Vaadin Bakery app starter based application, which is deployed to SAP Cloud Platform using the HANA database in the cloud deployment. If you want to try this yourself, you can create your own copy of the full-stack app from vaadin.com/start.
1. Get rid of data source declarations
Normally, like with the app generated by the Bakery starter, you’ll use named data sources defined either at the application or server level. If you use low level JDBC, you have probably been injecting them using the following code:
@Resource(name="myDataSource", lookup="java:comp/DefaultDataSource") DataSource myDS;
The lookup is the JNDI address where the DataSource has been configured. If you are using JPA, like the Bakery app is using, you’ll define that in persistence.xml file’s
The JNDI name we used in the DataSource injection example, “java:comp/DefaultDataSource”, is the default DataSource required by the Java EE 7 specification. It is something that should always be provided by the container. If the server administrator hasn’t configured anything for it, servers usually wire some sort of in-memory database for it. It is also a default that doesn’t need to be explicitly defined.
So in case of the Bakery app that is using JPA, you can now remove the jta-data-source tag from persistence.xml altogether. You can also go ahead and remove all data source specific hints, like these in case of a Bakery app:
<!-- These are used when using Hibernate (e.g. on Wildfly) --> <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> <property name="hibernate.show_sql" value="false" />
2. Get rid of obsolete JDBC drivers and data source declaration
If you deploy the app now locally using WildFly or TomEE, the app is already using the provided default DataSource. But we can now clean our project quite a bit, if we get rid of the H2 in-memory database, set up by the starter to achieve easier development process. First, remove the following dependency from pom.xml:
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.3.160</version> </dependency>
That dependency contains both the H2 database and the JDBC driver for it. Then you can get rid of the server specific configuration files that declare the in-memory database as a datasource:
- src/main/webapp/WEB-INF/resources.xml - the file used to declare the datasource for TomEE server
- src/main/webapp/WEB-INF/wildfly-h2-ds.xml - the file used to declare the datasource for WildFly server
- src/test/resources/server.xml - the file to define data source for Liberty server
Now you can try the project and verify it still works with the default DataSource provided automatically by your development. As the target is to deploy a TomEE based Java EE 7 execution environment in SAP Cloud Platform, let’s simply use the tomee-maven-plugin. We’ll also do a full clean build to ensure all obsoleted dependencies are cleared from the war file:
mvn clean install tomee:run
3. Wire the default DataSource in cloud environment
Now let’s get a bit closer to production and deploy the same app to CloudPlatform. All Java EE servers let you re-declare the default DataSource, but the procedure is platform specific. In this case, we’ll create a SAP HANA database service and wire that to the default DataSource of the TomEE based execution environment in SAP CloudPlatform.
Let’s first create a new SAP HANA database. CloudPlatform also provides MaxDB, but let’s use HANA in this exercise. Navigate to cloudplatform.sap.com and choose your Neo environment. Unless you already have a database ready, navigate to SAP HANA / SAP ASE > Databases & Schemas and click New. Fill in a name for your database and set a password for SYSTEM user.
Next we’ll need a database user account for our application. Follow these official instructions and you should have everything ready for the application. Remember the username and password, which are PSTRIAL and Welcome17Welcome17 if you literally follow the instructions. You’ll need the credentials soon when we connect the database to the application container.
Next, navigate back to Applications -> Java Applications and click Deploy application. Choose the war file built to your Bakery projects target directory, choose Java EE 7 Web Profile as a runtime and ensure the JVM version is JRE 8. Clicking deploy will upload the war file and prepare the execution environment. When that is finished, do not click start yet. We will still need to connect it to the database.
Close the dialog and you’ll see the prepared container. Click its name to open it. Choose “Configuration -> Data Source Bindings” and click “New Binding”. Leaving the name as
Now the execution environment is fully set and you can navigate to the containers Overview screen and hit start. After the container is started, you can verify everything works as expected from the update application link.
Pros and cons
All in all, I see the default DataSource feature as a thing that makes your setup simpler, for most use cases. Let’s summarise pros and cons.
- Less code and configuration
- No hassle with JDBC drivers
- Easier for developers to get started as they don’t need to fiddle with local database setup
- Same war file can be used in development and production, without obsolete dependencies
- Can’t be used if you access multiple databases
- The database used in development and production may be different
- Some Java EE containers (namely Liberty) take the liberty of not providing the default DataSource without extra configuration
Are you using default DataSource yourself? Do you have some further ideas of how to simplify the setup even more?