11 min read

JDO

Java Data Objects (JDO) is a complementing standard of accessing data from your data store using a standard interface-based abstraction model of persistence in java. The original JDO (JDO 1.0) specification is quite old and is based on Java Specification Request 12 (JSR 12). The current major version of JDO (JDO 2.0) is based on JSR 243. The original specifications were done under the supervision of Sun and starting from 2.0, the development of the API and the reference implementation happens as an Apache open-source project.

Why JDO?

We have been happily programming to retrieve data from relational stores using JDBC, and now the big question is do we need yet another standard, JDO? If you think that as software programmers you need to provide solutions to your business problems, it makes sense for you to start with the business use cases and then do a business analysis at the end of which you will come out with a Business Domain Object Model (BDOM). The BDOM will drive the design of your entity classes, which are to be persisted to a suitable data store. Once you design your entity classes and their relationship, the next question is should you be writing code to create tables, and persist or query data from these tables (or data stores, if there are no tables). I would like to answer ‘No’ for this question, since the more code you write, the more are the chances of making errors, and further, developer time is costly. Moreover, today you may write JDBC for doing the above mentioned “technical functionalities”, and tomorrow you may want to change all your JDBC to some other standard since you want to port your data from a relational store to a different persistence mechanism. To sum up, let us list down a few of the features of JDO which distinguishes itself from other similar frameworks.

  • Separation of Concerns: Application developers can focus on the BDOM and leave the persistence details (storage and retrieval) to the JDO implementation.
  • API-based: JDO is based on a java interface-based programming model. Hence all persistence behavior including most commonly used features of OR mapping is available as metadata, external to your BDOM source code. We can also Plug and Play (PnP) multiple JDO implementations, which know how to interact well with the underlying data store.
  • Data store portability: Irrespective of whether the persistent store is a relational or object-based file, or just an XML DB or a flat file, JDO implementations can still support the code. Hence, JDO applications are independent of the underlying database.
  • Performance: A specific JDO implementation knows how to interact better with its specific data store, which will improve performance as compared to developer written code.
  • J2EE integration: JDO applications can take advantage of J2EE features like EJB and thus the enterprise features such as remote message processing, automatic distributed transaction coordination, security, and so on.

JPOX—Java Persistent Objects

JPOX is an Apache open-source project, which aims at a heterogeneous persistence solution for Java using JDO. By heterogeneous we mean, JPOX JDO will support any combination of the following four main aspects of persistence:

  • Persistence Definition: The mechanism of defining how your BDOM classes are to be persisted to the data store.
  • Persistence API: The programming API used to persist your BDOM objects.
  • Query Language: The language used to find objects due to certain criteria.
  • Data store: The underlying persistent store you are persisting your objects to.

JDO Sample Using JPOX

In this sample, we will take the familiar Order and LineItems scenario, and expand it to have a JDO implementation. It is assumed that you have already downloaded and extracted the JPOX libraries to your local hard drive.

BDOM for the Sample

We will limit our BDOM for the sample discussion to just two entity classes, that is, OrderList and LineItem. The class attributes and relationships are shown in the following screenshot:

Java Data Objects and Service Data Objects in SOA

The BDOM illustrates that an Order can contain multiple line items. Conversely, each line item is related to one and only one Order.

Code BDOM Entities for JDO

The BDOM classes are simple entity classes with getter and setter methods for each attribute. These classes are then required to be wired for JDO persistence capability in a JDO specific configuration file, which is completely external to the core entity classes.

OrderList.java

OrderList is the class representing the Order, and is having a primary key attribute that is number.

public class OrderList{ 
  private int number; 
  private Date orderDate; 
  private Set lineItems; 
  // other getter & setter methods go here 
  // Inner class for composite PK 
 public static class Oid implements Serializable{ 
  public int number; 
  public Oid(){ 
  } 
  public Oid(int param){ 
   this.number = param; 
  } 
  public String toString(){
   return String.valueOf(number); 
  } 
  public int hashCode(){ 
   return number; 
  } 
  public boolean equals(Object other){ 
   if (other != null && (other instanceof Oid)){ 
     Oid k = (Oid)other; 
     return k.number == this.number; 
   } 
    return false; 
  } 
 }
}

