Community

Using Java Persistence API(JPA) in bluemix with EJBs

Share this post:

Dave Cohen / Advisory Software Engineer / IBM Cloud OE Runtime Test


 
This article will demonstrate how to deploy  a typical JPA application into the BlueMix cloud.
It makes use of a  JPA Sample Application, bound to a db2  database, driven by either EJBs or Servlets.  

  • JPA (Java Persistence API) is a set of APIs that is used for reading and writing data to databases via Java objects.  
  • An EJB (Enterprise Java Bean) is a server side Java object that contains business logic with special qualities  of service (collaborators) such as transactions and security.  

The article provides code snippets for EJBs and JPA, and a sample application.  It explains how to push this application to BlueMix, making use of the auto-config support to connect to a DB2 database. Auto-config is a feature of the BlueMix runtime that facilitates the connection of an application to a back end resource, such as a database, shielding the customer from the complexity of configuring resource XML stanzas or even creating the database itself.

Overview

1. Importing the Sample into Eclipse
2. EJBs

3. JPA
4. Persistence Units, persistence.xml and mapping to the database for JPA

5. Explanation of Auto-config
6. Pushing the standalone war file
7. Running the Application


1. Importing the Sample into Eclipse

Next if you want to examine the source and run the sample application yourself, you can get it from here: <a href="https://hub.jazz.net/project/dacohen01/EJB%20BlueMix%20Sample/overview" title="JPA Blue Mix Project" target="_blank"><span style="text-decoration: underline;">JPABlueMixProject</span></a> <br />Read instructions in the README.MD file to get the project set up with the CF plugin in Eclipse.<br /><br /><strong style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 14px; line-height: 1.5em;"><strong><strong><strong><strong><em></em></strong></strong></strong></strong></strong>

2. EJBs (Enterprise Java Beans)
The sample uses annotations to create callable handles to EJBs that are invoked from servlets.
Annotations (e.g. @EJB ListDBEJB listEJB; ) simplify the process of creating these callable handles to EJBs by just
specifying the EJB class name (e.g. ListDBEJB) followed by the instance name (e.g. listEJB):

Code in servlet that calls the EJB

@EJB ListDBEJB listEJB;<br /><br />OutBean output = null;    //output object to receive results from EJB call<br />InBean input = new InBean(); // create/instantiate a new input object<br /><br />input.setSql(Boolean.parseBoolean(request.getParameter("isMySQL")));  // set the DB type into<br />                                                                      // input object<br />output = listEJB.list(input);  // call the ejb and get the results in output instance


EJB definition in the EJB’s java file containing your business logic:

  @Stateless     // annotation for stateless session EJB bean
@LocalBean // local ejb, can only be called from within same JVM, as per ejbLite feature
public class ListDBEJB {
// your methods and business logic here
}


3. JPA

The PopulateDB function (via EJB or servlet) creates a database table  using native SQL:

q = em.createNativeQuery("CREATE TABLE  CUSTOMERACCT ( C_NUM  SMALLINT
NOT NULL , C_NAME CHARACTER(30) NOT NULL , C_MONEY DECIMAL(12,2)
NOT NULL,PRIMARY KEY ( C_NUM ) )");


and then populates the rows of the table using standard JPA APIs:

    // set values into the CustomerAcct java object("ca") and then persist them into the CustomerAcct database table<br />        for (short j = 0; j &lt; 8; j++) {
ca = new CustomerAcct();
ca.setCustomerAcct((short) (j + 1));
ca.setCustomerMoney(BigDecimal.valueOf(money[j]));
ca.setCustomerName(name[j]);
em.persist(ca);
}
em.close();

The ListDB functions lists out the customers in the database table using a named query (query invoked from a servlet or EJB, but  the query itself is defined in the JPA entity):

   EntityManager em = emfToUse.createEntityManager();  // get an entity manager handle

OpenJPAQuery q = OpenJPAPersistence.cast(em
.createNamedQuery("listCustomers")); // run the named query

Collection coll = null;
coll = q.getResultList(); // gather up the result set into a java collection

if (coll != null) { // if we have results
Iterator it = coll.iterator(); // get the collection into a java iterator
CustomerAcct[] cas = new CustomerAcct[8]; // set up an array for the results
int i = 0;
CustomerAcct ca = null;
while (it.hasNext()) { //iterate through the results of the query
ca = (CustomerAcct) it.next(); // get the next result
System.out.println("customer acct from result set: "+ca);
cas[i] = ca;
i++;
}
ob.setCustomerAccts(cas); //set array of customers into output object
}

Above query as defined in the CustomerAcct JPA Entity:

@Entity
@Table(name="CUSTOMERACCT")
@NamedQuery(
name="listCustomers",
query="select c from CustomerAcct c"
)

The CustomerCredit function locates a customer record and updates that customer’s balance in the CUSTOMERACCT table:

CustomerAcct customerAcct = em.find(CustomerAcct.class, customerNumber);  // find the customer record for this "customerNumber"
double money = customerAcct.getCustomerMoney().doubleValue()+ moneyToCredit; //determine the credit $$
customerAcct.setCustomerMoney(new BigDecimal(money)); // set new balance value<br /> em.close();<br /><br /><em></em>

4. Persistence Units, persistence.xml and mapping to the database for JPA

Persistence units specify the persistent unit names, dataSources and JPA entity name(s) necessary to access the database table.
The persistence.xml, which describes the persistence units, is under the src/META-INF folder.

The business logic of an application can inject a Persistence Unit (via annotation: @PersistenceUnit) and use it to to gain access to a database table which automatically maps that table to a JPA entity, easing accessing to the database table:

Example annotation to inject a persistent unit:
(as used in the business logic/java code of all of the EJBs and Servlets in this sample)

