Service Data Object (SDO) 2.0 is an open standard data model programming API that allows the developer to easily manipulate data at a high level. Although SDO 1.0 aims at the same data abstraction goal, it has several major drawbacks, the main one being a lack of helper classes, such as XSDHelper, XMLHelper, and so on. The end result is that the developer is forced to utilize the SDO 1.0 implementation APIs, which come from Eclipse Modeling Framework (EMF) SDK.
The current implementation, SDO 2.0, uses EMF 2.2 SDK, but that is an SDO 2.0 implementation detail that does not impact the developer writing to the new API. In the future, the open source community, through the Apache Software Foundation, may decide to provide a different implementation of SDO 2.0., but that should not affect the applications built upon SDO 2.0 APIs.
The most basic way to see the advantages of the new API is to use SDO 2.0 to create and then read an XML document compliant to XML Schema (XSD). To accomplish the same goal without using the SDO 2.0 would require the developer to understand how the XML parser works and tightly integrate the data parsing logic with the application. Later, if the XSD needs to change, the application would need to be touched everywhere, which would jeopardize the quality of the code.
It's difficult for new users of SDO 2.0 APIs to comprehend the concept by simply studying the specification. To help, I created an example from the XML Schema Primer (see Resources) to explain how SDO 2.0 APIs are used to:
- Write an XML document to the disk, and
- Read it back.
Scenario: purchase order information collection and delivery
Here's the usage scenario we will try to realize with our example. First, the company determines the requirements for purchase order (PO) information. Once that is done, we start creating a static form to structure the information. In the database, that static form is the table schema. In XML, that static form is the XML Schema (XSD). Later on, if additional customer information needs to be collected, we will need to redesign the form/table schema/XSD.
When placing an order, the customer needs to fill out a PO form or give the same information to the operator for filling out the form. The information in the form will then be used by the company to deliver the order.
After the company receives the PO information, it would most likely save it and then read it for the purpose of, say, customer support. In this example, we can save the information in XML format and then read it using SDO APIs.
Figure 1 shows a sample of PO information collected from customer Robert Smith. An XSD file will be created to structure this sample purchase order. A sample program called CreatePurchaseOrder.java is used to create the sample PO in XML format called po.xml. Finally, ReadPurchaseOrder.java is used to demonstrate how to read order information from the po.xml.
Figure 1. Sample purchase order information from Robert Smith
| Order date: 1999-10-20
Shipping information: Billing information: Order Items: 2. Part number: 926-AA Comment: Hurry, my lawn is going wild! |
Based on the sample purchase order shown in Figure 1, a PO type can be used to represent the order. Letâs call it PurchaseOrderType. The instance of PurchaseOrderType may contain four major data, as follows:
shipping informationbilling informationorder items informationcomment
The shipping and billing information may contain more data, such as name, street, city, state, zip, and country. Order items information may contain many information about items purchased by the customer. Each item may contain part number, product name, quantity, price, ship date, and comment. The comment area of the PO accommodates a string value without requiring more structured information.
Listing 1 shows all the purchase order information in a file structured in XSD format.
Listing 1. PO.xsd
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.example.com/PO" targetNamespace="http://www.example.com/PO">
<xsd:element name="purchaseOrder" type="PurchaseOrderType"/>
<xsd:element name="comment" type="xsd:string"/>
<xsd:complexType name="PurchaseOrderType">
<xsd:sequence>
<xsd:element name="shipTo" type="USAddress"/>
<xsd:element name="billTo" type="USAddress"/>
<xsd:element ref="comment" minOccurs="0"/>
<xsd:element name="items" type="Items"/>
</xsd:sequence>
<xsd:attribute name="orderDate" type="xsd:date"/>
</xsd:complexType>
<xsd:complexType name="USAddress">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="street" type="xsd:string"/>
<xsd:element name="city" type="xsd:string"/>
<xsd:element name="state" type="xsd:string"/>
<xsd:element name="zip" type="xsd:decimal"/>
</xsd:sequence>
<xsd:attribute name="country" type="xsd:NMTOKEN" fixed="US"/>
</xsd:complexType>
<xsd:complexType name="Items">
<xsd:sequence>
<xsd:element name="item" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="productName" type="xsd:string"/>
<xsd:element name="quantity">
<xsd:simpleType>
<xsd:restriction base="xsd:positiveInteger">
<xsd:maxExclusive value="100"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="USPrice" type="xsd:decimal"/>
<xsd:element ref="comment" minOccurs="0"/>
<xsd:element name="shipDate" type="xsd:date" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="partNum" type="SKU" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="SKU">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d{3}-[A-Z]{2}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
|
You can also use the Unified Modeling Language (UML) class diagram to structure the purchase order information, as shown in Figure 2.
Figure 2. UML class diagram of purchase order

