ONJava.com -- The Independent Source for Enterprise Java  
oreilly.comSafari Books Online.Conferences.
 

Returning XMLBeans from a Database Control

by Steve Hanson
01/08/2004
Content provided by BEA Systems

When working with database controls you may have asked yourself, "What sort of data type should this database control return?" This is an important question because not every consumer of a database control can consume every data type. Your database control cannot pass a RowSet to a Web service, because these data types are not supported over SOAP. Nor can it pass a ResultSet or Iterator to a page flow, because these data objects are always closed by the time they reach the Web tier.

So what sort of data types are universally consumable by both Web services, page flows, and other Workshop components? Two kinds of data types fit the bill: custom Java Arrays and XMLBeans. The following article shows you how to create database controls that provide data as XMLBean types. Casting database data as XMLBeans has two primary advantages: (1) XMLBeans are consumable by all Workshop components, and (2) data in XMLBean form is very flexible and easy to work with.

What Is an XMLBean?

An XMLBean is essentially an XML document with a Java API attached to it. The API is used for parsing and manipulating the data in the XML document. A typical XMLBean might represent database data in the following form.

<!DOCTYPE XCustomer>
<XCustomer xmlns="java:///database/customer_db"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <XCustomerRow>
        <CUSTID>1</CUSTID>
        <NAME>Fred Williams</NAME>
        <ADDRESS>123 Slugger Circle</ADDRESS>
    </XCustomerRow>
    <XCustomerRow>
        <CUSTID>2</CUSTID>
        <NAME>Marnie Smithers</NAME>
        <ADDRESS>5 Hitchcock Lane</ADDRESS>
    </XCustomerRow>
    <XCustomerRow>
        <CUSTID>3</CUSTID>
        <NAME>Bill Walton</NAME>
        <ADDRESS>655 Tall Timbers Road</ADDRESS>
    </XCustomerRow>
</XCustomer>

The data can be accessed and manipulated using the XMLBean's API. For example, assume that custBean represents the XML document above. The following Java code extracts the Fred Williams from the document.

String name = custBean.getXCustomer().getXCustomerRowArray(1).getNAME();

Retrofitting database controls to return XMLBeans rather than RowSets, ResultSets, or Iterators, is a powerful technique because there are few restrictions on where XMLBeans can be imported. This is not the case with ResultSets and Iterators, which cannot be passed directly to Web tier classes (Web services and page flows). Also, data in XMLBean form is very easy to manipulate because there is a rich API attached to the XMLBean.

Creating a Schema

The first step in using XMLBean classes is creating a schema from which the XMLBean classes can be generated. The schema you create for a database control must be capable of modeling the sorts of data returned from the database.

If you write your own schema, at a minimum, the schema's elements should have the same names as the fields in the database, which allows data returned from the database to be automatically mapped into the XMLBean.

To autogenerate a schema for a database or RowSet control, follow this procedure.

  1. Display the database control file in Design View.

  2. 2. Select a method that returns data from the database. (A method that does not return data, such as a CREATE TABLE statement will not work.)

  3. On the Properties Editor tab, in the section labeled sql, select the property named rowset-name.

  4. Enter a RowSet name. (The name you enter will become part of the schema, and the XMLBean classes derived from the schema.)

  5. Select and copy the schema text from the Edit RowSet Schema dialog. (The dialog does not support right-clicking, you must use Ctrl+C to copy the schema text.) Note that XCustomer appears in the schema in two places:

    <xsd:element name="XCustomer" ...
        
    <xsd:element name="XCustomerRow">

    Click for larger view
    (You can click on the screen shot to open a full-size view.)

  6. Cancel out of the dialog and save the schema text in an XSD file in a Schemas project. Make sure that the XSD file begins with the element <?xml version="1.0"?>.

    Click for larger view
    (You can click on the screen shot to open a full-size view.)

When the XSD file is compiled, XMLBean types are generated that can be returned by the methods in the database control. The XMLBean classes appear in the Schema project's XML Bean Classes folder.

Editing Schemas to Create New "Document" Types