@PersistenceUnit(unitName = "CustomerQueryDB2") EntityManagerFactory emf;

Its also important to understand the associations that are created in the contents of the persistence.xml:

Notice the persistent unit name, dataSource name and JPA entity name

Persistence.xml:<br /><br />&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"&gt;
&lt;persistence-unit name="CustomerQueryDB2"&gt;
&lt;jta-data-source&gt;jdbc/MyDataSourceDB2&lt;/jta-data-source&gt;
&lt;class&gt;myjpa.CustomerAcct&lt;/class&gt;
&lt;!-- exclude-unlisted-classes&gt;true&lt;/exclude-unlisted-classes --&gt;
&lt;properties&gt;
&lt;property name="openjpa.LockTimeout" value="30000" /&gt;
&lt;property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(foreignKeys=true,schemaAction='drop,add')" /&gt;
&lt;property name="openjpa.jdbc.TransactionIsolation" value="read-committed" /&gt;
&lt;property name="openjpa.Log" value="none" /&gt;
&lt;property name="openjpa.jdbc.UpdateManager" value="operation-order" /&gt;
&lt;/properties&gt;
&lt;/persistence-unit&gt;
&lt;/persistence&gt;

The dataSource in the Persistence Unit maps to the following dataSource stanza that is generated in server.xml:<br />
&lt;dataSource id='db2-MyDataSourceDB2' jdbcDriverRef='db2-driver'
jndiName='jdbc/MyDataSourceDB2' statementCacheSize='30' transactional='true'&gt;
&lt;properties.db2.jcc databaseName='${cloud.services.MyDataSourceDB2.connection.dbname}'
id='db2-MyDataSourceDB2-props' password='${cloud.services.MyDataSourceDB2.connection.password}'
portNumber='${cloud.services.MyDataSourceDB2.connection.port}'
serverName='${cloud.services.MyDataSourceDB2.connection.host}' user='${cloud.services.MyDataSourceDB2.connection.username}' /&gt;
&lt;/dataSource&gt;<br /><br />
&lt;library id='db2-library'&gt;
&lt;fileset dir='${server.config.dir}/lib' id='db2-fileset'
includes='db2jcc4.jar db2jcc_license_cu.jar' /&gt;
&lt;/library&gt;

&lt;jdbcDriver id='db2-driver' libraryRef='db2-library' /&gt;

5. Explanation of Auto-config

This application makes use of the auto-config capability of IBM Cloud OE Runtime.

The autoconfig capability generates the necessary dataSource stanza in the server.xml in order
to make the DB2 service bound to the application map to the backend database.

e.g. DataSource stanza automatically generated by autoconfig support in server.xml<br /><br />
&lt;library id='db2-library'&gt;
&lt;fileset dir='${server.config.dir}/lib' id='db2-fileset'
includes='db2jcc4.jar db2jcc_license_cu.jar' /&gt;
&lt;/library&gt;

&lt;jdbcDriver id='db2-driver' libraryRef='db2-library' /&gt;

&lt;dataSource id='db2-MyDataSourceDB2' jdbcDriverRef='db2-driver'
jndiName='MyDataSourceDB2' statementCacheSize='30' transactional='true'&gt;
&lt;properties.db2.jcc databaseName='${cloud.services.MyDataSourceDB2.connection.dbname}'
id='db2-MyDataSourceDB2-props' password='${cloud.services.MyDataSourceDB2.connection.password}'
portNumber='${cloud.services.MyDataSourceDB2.connection.port}'
serverName='${cloud.services.MyDataSourceDB2.connection.host}' user='${cloud.services.MyDataSourceDB2.connection.username}' /&gt;
&lt;/dataSource&gt;


6. Pushing the standalone war file

If you prefer to using the command line you can get the war file: JPABlueMixProject.war  and push the sample application using CF Commands, creating and binding the required services (dataSource in this case):

cf push jpa -p JPABlueMixProject.war<br />cf create-service SQLDB SQLDB_OpenBeta MyDataSourceDB2<br />cf bind-service jpa MyDataSourceDB2<br />(note this message comes out after bind service: "TIP: Use 'cf push' to ensure your env variable <br />changes take effect" )
cf push jpa -p JPABlueMixProject.war
<br />note: the plan name (e.g. "SQLDB_OpenBeta" for DB2) used in the <br />cf create-service command above, can <br />be found by issuing the CF MARKETPLACE command<br /><br /><strong style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 14px; line-height: 1.5em;"><strong>Now verify that the app is up and running ok<br /><br /></strong></strong>cf apps<br />name requested state instances memory disk urls<br />jpa started 0/1 512M 1G jpa.<b>ng.bluemix.net</b>

7. Running the Application

You can invoke it from a browser with the following URL: jpa.ng.bluemix.net/JPABlueMixProject
The home page looks like this:

JPA Sample

Note:
PopulateDB must be run before ListDB or CustomerCredit so that there is a database table to work with.

You can use the “Drop Table” button to drop the table and start all over again if you like

Have Fun!


Find

More stories
May 7, 2019

We’ve Moved! The IBM Cloud Blog Has a New URL

In an effort better integrate the IBM Cloud Blog with the IBM Cloud web experience, we have migrated the blog to a new URL: www.ibm.com/cloud/blog.

Continue reading

April 19, 2019

Reach Out to the IBM Cloud Development Teams on Slack

Get the help you need fast—directly from the IBM Cloud Development Teams and other users on Slack.

Continue reading

April 11, 2019

Permanent Redirect to cloud.ibm.com from console.bluemix.net

Starting on April 27, 2019, we will be turning on permanent redirects from bluemix.net to cloud.ibm.com. All of the same functionality that existed on bluemix.net is still available in cloud.ibm.com.

Continue reading