Uncategorized

JPA 2.1 using Hibernate on Liberty Buildpack

Share this post:

On a recent project we were looking at rewriting a system which provides data-ingestion services into a DB2 instance.  As we move more workloads into IBM’s cloud offerings we always stop, think, review to implement the most suitable technical approach to create the work product.

Our team has standardized most of our application development on either Liberty or NodeJS runtimes. We evaluated both and decided that the JPA specification and the features of Hibernate allowed us to create database agnosticism in how we persisted data in the application.

We designed a standard N-Tier application that would receive data at the presentation layer, and pass it, and any associated meta data, to the application layer.  The application would inspect the payload and identify the appropriate domain and its services to manage data in our persistence layer. The high level architecture is shown below.

In this post we will focus on how we implemented the ORM package using Hibernate. At the time of this writing, hibernate was at version 5.2.10. Final released on August 14th 2017.  All our java projects use gradle, so we updated our build gradle to include hibernate-core as per below:

compile group: ‘org.hibernate’, name: ‘hibernate-core’, version: ‘5.2.10.Final’

We are going to touch lightly here on some hibernate basics, but please don’t consider this a definitive guide to hibernate. The home of hibernate on the web has some excellent starter packs we highly recommend them over our overview below should this discussion whet your appetite. http://docs.jboss.org/hibernate/orm/5.2/quickstart/html_single/

Why use ORM?

This was a question we proposed first. We hadn’t used ORM in many years and we revisited the field, read up on the JPA spec, and started to understand the current ORM implementation in hibernate.  Here is what we think we have gathered.

Hibernate and JPA are not the same thing. JPA is a specification that hibernate implements.  You can still implement hibernate using their annotations and mapping files but everything we read led us to believe that the development of hibernate is moving towards a robust implementation of the JPA specification over an alternative view.  You’ll find as we continue that we use hibernate and JPA in the same context – to us they are the same thing.  We’ll do our best to make that less confusing…but…no promises.

ORM requires thought.  We probably spent the best part of 4 days reading, testing and determining how the capabilities of ORM could be applied to our problem domain. This included learning about lazy and eager fetching, the best way to organize classes into an ORM domain model and how to best use identity fields.  We highly endorse thinking and learning.  If you’re new to ORM it can be overwhelming, but, once you start to understand the basics, you see it provides a feature rich and solid development pattern to ensure code longevity and ease of maintenance.

Know when not to use ORM.  As you learn you’ll see cases when JPA allows you to specify custom queries.  Where appropriate use them. There’s a reason they exist and accomplishing your objectives without them it can over complicate the implementation.  You are without doubt going to find some development approaches which strongly suggest nothing but JPA or nothing but plain SQL, the truth should always be simply – it depends.

So if ORM proves right to you, and you want to deploy on liberty – read on!

Setting up Hibernate/JPA

We are going to assume you are working on either a new project and you know how to set-up gradle, or an existing project where you are using gradle for your dependency and build process.  We are also going to assume you’re using eclipse.  However, nothing we are going to cover here is defendant on your using those tools you will just need to translate the steps into your local IDE and build set-up.  Finally, our implementation utilizes Db2, if you’re using a different database implementation you’ll need the right dialect, this is explained below

Our project was setup with a folder structure of:

  1. src/main/java
  2. src/main/resources
  3. src/test/java
  4. src/main/webapp

Setting up JPA for your project.

We hand annotated our classes for JPA support, Eclipse (if you enable the JPA facet) will generate classes and annotations for you, we decided against this as we wanted to make sure we understood each annotation and how it worked.  Once you have a simple @Entity annotated we can start to configure your web application for JPA support.

In your web.xml located for us at src/main/webapp/WEB-INF/web.xml we added a JDBC reference to our data source:

<resource-ref>
<description>Connect to Tennis</description>
<res-ref-name>jdbc/dbRed</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
<mapped-name>jdbc/db</mapped-name>
<lookup-name>jdbc/db</lookup-name>
</resource-ref>

If your deploying to liberty and using Db2 on Cloud make the mapped and lookup name the same as the name of the service you deployed when you provisioned those services.  If the service was name MyDb2Service the JDBC name would be jdbc/MyDb2Service.  Bluemix will add this to the server.xml for you at deploy time.