The XSD po.xsd file and the UML class diagram differ in the following ways:
- The class diagram defines
ItemType, which is not defined inpo.xsd.diagram. Althoughpo.xsddidnât defineItemTypespecifically, the XSD specification handlesItemTypeas an anonymous type. - All
xsd:<type>in XSD has been abbreviated to become<type>in the class diagram. In XSD, the xsd in the pattern ofxsd:<type>is used to indicate the namespace to which the type belongs. In the class diagram, it was taken out for simplicity. SKU typeis not defined in the class diagram.SKU typeis in fact a normalized string type defined in theponamespace. In the class diagram, it is represented bystring type.
The sample program CreatePurchaseOrder.java shown in Listing 2 creates a PO in XML format called po.xml, shown in Listing 3.
Listing 2. CreatePurchaseOrder.java
/**
* Author: Fuhwei Lwo
*/
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.OutputStream;
import commonj.sdo.DataObject;
import commonj.sdo.helper.DataFactory;
import commonj.sdo.helper.XMLHelper;
import commonj.sdo.helper.XSDHelper;
public class CreatePurchaseOrder {
private static final String PO_MODEL = "po.xsd";
private static final String PO_NAMESPACE = "http://www.example.com/PO";
private static final String PO_XML = "po.xml";
private static void definePOTypes() throws Exception {
FileInputStream fis = new FileInputStream(PO_MODEL);
XSDHelper.INSTANCE.define(fis, null);
fis.close();
}
public static void main(String[] args) throws Exception {
definePOTypes();
DataObject purchaseOrder =
DataFactory.INSTANCE.create(PO_NAMESPACE, "PurchaseOrderType");
purchaseOrder.setString("orderDate", "1999-10-20");
DataObject shipTo = purchaseOrder.createDataObject("shipTo");
shipTo.set("country", "US");
shipTo.set("name", "Alice Smith");
shipTo.set("street", "123 Maple Street");
shipTo.set("city", "Mill Valley");
shipTo.set("state", "CA");
shipTo.setString("zip", "90952");
DataObject billTo = purchaseOrder.createDataObject("billTo");
billTo.set("country", "US");
billTo.set("name", "Robert Smith");
billTo.set("street", "8 Oak Avenue");
billTo.set("city", "Mill Valley");
billTo.set("state", "PA");
billTo.setString("zip", "95819");
purchaseOrder.set("comment", "Hurry, my lawn is going wild!");
DataObject items = purchaseOrder.createDataObject("items");
DataObject item1 = items.createDataObject("item");
item1.set("partNum", "872-AA");
item1.set("productName", "Lawnmower");
item1.setInt("quantity", 1);
item1.setString("USPrice", "148.95");
item1.set("comment", "Confirm this is electric");
DataObject item2 = items.createDataObject("item");
item2.set("partNum", "926-AA");
item2.set("productName", "Baby Monitor");
iteim2.setInt("quantity", 1);
item2.setString("USPrice", "39.98");
item2.setString("shipDate", "1999-05-21");
OutputStream stream = new FileOutputStream(PO_XML);
XMLHelper.INSTANCE.save(purchaseOrder, PO_NAMESPACE, "purchaseOrder", stream);
}
}
|
Listing 3. Po.xml
<?xml version="1.0" encoding="ASCII"?>
<po:purchaseOrder xmlns:po="http://www.example.com/PO" orderDate="1999-10-20">
<shipTo country="US">
<name>Alice Smith</name>
<street>123 Maple Street</street>
<city>Mill Valley</city>
<state>CA</state>
<zip>90952</zip>
</shipTo>
<billTo country="US">
<name>Robert Smith</name>
<street>8 Oak Avenue</street>
<city>Mill Valley</city>
<state>PA</state>
<zip>95819</zip>
</billTo>
<comment>Hurry, my lawn is going wild!</comment>
<items>
<item partNum="872-AA">
<productName>Lawnmower</productName>
<quantity>1</quantity>
<USPrice>148.95</USPrice>
<comment>Confirm this is electric</comment>
</item>
<item partNum="926-AA">
<productName>Baby Monitor</productName>
<quantity>1</quantity>
<USPrice>39.98</USPrice>
<shipDate>1999-05-21</shipDate>
</item>
</items>
</po:purchaseOrder>
|
The sample Java program first registers all types described in po.xsd with an SDO runtime by calling XSDHelper.INSTANCE.define() method. It then creates a root DataObject out of the PurchaseOrderType. From there, it uses DataObject APIs to build the DataObject tree representing the purchase order information, shown in Figure 3.
Figure 3. DataObject tree