LineItem.java

LineItem represents each item container in the Order. We don’t explicitly define a primary key for LineItem even though JDO will have its own mechanism to do that.

public class LineItem{ 
  private String productId; 
  private int numberOfItems; 
  private OrderList orderList; 
  // other getter & setter methods go here
}

package.jdo

JDO requires an XML configuration file, which defines the fields that are to be persisted and to what JDBC or JDO wrapper constructs should be mapped to. For this, we can create an XML file called package.jdo with the following content and put it in the same directory where we have the entities.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jdo SYSTEM "file:/javax/jdo/jdo.dtd">
<jdo> 
  <package name="com.binildas.jdo.jpox.order"> 
    <class name="OrderList" identity-type="application" 
      objectid-class="OrderList$Oid" table="ORDERLIST"> 
   <field name="number" primary-key="true"> 
    <column name="ORDERLIST_ID"/> 
   </field> 
   <field name="orderDate">
   <column name="ORDER_DATE"/> 
   </field> 
   <field name="lineItems" persistence-modifier="persistent" mapped-by="orderList"> 
    <collection element-type="LineItem"> 
   </collection> 
  </field> 
  </class> 
   <class name="LineItem" table="LINEITEM"> 
     <field name="productId"> 
      <column name="PRODUCT_ID"/> 
    </field> 
      <field name="numberOfItems"> 
      <column name="NUMBER_OF_ITEMS"/> 
     </field> 
     <field name="orderList" persistence-modifier="persistent"> 
      <column name="LINEITEM_ORDERLIST_ID"/> 
    </field> 
   </class> 
 </package>
</jdo>

jpox.PROPERTIES

In this sample, we will persist our entities to a relational database, Oracle. We specify the main connection parameters in jpox.PROPERTIES file.

javax.jdo.PersistenceManagerFactoryClass=org.jpox.jdo.JDOPersistenceManagerFactory
javax.jdo.option.ConnectionDriverName=oracle.jdbc.driver.OracleDriver
javax.jdo.option.ConnectionURL=jdbc:oracle:thin:@127.0.0.1:1521:orcl
javax.jdo.option.ConnectionUserName=scott
javax.jdo.option.ConnectionPassword=tiger
org.jpox.autoCreateSchema=true
org.jpox.validateTables=false
org.jpox.validateConstraints=false

Main.java

This class contains the code to test the JDO functionalities. As shown here, it creates two Orders and adds few line items to each order. First it persists these entities and then queries back these entities using the id.

public class Main{ 
  static public void main(String[] args){ 
   Properties props = new Properties(); 
   try{ 
    props.load(new FileInputStream("jpox.properties")); 
      } 
     catch (Exception e){ 
       e.printStackTrace(); 
      } 
      PersistenceManagerFactory pmf = 
      JDOHelper.getPersistenceManagerFactory(props); 
      PersistenceManager pm = pmf.getPersistenceManager(); 
      Transaction tx = pm.currentTransaction(); 
      Object id = null; 
      try{ 
	  tx.begin(); 
	  LineItem lineItem1 = new LineItem("CD011", 1); 
	  LineItem lineItem2 = new LineItem("CD022", 2); 
	  OrderList orderList = new OrderList(1, new Date()); 
	 orderList.getLineItems().add(lineItem1); 
	 orderList.getLineItems().add(lineItem2); 
	 LineItem lineItem3 = new LineItem("CD033", 3); 
	 LineItem lineItem4 = new LineItem("CD044", 4); 
	 OrderList orderList2 = new OrderList(2, new Date()); 
	 orderList2.getLineItems().add(lineItem3); 
	 orderList2.getLineItems().add(lineItem4); 
	 pm.makePersistent(orderList); 
	 id = pm.getObjectId(orderList); 
	 System.out.println("Persisted id : "+ id); 
	 pm.makePersistent(orderList2); 
	 id = pm.getObjectId(orderList2); 
	 System.out.println("Persisted id : "+ id); 
	 orderList = (OrderList) pm.getObjectById(id); 
	 System.out.println("Retreived orderList : " + orderList); 
	 tx.commit();
        } 
	 catch (Exception e){ 
	   e.printStackTrace(); 
           if (tx.isActive()){ 
		tx.rollback(); 
	    } 
	  } 
	   finally{ 
	    pm.close(); 
         }  
     }
}