If you are using your own server.xml you’ll need to edit the file to include the data source reference and connection properties to the database instance including any required JAR files.

In src/main/resources create a folder called META-INF, and inside this create an XML file called “persistence.xml”. Below you can see the contents from our persistence.xml sample.

<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="domainName">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>java:comp/env/jdbc/dbRef</jta-data-source>
<class>com.ibm.domain.EntityObject</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.DB2Dialect" />
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.engine.transaction.jta.platform.internal.WebSphereExtendedJtaPlatform" />
</properties>
</persistence-unit>
</persistence>

The areas in italics will need to be changed for your project.

  • The unit name should be something to describe the name.
  • The JTA Data Source should be set to whatever you resource reference is in the web.xml from the previous step
  • The <class> object should contain a list of classes that have been annotated to the JPA specification e.g:
    <class>com.ibm.domain.EntityObject</class>
    <class>com.ibm.domain.EntituObject2</class>

You can see in the properties section how we configure any hibernate customizations for our platform, we have applied the DB2 dialect if you are using a different data source you just need to alter this to the implementation provided by hibernate: https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/dialect/DB2Dialect.html

Making a JPA call in your code

We created an abstract super class to use as a utility for other JPA implementations to make use of,  the class diagram below shows our abstract class providing common utilities to the implementation classes

The saveOrUpdate function in the Repository implementation class looked like the following:

package com.ibm.dataingest.persistence;</code>

public class TennisPlayerRepository extends BaseJPARepository&lt;Player&gt; {

private static final String className = TennisPlayerRepository.class.getName();

private static final Logger logger = Logger.getLogger(className);

public TennisPlayerRepository() {
super();
}

@Override
public void saveOrUpdate(Player player) {
final String methodName = "saveOrUpdate";
logger.entering(className, methodName, player);
UserTransaction userTxn = retrieveUserTransaction();
try {
// Commence the user transaction
userTxn.begin();
entityManager.persist(player);
// End the user transaction
userTxn.commit();
}
catch (SystemException | NotSupportedException | SecurityException | IllegalStateException | RollbackException | HeuristicMixedException | HeuristicRollbackException e) {
logger.logp(Level.SEVERE, className, methodName, "Unable to handle player with ID of {0}, exception below.", player.getId());
logger.logp(Level.SEVERE, className, methodName, "Error:", e);
try {
userTxn.rollback();
}
catch (SystemException e1) {
logger.logp(Level.SEVERE, className, methodName, "Unable to roll back transaction during error with  player with ID of {0}, exception below.", player.getId());
logger.logp(Level.SEVERE, className, methodName, "Error:", e1);}
}
logger.exiting(className, methodName);
}
}

Here is how the this works.  As we are using JTA, the server is going to provide the transaction session for us. Firstly, we call the super class and retrieve the current transaction, that method looks like this:

try {
return InitialContext.doLookup("java:comp/UserTransaction");
} catch (NamingException x) {
throw new RuntimeException(x);
}

Once we have the transaction we tell the entity manager to persist the object it has been passed, then we tell it to commit our session.  If we get any exceptions we rollback the transaction in the commit history.

 

Once you have wired in your code into the persistence class you can test your code.

Deploy to bluemix

Now build you war and upload to bluemix or use the DevOps tools to do it for you.  Hit your endpoint and check your datasource!

Conclusion

Hopefully this saves you some effort in getting JPA 2.1 to work with the liberty build pack on Bluemix.  If you’re running liberty locally you will need to be on at least 17.0.0.2 as there is a known issue on 17.0.0.1.

As we stated earlier ORM presents many benefits when user for persistence functions.  However, it doesn’t reduce the importance of a developer checking the implementation, reviewing SQL performance with a DBA, and verifying that your interface is efficient as possible.  Use wisely and enjoy it’s benefits when appropriate to do so.

More Uncategorized stories

Migrate your GCM client Apps on Android to FCM

Google Cloud Messaging (GCM) has been deprecated and is integrated with Firebase Cloud Messaging (FCM). Google will turn off most GCM services by April 2019.

Continue reading

IBM Analytics Engine is now available in the London DC

The IBM Analytics Engine team is excited to announce the General Availability (GA) of IBM Analytics Engine, the next generation of IBM’s Apache Spark and Apache Hadoop cloud service in the London DC.

Continue reading