In Figure 3, each rectangular box has two compartments. The top compartment (with gray color) indicates the DataObject instance name and its real type; the bottom compartment indicates the contained properties. For example, the root object of the tree is the purchaseOrder DataObject instance; its real type is PurchaseOrderType, defined in PO.xsd in Listing 1. In this DataObject instance, it contains two property values â orderDate and comment.
After creating the DataObject tree, the program invokes the XMLHelper.INSTANCE.save() method to save the contents of the tree starting from the purchaseOrder DataObject instance to an XML document, in this case, po.xml. In fact, you can specify any DataObject instance from the tree as the first parameter of XMLHelper.INSTANCE.save() method and the save() method will save all DataObject instances from the one you specified.
After CreatePurchaseOrder.java creates po.xml, we can compile and run ReadPurchaseOrder.java, shown in Listing 4 to demonstrate using SDO APIs to traverse the contents of po.xml. The application performs the following actions:
- Checks to be sure the types defined in
po.xsdwere registered with SDO runtime - Invokes
XMLHelper.load()method to loadpo.xmlto the memory which is represented by theXMLDocumentinstancexmlDoc - Invokes
xmlDoc.getRootObject()method to retrieve the root object of theDataObjecttree calledpurchaseOrder, which corresponds to thepurchaseOrder DataObjectin theDataObjecttree diagram shown in Figure 3 - After the
purchaseOrder DataObjectis returned, traverses theDataObjecttree to retrieve all the information about this PO
Listing 4. ReadPurchaseOrder.java
/**
/**
* Author: Fuhwei Lwo
*/
import java.io.FileInputStream;
import java.util.List;
import commonj.sdo.DataObject;
import commonj.sdo.helper.XMLDocument;
import commonj.sdo.helper.XMLHelper;
import commonj.sdo.helper.XSDHelper;
public class ReadPurchaseOrder {
private static final String PO_MODEL = "po.xsd";
private static final String PO_XML = "po.xml";
private static void definePOTypes() throws Exception {
FileInputStream fis = new FileInputStream(PO_MODEL);
XSDHelper.INSTANCE.define(fis, null);
fis.close();
}
public static void main(String[] args) throws Exception {
definePOTypes();
FileInputStream fis = new FileInputStream(PO_XML);
XMLDocument xmlDoc = XMLHelper.INSTANCE.load(fis);
DataObject purchaseOrder = xmlDoc.getRootObject();
System.out.println("Order date: " + purchaseOrder.get("orderDate"));
System.out.println("Comment: " + purchaseOrder.get("comment"));
DataObject shipTo = purchaseOrder.getDataObject("shipTo");
System.out.println("Ship to name: " + shipTo.get("name"));
DataObject billTo = purchaseOrder.getDataObject("billTo");
System.out.println("Bill to name: " + billTo.get("name"));
System.out.println();
DataObject items = purchaseOrder.getDataObject("items");
List itemList = items.getList("item");
for (int i=0; i<itemList.size(); i++) {
DataObject item = (DataObject)itemList.get(i);
System.out.println("Part num: " + item.get("partNum"));S
System.out.println("Product name: " + item.get("productName"));
} // for
}
}
|
System.out.println() in bold in Listing 4 displays the property values of various data objects including the following:
orderDateandcommentproperties of thepurchaseOrder DataObjectnameproperty of theshipTo DataObjectnameproperty of thebillTo DataObjectpartNumandproductNameproperties of various data objects
Figure 4. Console output of running ReadPurchaseOrder
| Order date: 1999-10-20
Comment: Hurry, my lawn is going wild! Part num: 872-AA Part num: 926-AA |
In figure 4, we can see the output of running the ReadPurchaseOrder Java code.
Conclusion: SDO to become de facto data model programming API
SDO 2.0 APIs provide a consistent way of creating and accessing data and shielding the developers from the underlined detailed implementation of parsing and maintaining data integrity. SDO 2.0 is currently an incubator subproject (called Tuscany) under the Apache Software Foundation that is intended become the de facto standard of data model programming APIs for SOA development. See the Resources section for a link.
As you can see from the examples above, the SDO 2.0 APIs completely shield you from knowing and using the XML parser APIs to read, write, and manipulate data. If you create the DataObject in Java representing the XML data in compliance with the XML Schema you define, SDO 2.0 gives you the convenience and flexibility to focus on how to use the data. As a result, it provides you the great benefits of increasing your development productivity and product quality.
In conclusion, using the data abstraction technology offered by SDO 2.0 allows you to treat your data according to whatever business logic you define to meet your business need. This helps you simplify your business application development and also increase your team's productivity and the quality of its work.
Learn
-
See the XML Schema Part 0: Primer Second Edition on the W3 Web site for a description of the XML Schema facilities, and to learn how to create schemas using the XML Schema language.
-
Read the Service Data Objects specification.
-
Learn more about the
Tuscany/SDO 2.0 project at Apache Software Foundation Web site.
- SOA and Web services -- hosts hundreds of informative articles and introductory, intermediate, and advanced tutorials on how to develop Web services applications.
Discuss
- developerWorks blogs -- get involved in the developerWorks community.