Build and Run the JDO Sample

You can download the required code for this article from http://www.packtpub.com/files//code/3216_Code.zip. Unzip the file and the code of our interest is in the folder 3216_04_Code. There is also a README.txt file, which gives detailed steps to build and run the samples.

Since we use Oracle to persist entities, we need the following two libraries in the classpath:

  • jpox-rdbms*.jar
  • classes12.jar

We require a couple of other libraries too which are specified in the build.xml file. Download these libraries and change the path in examples.PROPERTIES accordingly.

To build the sample, first bring up your database server. Then to build the sample in a single command, it is easy for you to go to ch04jdo folder and execute the following command.

cd ch04jdo
ant

The above command will execute the following steps:

  • First it compiles the java source files
  • Then for every class you persist, use JPOX libraries to enhance the byte code.
  • As the last step, we create the required schema in the data store.

Java Data Objects and Service Data Objects in SOA

To run the sample, execute:

ant run

You can now cross check whether the entities are persisted to your data store. This is as shown in the following screenshot where you can see that each line item is related to the parent order by the foreign key.

Java Data Objects and Service Data Objects in SOA

 

Data Services

Good that you now know how to manage the basic data operations in a generic way using JDO and other techniques. By now, you also have good hands-on experience in defining and deploying web services. We all appreciate that web services are functionalities exposed in standard, platform, and technology neutral way. When we say functionality we mean the business use cases translated in the form of useful information. Information is always processed out of data. So, once we retrieve data, we need to process it to translate them into information.

When we define SOA strategies at an enterprise level, we deal with multiple Line of Business (LOB) systems; some of them will be dealing with the same kind of business entity. For example, a customer entity is required for a CRM system as well as for a sales or marketing system. This necessitates a Common Data Model (CDM), which is often referred to as the Canonical Data Model or Information Model. In such a model, you will often have entities that represent “domain” concepts, for example, customer, account, address, order, and so on. So, multiple LOB systems will make use of these domain entities in different ways, seeking different information-based on the business context. OK, now we are in a position to introduce the next concept in SOA, which is “Data Services”.

Data Services are specialization of web services which are data and information oriented. They need to manage the traditional CRUD (Create, Read, Update, and Delete) operations as well as a few other data functionalities such as search and information modeling. The Create operation will give you back a unique ID whereas Read, Update, and Delete operations are performed on a specific unique ID. Search will usually be done with some form of search criteria and information modeling, or retrieval happens when we pull useful information out of the CDM, for example, retrieving the address for a customer.

The next important thing is that no assumptions should be made that the data will be in a java resultset form or in a collection of transfer object form. Instead, you are now dealing with data in SOA context and it makes sense to visualize data in XML format. Hence, XML Schema Definition (XSDs) can be used to define the format of your requests and responses for each of these canonical data definitions. You may also want to use ad hoc queries using XQuery or XPath expressions, similar to SQL capabilities on relational data. In other words, your data retrieval and data recreation for information processing at your middle tier should support XML tools and mechanisms, and should also support the above six basic data operations. If so, higher level of abstractions in the processing tier can make use of the above data services to provide Application Specialization capabilities, specialized for the LOB systems. To make the concept clear, let us assume that we need to get the order status for a particular customer (getCustomerOrderStatus()) which will take the customer ID argument. The data services layer will have a retrieve operation passing the customer ID and the XQuery or the XPath statement will obtain the requested order information from the retrieved customer data. High level processing layers (such as LOB service tiers) can use high-level interface (for example, our getCustomerOrderStatus operation) of the Application Specialization using a web services (data services) interface and need not know or use XQuery or XPath directly. The underlying XQuery or XPath can be encapsulated, reused, and optimized.

LEAVE A REPLY

Please enter your comment!
Please enter your name here