XML Beans Example
- I selected XML Beans for a closer look, although it appears that Castor currently has a larger “mindshare” than XML Beans
- However, with most of these frameworks, your workflow looks like this:
- Write an XML Scheme defining the types of your objects
- Run the data binding framework's schema compiler to produce Java source code
- Compile that source code and place it in a .jar file
- Place that .jar file into your classpath and use it to read and write XML documents based on that schema
- I wrote the following schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://openuri.org/addressBook"
targetNamespace="http://openuri.org/addressBook"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:complexType name="addressType">
<xs:sequence>
<xs:element name="streetInfo" type="xs:string" minOccurs="1" maxOccurs="3"/>
<xs:element name="city" type="xs:string" />
<xs:element name="state" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="postalCode" type="xs:string" />
<xs:element name="country" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="personType">
<xs:sequence>
<xs:element name="name" type="xs:string" />
<xs:element name="address" type="tns:addressType" />
<xs:element name="phone" type="xs:string" />
<xs:element name="dateOfBirth" type="xs:date" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="entryType">
<xs:sequence>
<xs:element name="person" type="tns:personType" />
<xs:element name="creationDate" type="xs:dateTime" />
<xs:element name="modificationDate" type="xs:dateTime" />
</xs:sequence>
<xs:attribute name="id" type="xs:integer" use="required" />
</xs:complexType>
<xs:complexType name="addressBookType">
<xs:sequence>
<xs:element name="entry" type="tns:entryType" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:element name="addressBook" type="tns:addressBookType" />
</xs:schema>
- This schema defines the following types:
- Postal Address
- Person
- Entry
- Address Book
- The XML Beans schema compiler produced a self-contained .jar file that allowed me to write a java program that looks like this:
import java.io.File;
import org.apache.xmlbeans.*;
import org.openuri.addressBook.*;
public class addressBook {
public static void main(String[] args) throws Exception {
File xmlFile = new File("addressBook.xml");
// Bind the instance to the generated XMLBeans types.
AddressBookDocument abDoc = AddressBookDocument.Factory.parse(xmlFile);
AddressBookType ab = abDoc.getAddressBook();
EntryType[] entries = ab.getEntryArray();
for (int i = 0; i < entries.length; i++) {
EntryType e = entries[i];
int id = e.getId().intValue();
PersonType p = e.getPerson();
String name = p.getName();
System.out.println("Entry " + id + ": " + name);
}
}
}
- When applied to this XML document...
<?xml version="1.0" encoding="UTF-8"?>
<addressBook
xmlns="http://openuri.org/addressBook"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://openuri.org/addressBook addressBook.xsd">
<entry id="0">
<person>
<name>Kenneth M. Anderson</name>
<address>
<streetInfo>Department of Computer Science</streetInfo>
<streetInfo>University of Colorado</streetInfo>
<streetInfo>430 UCB</streetInfo>
<city>Boulder</city>
<state>CO</state>
<postalCode>80309-0430</postalCode>
<country>USA</country>
</address>
<phone>+1 (303) 492-6003</phone>
<dateOfBirth>1968-08-25</dateOfBirth>
</person>
<creationDate>2006-04-28T12:15:00</creationDate>
<modificationDate>2006-04-28T12:15:00</modificationDate>
</entry>
<entry id="1">
<person>
<name>Leysia Palen</name>
<address>
<streetInfo>Department of Computer Science</streetInfo>
<streetInfo>University of Aarhus</streetInfo>
<streetInfo>IT-parken, Aabogade 34</streetInfo>
<city>Aarhus N</city>
<postalCode>DK-8200</postalCode>
<country>Denmark</country>
</address>
<phone>+45 8942 5617</phone>
<dateOfBirth>1968-05-21</dateOfBirth>
</person>
<creationDate>2006-04-28T13:04:00</creationDate>
<modificationDate>2006-04-28T13:04:00</modificationDate>
</entry>
</addressBook>
- the above program produces the following output:
Entry 0: Kenneth M. Anderson
Entry 1: Leysia Palen
- I will return to XML Beans during my Axis 2 example
Axis 2: Example
- AddressBook Service (builds on XML Beans Example)
- Developed a Web Service with the following operations:
- addEntry
- getEntry
- getEntries
- numEntries
- removeEntries
- updateEntry
- Each operation expects an OMElement and returns an OMElement. OMElement is part of Axis2's AXIOM object model that makes it straightforward to process SOAP message bodies. For many of the operations, I just use AXIOM to read the input and generate the output; on some of the operations, however, I convert the OMElement into an XML Beans representation and then use the XML Beans API to manipulate and persist the address book
- A service is described via the creation of a services.xml file. My services.xml file contains the following information:
<?xml version="1.0" encoding="utf-8"?>
<service name="addressBook" scope="application">
<description>
This service provides operations over an address book. You can
create, update, and retrieve entries.
</description>
<parameter name="ServiceClass"
locked="false">addressBook.addressBook</parameter>
<parameter name="addressBookDir" locked="false">
/Users/kena/java/tomcat5/webapps/axis2/WEB-INF/addressBook
</parameter>
<operation name="addEntry">
<messageReceiver
class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver" />
</operation>
<operation name="numEntries">
<messageReceiver
class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver" />
</operation>
<operation name="getEntries">
<messageReceiver
class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver" />
</operation>
<operation name="getEntry">
<messageReceiver
class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver" />
</operation>
<operation name="removeEntry">
<messageReceiver
class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver" />
</operation>
<operation name="updateEntry">
<messageReceiver
class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver" />
</operation>
</service>
- This file describes a single service. It provides a description and indicates the name of the class that implements this service. It defines a parameter that is used by the service to locate its persistent information and then it defines each of the operations listed above, identifying each operation as supporting standard RPC semantics via XML messages (e.g. SOAP over HTTP implementing an RPC message pattern).
- This file, the class that implements the service and anything else needed by the service is packaged into a .aar file which is simply a .jar file that has been renamed to have the .aar extension. This service file is then placed in the Axis2 services directory; the Axis2 runtime will automatically detect the new .aar file, read it, and make the service available via its host application server.
- I will provide more details about this example during lecture
- Limitations of current example:
- The index attribute of Entries are ignored (operations use position-based semantics)
- No error handling, or worse, inconsistent handling of errors
- No ability to search entries by content (e.g. you can't search for “Ken Anderson”)
- Address book does not detect or handle duplicate entries