Note that only one of the generated types is a "Document" XMLBean type: XCustomerDocument. The other types, XCustomerDocument.XCustomer and XCustomerDocument.XCustomer.XCustomerRow, can only be used with reference to the "Document" type. This distinction is especially important because only "Document" types are eligible for direct participation in a business process, or to be passed to a Web service. For this reason you may want to edit your schema to include "Document" types corresponding to other types in the Schema, especially if you have a very large schema with many nested types defined in terms of a single "Document" type.

To generate a new Document type for some element, move that element so that it becomes a top-level element in the schema. In the following example, the XCustomerRow element has been moved to the top-level of the schema: its original position has been replaced with a reference element: <xsd:element ref="XCustomerRow"/>.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
  targetNamespace="java:///database/customer_db" 
  xmlns="java:///database/customer_db" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns:wld="http://www.bea.com/2002/10/weblogicdata" 
  elementFormDefault="qualified" 
  attributeFormDefault="unqualified">
   <xsd:element name="XCustomer" 
     wld:DefaultNamespace="java:///database/customer_db" 
     wld:RowSet="true">
     <xsd:complexType>
      <xsd:choice maxOccurs="unbounded">
       <xsd:element ref="XCustomerRow"/>
      </xsd:choice>
     </xsd:complexType>
   </xsd:element>
    <xsd:element name="XCustomerRow">
      <xsd:complexType>
        <xsd:sequence>
          <xsd:element name="CUSTID" type="xsd:int" wld:JDBCType="INTEGER" 
            minOccurs="0" wld:TableName="WEBLOGIC.CUSTOMER" nillable="true"></xsd:element>
          <xsd:element name="NAME" type="xsd:string" wld:JDBCType="VARCHAR" 
            minOccurs="0" wld:TableName="WEBLOGIC.CUSTOMER" nillable="true"></xsd:element>
          <xsd:element name="ADDRESS" type="xsd:string" wld:JDBCType="VARCHAR" 
            minOccurs="0" wld:TableName="WEBLOGIC.CUSTOMER" nillable="true"></xsd:element>
          <xsd:element name="CITY" type="xsd:string" wld:JDBCType="VARCHAR" 
            minOccurs="0" wld:TableName="WEBLOGIC.CUSTOMER" nillable="true"></xsd:element>
          <xsd:element name="STATE" type="xsd:string" wld:JDBCType="CHAR" 
            minOccurs="0" wld:TableName="WEBLOGIC.CUSTOMER" nillable="true"></xsd:element>
          <xsd:element name="ZIP" type="xsd:string" wld:JDBCType="VARCHAR" 
            minOccurs="0" wld:TableName="WEBLOGIC.CUSTOMER" nillable="true"></xsd:element>
          <xsd:element name="AREA_CODE" type="xsd:string" wld:JDBCType="CHAR" 
            minOccurs="0" wld:TableName="WEBLOGIC.CUSTOMER" nillable="true"></xsd:element>
          <xsd:element name="PHONE" type="xsd:string" wld:JDBCType="CHAR" 
            minOccurs="0" wld:TableName="WEBLOGIC.CUSTOMER" nillable="true"></xsd:element>
        </xsd:sequence>
        <xsd:anyAttribute namespace="http://www.bea.com/2002/10/weblogicdata" 
          processContents="skip"></xsd:anyAttribute>
      </xsd:complexType>
    </xsd:element>
</xsd:schema>

There are now two top-level elements, XCustomer and XCustomerRow, which compile into two corresponding "Document" types: XCustomerDocument and XCustomerRowDocument.

Returning a XMLBean Types from Control Methods

Once you have generated XMLBean types that model the database data, you can import these types into your database control.

import databaseCustomerDb.XCustomerDocument;
import databaseCustomerDb.XCustomerDocument.XCustomer;
import databaseCustomerDb.XCustomerDocument.Factory;

XMLBean types can be returned from the control's methods.


/**
  * @jc:sql statement="SELECT custid, name, address FROM customer" 
  */
  public XCustomerDocument findAllCustomersDoc(); 

The data returned from the query is automatically mapped into the XMLBean because the names of the database fields match the fields of the XMLBean.

Related Topics

Steve Hanson has been working on the WebLogic Workshop documentation team since 2002. Before he began his tech writing career, he was an instructor in Philosophy at the University of Washington. When he isn't working on J2EE, Steve is working on his dissertation on Aristotle's biology.


Return to ONJava.com