Document Access Definition Extension (DADX) 1.0

Arthur Ryman
2001-10-03

Abstract

DADX is an XML technology for rapidly creating Web Services that access relational databases such as DB2 UDB. When combined with the DB2 XML Extender, DADX supports mapping relational data into complex XML documents and storing XML documents in the database. DADX consists of an XML document format and a Java runtime component that work with Apache SOAP 2.2 and that run on J2EE compliant application servers like WebSphere and Tomcat. To create a new Web Service, the developer authors SQL statements in a DADX document and deploys it to the application server. The DADX runtime executes SOAP requests sent to the new service and provides additional support including HTTP GET and POST bindings, test page and WSDL generation, and translation of DTD into XML Schema. This document describes the DADX document format and runtime.

Status

This document describes the beta version of the DADX. The DADX runtime supports DB2 UDB 7.2, DB2 XML Extender 7.2, and WebSphere 4.0 and requires Apache SOAP 2.2 and JDBC 2.0. The runtime works well with Tomcat but should also work with other J2EE application servers and JDBC 2.0 databases.

Table of Contents

Quick Tour

This section gives a quick tour of DADX using the SAMPLE database that comes with DB2. As our starting point let's assume that you have set up your application server and are now ready to create a Web Service that accesses the SAMPLE database.

In the tradition of programming languages, let's begin with the simplest possible DADX document, HelloSample0.dadx:
 
Listing of HelloSample0.dadx
<?xml version="1.0" encoding="UTF-8"?>
<DADX xmlns="http://schemas.ibm.com/db2/dxx/dadx">
  <operation name="listDepartments">
    <query>
      <SQL_query>SELECT * FROM DEPARTMENT</SQL_query>
    </query>
  </operation>
</DADX>

HelloSample0.dadx defines a Web Service with a single operation named listDepartment which simply lists the contents of the DEPARTMENT table. In general, the operations in a DADX Web Services can be defined by the following operators:

To deploy this Web Service, simply copy it to the application server. For this tour we have set up our application server on localhost:8080 and created a Web application named services. Within the services application, we have configured a group named sample to access the SAMPLE database.

Test Page

We can immediately test the new service by requesting the URL:
http://localhost:8080/services/sample/HelloSample0.dadx/TEST
which returns the following automatically generated documentation and test page:

TEST Page

To test the listDepartments operation, click its link in the Methods frame, then click the Invoke button in the Inputs frame. The XML result of the operation is displayed in the Result frame:

listDepartments Result
 

HTTP GET and POST Bindings

The test page acts as a simple HTML client of the Web Service and uses the HTTP POST binding. The Web Service can also be accessed using HTTP GET and SOAP bindings. The listDepartments operation can be invoked via the HTTP GET and POST bindings using the following URL:
http://localhost:8080/services/sample/HelloSample0.dadx/listDepartments
which returns an XML response document (listDepartments.xml). The difference between the HTTP GET and POST bindings is that with HTTP GET any input parameters to the operation are added to the URL but in HTTP POST the parameters are sent in the request body.

SOAP Binding

The SOAP binding also uses HTTP POST but the operation name, input parameters, and other information are sent as an XML request body. The URL for accessing the SOAP binding is:
http://localhost:8080/services/sample/HelloSample0.dadx/SOAP
The SOAP binding is useful for Java or JavaScript clients.

WSDL

You can request the WSDL document for the service (HelloSample0.wsdl) by the URL:
http://localhost:8080/services/sample/HelloSample0.dadx/WSDL
The WSDL document is automatically generated from the DADX document.

UDDI

When you register a Web Service in a UDDI Business Registry, the recommended best practice (Using WSDL in a UDDI Registry 1.02) is to split the WSDL document into a service instance document and a binding document. The service instance document contains the address at which the service is deployed and it imports the binding document. Many service instances might refer to a common binding document. The binding document is registered in UDDI as a reusable tModel.

You can request the WSDL service instance document (HelloSample0-service.wsdl) by the URL:

http://localhost:8080/services/sample/HelloSample0.dadx/WSDLservice
and the WSDL binding document (HelloSample0-binding.wsdl) by the URL:
http://localhost:8080/services/sample/HelloSample0.dadx/WSDLbinding

XML Schema

The data types used in the Web Service interface are defined using XML Schema. You can request the XML Schema definitions (HelloSample0.xsd) for the service by the URL:
http://localhost:8080/services/sample/HelloSample0.dadx/XSD
The DB2 XML Extender uses DTDs to define the schema of XML documents. The DADX runtime automatically translates DTD into XML Schema. For example, if an XML document was defined using the DTD order.dtd, then the following URL would returns its translation into XML Schema:
http://localhost:8080/services/sample/order.dtd/XSD

Documentation

You can include documentation in the DADX for the service as a whole and for each operation. HelloSample1.dadx illustrates how to add documentation:
 
Listing of HelloSample1.dadx
<?xml version="1.0" encoding="UTF-8"?>
<DADX
  xmlns="http://schemas.ibm.com/db2/dxx/dadx"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">

  <wsdl:documentation>
    Simple DADX example that access the SAMPLE database.
  </wsdl:documentation>

  <operation name="listDepartments">
    <wsdl:documentation>
      Lists the departments.
    </wsdl:documentation>
    <query>
      <SQL_query>SELECT * FROM DEPARTMENT</SQL_query>
    </query>
  </operation>

</DADX>

The documentation can contain any valid XML. For proper display in a browser, you should use XHTML. Now when you request the test page, the documentation is included:

Documentation

Automatic Reloading

During the course of development you are likely to make frequent changes to your DADX files. The DADX runtime allows you to make changes to your DADX files while the application server is running, and will automatically reload the new version. Automatic reloading makes developing DADX Web Services as simple as developing JavaServer Pages. You can turn off automatic reloading when you deploy your DADX Web Services to a production server.

What's Next

In this Quick Tour you have seen some of the productivity benefits of DADX. In the following sections the DADX document format and runtime will be explained in greater detail.

Introduction

The DB2 XML Extender (DXX) makes it easy to create XML applications using DB2 UDB. DXX consists of a set of stored procedures, user defined types (UDT) and user defined functions (UDF) that enable an application programmer to store and retrieve XML data using DB2. DXX allows XML documents to be stored intact, and optionally indexed in side tables, using the XML Column access method, or as a collection of relational tables using the XML Collection access method. DXX uses an XML document format called Document Access Definition (DAD) to define the mapping between XML and relational data.

Web Services are XML based application functions that can be invoked over the Internet. It is therefore natural to use DXX to implement Web Services. This document specifies an XML document format called DAD Extension (DADX) that makes it easy to create Web Services using DXX. A DADX document specifies how to create a Web Service using a set of operations that are defined by DAD documents and SQL statements. A Java component, the DxxInvoker, provides the runtime support for invoking DADX documents as Web Services in Apache Simple Object Access Protocol (SOAP) 2.2 which is supported by WebSphere Application Server 4.0 and other J2EE servlet engines such as Tomcat.

Design Goals

The design goals for DADX are:
  1. DADX lets developers easily create simple XML based Web Services that access DB2
  2. DADX lets developers be productive without the requirement for a knowledge of SOAP, WSDL, or UDDI
  3. DADX documents can be authored using a simple text editor, although this requires a knowledge of XML, SQL, and DXX
  4. DADX documents can be authored using tools provided in WebSphere Studio Application Developer with minimal knowledge of XML, SQL, and DXX
DXX is a collection of stored procedures, UTDs, and UDFs which are typically used in programs written in SQL, Java, C++, or other languages. Although this allows for maximum flexibility, it requires too much programming skill for simple applications. Ideally, it should be possible to use DXX with only a knowledge of SQL and XML. With the use of tools that assist in building SQL statements and defining the mapping from relational data to XML, the requirements for programming skill is reduced even further. Also, DXX support for XML makes it a natural choice for implementing Web Services. A DADX document must therefore contain enough information to invoke DXX and to describe the Web Service using WSDL.

DxxInvoker

A Java component, the DxxInvoker servlet, interfaces with the Apache SOAP runtime using the pluggable provider interface. The Web application developer creates an instance of DxxInvoker for each database that is to be accessed. Each instance of DxxInvoker is associated with a database connection and a group of DADX resources. The DxxInvoker servlet is a subclass of the Apache SOAP RPCRouterServlet and inherits all of its servlet init parameters which are described in the Apache SOAP documentation.

The database connection information for each group of DADX Web Services is specified in a group.properties file while is described in detail below. WebSphere Studio Application Developer includes tools for setting up groups of DADX Web Services.

The database administrator sets up the databases and enables them for use by DXX. The Web Service developer creates DAD and DADX documents and deploys them to the Web application. Each DADX document is associated with a URL that identifies the Web Service.

The web.xml File

For example, suppose that we wish to create Web Services that access the SALES_DB database that  is used in the DXX "Getting Started" tutorial. We create a Web application named services0 and define an instance of DxxInvoker named dxx_sales_db that accesses the SALES_DB database and handles requests to URLs of the form /sales/*. This information is specified by the following  J2EE web.xml file for the application:
 
Listing of web.xml
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">

<web-app>

    <servlet>
        <servlet-name>dxx_sales_db</servlet-name>
        <servlet-class>com.ibm.etools.webservice.rt.dxx.servlet.DxxInvoker</servlet-class>
        <init-param>
          <param-name>faultListener</param-name>
          <param-value>org.apache.soap.server.DOMFaultListener</param-value>
        </init-param>
        <load-on-startup>-1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dxx_sales_db</servlet-name>
        <url-pattern>/sales/*</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
       <welcome-file>index.html</welcome-file>
    </welcome-file-list>

</web-app>

In this example, the <servlet> element defines an instance of the DxxInvoker servlet named dxx_sales_db. The servlet name must be a valid directory name and is used to store the DADX resources for this group of Web Services. The <servlet-mapping> element associates the dxx_sales_db servlet with URLs of the form /sales/*. The URL pattern must be of this form for DxxInvoker to operate correctly. The init parameters have the same meaning as for the Apache SOAP RPCRouterServlet.

The groups Directory

The resources for all DADX Web Service groups are stored in the directory WEB-INF/classes/groups where WEB-INF is the directory used by J2EE Web applications to store resources that are not directly available to HTTP requests. This means that users cannot see the contents of your DADX files. DADX files contain the implementation of the Web Services and are therefore similar to Java classes.

The classes directory is part of the Java classpath for the Web application. This means that your DADX files can be loaded by the Java class loader and that your Web application can execute directly from its WAR file if your application server supports that mode of operation.

Within the groups directory each group of DADX Web Services is stored in a directory with the same name as its servlet instance. The DxxInvoker servlet determines where to find DADX files by looking for a directory that matches its servlet name. In our example, the DADX files are stored in the WEB-INF/classes/groups/dxx_sales_db directory.

The group.properties File

The database connection information, and other parameters, are defined in the group.properties file for the group which, in our example, is stored in the WEB-INF/classes/groups/dxx_sales_db directory:
 
Listing of group.properties
# dxx_sales_db group properties

dbDriver=COM.ibm.db2.jdbc.app.DB2Driver
dbURL=jdbc:db2:sales_db
userID=
password=
namespaceTable=sales_db.nst
autoReload=true
reloadIntervalSeconds=5

The group.properties file is a standard Java properties files. The properties have the following meanings:
 
Property Description
initialContextFactory The Java class name of the JDNI initial context factory that is used to locate the DataSource for the database.
datasourceJNDI The JNDI name of the DataSource for the database.
dbDriver The Java class name of the JDBC driver for the database.
dbURL The JDBC URL of the database.
userID The user id for the database.
password The password for the database.
namespaceTable The resource name of the namespace table.
autoReload The boolean automatic reloading mode.
reloadIntervalSeconds The integer automatic reloading time interval in seconds.
groupNamespaceUri The URI prefix for automatically generated namespaces for the WSDL and XSD documents. 

The PartOrders.dadx Web Service

In our example, the SALES_DB database stores information about part orders. Suppose that we must provide a Web Service that retreives orders based on the following conditions: We create a  DADX file named PartOrders.dadx that contains the following operations: We create a Web Service by deploying the PartOrders.dadx file to the services0 Web application which has been configured with the dxx_sales_db instance of the DxxInvoker servlet. The deployment  location of this file is WEB-INF/classes/groups/dxx_sales_db/PartOrders.dadx.

The Web Service supports access by the following protocols:

HTTP GET and POST are useful for simple access from Web browsers. In this case, the request uses the content type of application/x-www-form-urlencoded. For example, suppose the Web Services are deployed on the host www.mycompany.com. The following URLs would invoke the Web Services using HTTP GET: Note that in these URLs the method is encoded as the extra path info and the parameters are encoded as the query string. The responses to these requests have a content type of text/xml. For HTTP POST the query string is sent in the body of the request instead of the URL, but its content type is still application/x-www-form-urlencoded.

A Web Service defined by a DADX file is self-describing. It dynamically generates a documentation and test page, WSDL documents, and XML Schema. The following HTTP GET URL requests the documentation and test page:

The following HTTP GET URL requests the WSDL description of the service: For HTTP SOAP, the services are invoked by sending SOAP envelopes using POST to the URL: but with a request content type of text/xml instead of application/x-www-form-urlencoded.
 
Listing of PartOrders.dadx
<?xml version="1.0"?>
<DADX xmlns="http://schemas.ibm.com/db2/dxx/dadx"
      xmlns:xsd="http://www.w3.org/1999/XMLSchema">
  <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/1999/xhtml">
    Provides queries for part order information at myco.com.
    See <a href="../documentation/PartOrders.html" target="_top">PartOrders.html</a> for more information.
  </wsdl:documentation>

  <operation name="findAll">
    <documentation xmlns="http://schemas.xmlsoap.org/wsdl/">
      Returns all the orders with their complete details.
    </documentation>
    <retrieveXML>
       <DAD_ref>getstart_xcollection.dad</DAD_ref>
       <SQL_override>
       select o.order_key, customer_name, customer_email,
         p.part_key, color, quantity, price, tax, ship_id, date, mode
       from order_tab o, part_tab p,
         table(select substr(char(timestamp(generate_unique())),16) as ship_id,
           date, mode, part_key from ship_tab) s
       where p.order_key = o.order_key and s.part_key = p.part_key
       order by order_key, part_key, ship_id
       </SQL_override>
    </retrieveXML>
  </operation>

  <operation name="findByColor">
    <documentation xmlns="http://schemas.xmlsoap.org/wsdl/">Returns all the orders that include one or more parts that have the specified color, and only shows the details for those parts.</documentation>
    <retrieveXML>
      <DAD_ref>getstart_xcollection.dad</DAD_ref>
      <SQL_override>
       select o.order_key, customer_name, customer_email,
         p.part_key, color, quantity, price, tax, ship_id, date, mode
       from order_tab o, part_tab p,
         table(select substr(char(timestamp(generate_unique())),16) as ship_id,
           date, mode, part_key from ship_tab) s
       where p.order_key = o.order_key and s.part_key = p.part_key
         and color = :color
       order by order_key, part_key, ship_id
      </SQL_override>
      <parameter name="color" type="xsd:string"/>
    </retrieveXML>
  </operation>

  <operation name="findByMinPrice">
    <documentation xmlns="http://schemas.xmlsoap.org/wsdl/">Returns all the orders that include one or more parts that have a price greater than or equal to the specified minimum price, and only shows the details for those parts.</documentation>
    <retrieveXML>
      <DAD_ref>getstart_xcollection.dad</DAD_ref>
      <SQL_override>
       select o.order_key, customer_name, customer_email,
         p.part_key, color, quantity, price, tax, ship_id, date, mode
       from order_tab o, part_tab p,
         table(select substr(char(timestamp(generate_unique())),16) as ship_id,
           date, mode, part_key from ship_tab) s
       where p.order_key = o.order_key and s.part_key = p.part_key
         and p.price >= :minprice
       order by order_key, part_key, ship_id
      </SQL_override>
      <parameter name="minprice" type="xsd:decimal"/>
    </retrieveXML>
  </operation>

</DADX>

PartOrders.dadx implements all three of its operations using the <retrieveXML> operator which uses the DXX XML Collection access method. In general, each operation may use a different operator and access method. The supported operators are described in detail below.

Each operation in PartOrders.dadx refers to the same DAD, getstart_xcollection.dad:
 
Listing of getstart_xcollection.dad
<?xml version="1.0"?>
<!DOCTYPE DAD SYSTEM "c:\dxx\dtd\dad.dtd">
<DAD>
<validation>NO</validation>
<Xcollection>
<SQL_stmt>select o.order_key, customer_name, customer_email, p.part_key, color, quantity, price, tax, ship_id, date, mode from order_tab o, part_tab p, table(select substr(char(timestamp(generate_unique())),16) as ship_id, date, mode, part_key from ship_tab) s where o.order_key = 1 and p.price > 20000 and p.order_key = o.order_key and s.part_key = p.part_key ORDER BY order_key, part_key, ship_id</SQL_stmt>
<prolog>?xml version="1.0"?</prolog>
<doctype>!DOCTYPE Order SYSTEM "c:\dxx\samples\dtd\getstart.dtd"</doctype>
<root_node>
<element_node name="Order">
  <attribute_node name="key">
    <column name="order_key"/>
  </attribute_node>
  <element_node name="Customer">
    <element_node name="Name">
      <text_node><column name="customer_name"/></text_node>
    </element_node>
    <element_node name="Email">
      <text_node><column name="customer_email"/></text_node>
    </element_node>
  </element_node>
  <element_node name="Part">
    <attribute_node name="color">
      <column name="color"/>
    </attribute_node>
    <element_node name="key">
      <text_node><column name="part_key"/></text_node>
    </element_node>
    <element_node name="Quantity">
      <text_node><column name="quantity"/></text_node>
    </element_node>
    <element_node name="ExtendedPrice">
      <text_node><column name="price"/></text_node>
    </element_node>
    <element_node name="Tax">
      <text_node><column name="tax"/></text_node>
    </element_node>
    <element_node name="Shipment" multi_occurrence="YES">
      <element_node name="ShipDate">
        <text_node><column name="date"/></text_node>
      </element_node>
      <element_node name="ShipMode">
        <text_node><column name="mode"/></text_node>
      </element_node>
    </element_node>
  </element_node>
</element_node>
</root_node>
</Xcollection>
</DAD>

Each operation in PartOrders.dadx specifies an SQL override which replaces the SQL statement defined in getstart_xcollection.dad. Although PartOrders.dadx overrides the SQL statement, the new SQL statement must produce a result set that is compatible with the SQL mapping defined in getstart_xcollection.dad. For example, the column names that appear in the getstart_xcollection.dad must also appear in the SQL override.

In this example, the WHERE clause of the SQL statement is modified to include new search conditions. The SQL override may include one or more host variables which are identified using a colon prefix. In this example, findByColor uses :color and findByMinPrice uses :minprice. The host variables are declared as parameters and have simple XSD types that correspond to the built-in SQL data types. The supported types are described below.

DxxInvoker extracts the input parameters from the request, parses and validates them, converts them to SQL syntax and substitutes them for the host variables in the SQL override. For example, in HTTP GET, the request parameter color is encoded as color=red which is then quoted as 'red' before replacing the host variable :color.

getstart_xcollection.dad refers to the DTD document c:\dxx\samples\dtd\getstart.dtd via the SYSTEM URL in the <doctype> element. This URL is called the DTDID and is used by DXX for validation and mapping. The DTDID is also used as the primary key of the DTD_REF table which DXX creates to store DTDs. DXX inserts the contents of the <doctype> element as the document type declaration of the generated result.

A DAD document can also refer to a DTD using the <dtdid> element. Although the XML Extender Administration and Programming manual states that the <dtdid> element is required for the XML Collection access method, the current implementation of DXX does not enforce this rule. If the <dtdid> element is present then it must match the SYSTEM URL specified in the <doctype> element.

In general, a DAD document must refer to a DTD using the <dtdid> or <doctype> elements, except in the case of the XML Column access method if validation is not performed and if side tables are not generated. If the DTD is not defined then any XML document can be used in the operation.

The getstart.dtd DTD which defines the XML format for the generated XML document  is as follows:
 
Listing of getstart.dtd
<?xml encoding="US-ASCII"?>

<!ELEMENT Order (Customer, Part+)>
<!ATTLIST Order key CDATA #REQUIRED>
<!ELEMENT Customer (Name, Email)>
<!ELEMENT Name (#PCDATA)>
<!ELEMENT Email (#PCDATA)>
<!ELEMENT Part (key,Quantity,ExtendedPrice,Tax, Shipment+)>
<!ELEMENT key (#PCDATA)>
<!ELEMENT Quantity (#PCDATA)>
<!ELEMENT ExtendedPrice (#PCDATA)>
<!ELEMENT Tax (#PCDATA)>
<!ATTLIST Part color CDATA #REQUIRED>
<!ELEMENT Shipment (ShipDate, ShipMode)>
<!ELEMENT ShipDate (#PCDATA)>
<!ELEMENT ShipMode (#PCDATA)>

DADX Operations

The preceeding discussion used a DADX document that employed a single type of operation, retrieveXML. This section describes the complete set of operations supported by DADX.

The XML Collection operations use the DXX stored procedures. The SQL operations use normal SQL SELECT, UPDATE, INSERT, DELETE and CALL statements, and can be used for XML Column operations by employing the DXX UDTs and UDFs. When using the SQL operations, parameters may be defined using XSD elements as well as simple types. For the query operation, XSD elements may be associated with the column values in the result set. For call operations, parameters may be declared as in, out, or in/out.

The schema  for DADX documents is dadx.xsd:
 
Listing of dadx.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema
  targetNamespace="http://schemas.ibm.com/db2/dxx/dadx"
  xml:lang="en"
  xmlns="http://www.w3.org/2001/XMLSchema"
  xmlns:dadx="http://schemas.ibm.com/db2/dxx/dadx"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  elementFormDefault="qualified">

  <import namespace="http://schemas.xmlsoap.org/wsdl/" schemaLocation="wsdl.xsd"/>
 
  <annotation>
    <documentation>
      A Document Accession Definition Extension (DADX) document defines a Web Service
      that is implemented by operations that access a relational database and that optionally use
      stored procedures, types and functions provided by the DB2 XML Extender.
    </documentation>
  </annotation>

  <element name="DADX">

    <annotation>
      <documentation>
        Defines a Web Service.
        The Web Service is described by an optional WSDL documentation element.
        The Web Service may implement a set of WSDL bindings defined elsewhere.
        The Web Service consists of one or more uniquely named operations.
      </documentation>
    </annotation>

    <complexType>
      <sequence>
        <element ref="wsdl:documentation" minOccurs="0"/>
        <element ref="dadx:implements" minOccurs="0"/>
        <element ref="dadx:result_set_metadata" minOccurs="0" maxOccurs="unbounded"/>
        <element ref="dadx:operation" maxOccurs="unbounded"/>
      </sequence>
    </complexType>
    
    <key name="result_set_metadataNames">
      <selector xpath="dadx:result_set_metadata"/>
      <field xpath="@name"/>
    </key>
    
    <keyref name="resultSetMetatdata" refer="dadx:result_set_metadataNames">
      <selector xpath="dadx:operation/dadx:call/dadx:result_set"/>
      <field xpath="@metadata"/>
    </keyref>

    <unique name="operationNames">
      <selector xpath="dadx:operation"/>
      <field xpath="@name"/>
    </unique>

  </element>

  <element name="implements">

    <annotation>
      <documentation>
        Defines the namespace and location of a set of WSDL bindings
        defined elsewhere. This information is imported into the
        WSDL document generated for this Web Service.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="namespace" type="anyURI" use="required"/>
      <attribute name="location" type="anyURI" use="required"/>
    </complexType>
  </element>
  
  <element name="result_set_metadata">
  
    <annotation>
      <documentation>
        Defines the metadata for a result set returned by a stored procedure.
        Each metadata element defines a global element in the WSDL for the Web Service.
        The metatdata name defines the name of its global element.
        The metadata rowName defines the element name of each row.
        The metadata contains one or more column definitions.
      </documentation>
    </annotation>
    
    <complexType>
      <sequence>
        <element ref="dadx:column" minOccurs="1" maxOccurs="unbounded"/>
      </sequence>
      <attribute name="name" type="NCName" use="required"/>
      <attribute name="rowName" type="NCName" use="required"/>
    </complexType>
    
  </element>
  
  <element name="column">
  
     <annotation>
      <documentation>
        Defines the metadata for a column of a result set returned by a stored procedure.
        The column name, type, and nullability must match the values returned by the JDBC result set metadata at runtime.
        A column is considered to be nullable unless it is explicitly defined to not accept nulls.
        If the "nullable" attribute is absent then the column is considered to not be nullable.
        The element name associated with the column isdefined by the value of the "as" attribute if present, or the column name otherwise.
        The element may contain an XML document, in which case it must have an "element" attribute that defines the XML Schema name
        of its root element.
      </documentation>
    </annotation>
    
    <complexType>
      <attribute name="name" type="string" use="required"/>
      <attribute name="type" type="dadx:columnType" use="required"/>
      <attribute name="nullable" type="boolean"/>
      <attribute name="as" type="string"/>
      <attribute name="element" type="QName"/>
    </complexType>
    
 </element>

  <simpleType name="columnType">
    <restriction base="string">
      <enumeration value="BIGINT"/>
      <enumeration value="CHAR"/>
      <enumeration value="CLOB"/>
      <enumeration value="DATE"/>
      <enumeration value="DECIMAL"/>
      <enumeration value="DOUBLE"/>
      <enumeration value="FLOAT"/>
      <enumeration value="INTEGER"/>
      <enumeration value="NUMERIC"/>
      <enumeration value="REAL"/>
      <enumeration value="SMALLINT"/>
      <enumeration value="TIME"/>
      <enumeration value="TIMESTAMP"/>
      <enumeration value="TINYINT"/>
      <enumeration value="VARCHAR"/>
    </restriction>
  </simpleType>

  <element name="operation">

    <annotation>
      <documentation>
        Defines an operation of the Web Service.
        Each operation has a unique name and is optionally described
        by WSDL documentation.
        An operation is defined using one of the supported operators.
      </documentation>
    </annotation>

    <complexType>
      <sequence>
        <element ref="wsdl:documentation" minOccurs="0"/>
        <choice>
          <element ref="dadx:retrieveXML"/>
          <element ref="dadx:storeXML"/>
          <element ref="dadx:query"/>
          <element ref="dadx:update"/>
          <element ref="dadx:call"/>
        </choice>
      </sequence>
      <attribute name="name" type="NCName" use="required"/>
    </complexType>
  </element>

  <element name="retrieveXML">

    <annotation>
      <documentation>
        Retrieves a set of XML documents by composing them from relational data.
        This operator requires the DB2 XML Extender.
        The mapping from relational data to XML is defined by a
        Document Access Definition (DAD) which can be specified
        by refering to either a resource file or the name of an XML Collection
        that has been previously enabled in the database.
        The DAD must define an XML Collection and can use either SQL
        or RDB mapping. The DAD behavior may be modified by an override.
        If no override is desired, the no_override element must be used.
        Otherwise, the SQL_override element must be used for SQL mapping and the
        XML_override element must be used for RDB mapping. In either case, the
        override string may contain input parameters using the host variable syntax.
        The name and type of all parameters must be defined in a list of
        parameter elements that are uniquely named within this operation.
        </documentation>
    </annotation>

    <complexType>
      <sequence>
        <choice>
          <element ref="dadx:DAD_ref"/>
          <element ref="dadx:collection_name"/>
        </choice>
        <choice>
          <element name="no_override">
            <complexType/>
          </element>
          <element name="SQL_override" type="string"/>
          <element name="XML_override" type="string"/>
        </choice>
        <element ref="dadx:parameter" minOccurs="0" maxOccurs="unbounded"/>
      </sequence>
    </complexType>

    <unique name="retrieveXmlParameterNames">
      <selector xpath="dadx:parameter"/>
      <field xpath="@name"/>
    </unique>

  </element>

  <element name="storeXML">

    <annotation>
      <documentation>
        Stores an XML document by decomposing it into relational data.
        This operator requires the DB2 XML Extender.
        The mapping from relational data to XML is defined by a
        Document Access Definition (DAD) which can be specified
        by refering to either a resource file or the name of an XML Collection
        that has been previously enabled in the database.
        The DAD must define an XML Collection and must use RDB mapping.
        </documentation>
    </annotation>

    <complexType>
       <choice>
        <element ref="dadx:DAD_ref"/>
        <element ref="dadx:collection_name"/>
      </choice>
     </complexType>
  </element>

  <element name="query">

    <annotation>
      <documentation>
        Retrieves a set of relational data using an SQL SELECT statement.
        The result set must consist of uniquely named columns.
        If any result set column contains XML documents, the XML document type must be
        defined using an XML_result element. 
        The statement may contain input parameters using the host variable syntax.
        The input parameters must be defined by a list of parameter elements that are
        uniquely named within this operation.
      </documentation>
    </annotation>

    <complexType>
      <sequence>
        <element name="SQL_query" type="string"/>
        <element ref="dadx:XML_result" minOccurs="0" maxOccurs="unbounded"/>
        <element ref="dadx:parameter" minOccurs="0" maxOccurs="unbounded"/>
      </sequence>
    </complexType>

    <unique name="XML_resultNames">
      <selector xpath="dadx:XML_result"/>
      <field xpath="@name"/>
    </unique>

    <unique name="queryParameterNames">
      <selector xpath="dadx:parameter"/>
      <field xpath="@name"/>
    </unique>

  </element>

  <element name="update">

    <annotation>
      <documentation>
        Updates a relational table using an SQL INSERT, UPDATE, or DELETE statement and
        reports the number of rows affected.
        The statement may contain input parameters using the host variable syntax.
        The input parameters must be defined by a list of parameter elements that are
        uniquely named within this operation.
      </documentation>
    </annotation>

    <complexType>
      <sequence>
        <element name="SQL_update" type="string"/>
        <element ref="dadx:parameter" minOccurs="0" maxOccurs="unbounded"/>
      </sequence>
    </complexType>

    <unique name="updateParameterNames">
      <selector xpath="dadx:parameter"/>
      <field xpath="@name"/>
    </unique>

  </element>

  <element name="call">

    <annotation>
      <documentation>
        Calls a stored procedure.
        The call statement contains in, out, and in/out parameters using host variable syntax.
        The parameters are defined by a list of parameter elements that are uniquely named
        within the operation.
      </documentation>
    </annotation>

    <complexType>
      <sequence>
        <element name="SQL_call" type="string"/>
        <element ref="dadx:parameter" minOccurs="0" maxOccurs="unbounded"/>
        <element ref="dadx:result_set" minOccurs="0" maxOccurs="unbounded"/>
      </sequence>
    </complexType>

    <unique name="callParameterNames">
      <selector xpath="dadx:parameter"/>
      <field xpath="@name"/>
    </unique>

    <unique name="callResultSetNames">
      <selector xpath="dadx:result_set"/>
      <field xpath="@name"/>
    </unique>
    
  </element>
  
  <element name="result_set">
      <annotation>
      <documentation>
        Defines a result set.
        The name defines the element name of the result set and becomes part of the output message.
        The metatdata name refers to a result set metadata element defined in the same document.
      </documentation>
    </annotation>
    
    <complexType>
      <attribute name="name" type="NCName" use="required"/>
      <attribute name="metadata" type="NCName" use="required"/>     
    </complexType>
    
</element>

  <element name="DAD_ref" type="string"/>

  <element name="collection_name" type="string"/>

  <element name="parameter">

    <annotation>
      <documentation>
        Defines a named parameter. A parameter must have it contents defined either by 
        an XML Schema element or type, but not both. The parameter kind in one of in,
        out, or in/out, with in being the default.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="name" type="NCName" use="required"/>
      <attribute name="element" type="QName"/>
      <attribute name="type" type="QName"/>
      <attribute name="kind" type="dadx:parameterKindType" default="in"/>
    </complexType>
  </element>

  <simpleType name="parameterKindType">
    <restriction base="string">
      <enumeration value="in"/>
      <enumeration value="out"/>
      <enumeration value="in/out"/>
    </restriction>
  </simpleType>

  <element name="XML_result">

    <annotation>
      <documentation>
        Defines a named column that contains XML documents. The document type
        must be defined by the XML Schema element of its root.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="name" type="NCName" use="required"/>
      <attribute name="element" type="QName" use="required"/>
    </complexType>
  </element>

</schema>

<retrieveXML>

The retrieveXML operation generates zero or more XML documents from a set of relational tables using the XML Collection access method.

This operation is currently implemented by the dxxGenXML or dxxRetrieveXML stored procedures but we plan to use the new dxxGenXMLClob and dxxRetrieveXMLClob which were introduced in Fixpak 4. The new stored procedures are more portable but differ in that they return at most one document. This difference only affects the XML Schema generated for the output (maxOccurs="unbounded" for the old procedures, maxOccurs="1" for the new ones).

Consider the following example:
 
<operation name="findByColorAndMinPrice">
  <documentation>Returns all the orders that have the specified color and at least the specified minimum price.</documentation>
  <retrieveXML>
    <DAD_ref>getstart_xcollection.dad</DAD_ref>
    <SQL_override>
     select o.order_key, customer_name, customer_email,
       p.part_key, color, quantity, price, tax, ship_id, date, mode
     from order_tab o, part_tab p,
       table(select substr(char(timestamp(generate_unique())),16) as ship_id,
         date, mode, part_key from ship_tab) s
     where p.order_key = o.order_key and s.part_key = p.part_key
       and color = :color and price >= :minprice
     order by order_key, part_key, ship_id
    </SQL_override>
    <parameter name="color" type="xsd:string"/>
    <parameter name="minprice" type="xsd:decimal"/>
  </retrieveXML>
</operation>

This operation is implemented by dxxGenXML if a <DAD_ref> element is used and by dxxRetrieveXML if a <collection_name> element is used.

The dxxGenXML stored procedure takes as arguments a DAD document and an optional override. The override can be either SQL or XML. If the override is SQL then the DAD must use SQL mapping. If the override is XML then the DAD must use RDB_node mapping. If an override is defined, then the operation can also define one or more <parameter> elements. The parameters form the input message. DxxInvoker extracts the parameters from the input message, validates them, and then substitutes them into the override by replacing the parameter markers, e.g. :color and :minprice.

The dxxGenXML returns zero or more XML documents that satisfy that DTD referenced by the DAD file. DxxInvoker invokes the dxxGenXML stored procedure, retrieves the result set and places it in the output message.

The WSDL message definitions generated for this example are:
 
<message name="findByColorAndMinPriceInput">
  <part name="color" type="xsd:string"/>
  <part name="minprice" type="xsd:decimal"/>
</meesage>

<message name="findByColorAndMinPriceOutput">
  <part name="return" element="xsd1:findByColorAndMinPriceResult"/>
</message>

where xsd1:findByColorAndMinPriceResult is defined in the WSDL <types> element as follows:
 
<element name="findByColorAndMinPriceResult">
  <complexType>
    <sequence>
        <element ref="dtd1:Order" minOccurs="0" maxOccurs="unbounded"/>
    </sequence>
  </complexType>
</element>

The retrieveXML operation is implemented by the dxxRetrieveXML stored procedure if the <DAD_ref> element is replaced by the <collection_name> element. The dxxRetriveXML stored procedure is the same as dxxGenXML except that instead of using a DAD document, it uses the name of a collection. The name of the collection and its corresponding DAD document are stored in the XML_USAGE table. DxxInvoker determines the type of the result XML documents by retrieving the DAD document from the XML_USAGE table and examining its <doctype> element.

<storeXML>

The storeXML operation stores an XML document in a set of relational tables using the XML Collection access method. The DAD document that defines the collection must use the RDB_node mapping method. Here is a sample DAD that uses RDB_node mapping, getstart-xcollection-rdb.dad:
 
Listing of getstart-xcollection-rdb.dad
<?xml version="1.0"?>
<!DOCTYPE DAD SYSTEM "c:\dxx\dtd\dad.dtd">
<DAD>
  <validation>NO</validation>
  <Xcollection>
    <prolog>?xml version="1.0"?</prolog>
    <doctype>!DOCTYPE Order SYSTEM "c:\dxx\samples\dtd\getstart.dtd"</doctype>
    <root_node>
      <element_node name="Order">
        <RDB_node>
          <table name="ORDER_TAB"/>
          <table name="PART_TAB"/>
          <table name="SHIP_TAB"/>
          <condition>
            order_tab.order_key=part_tab.order_key AND 
            part_tab.part_key=ship_tab.part_key
          </condition>
        </RDB_node>
        <attribute_node name="key">
          <RDB_node>
            <table name="ORDER_TAB"/>
            <column name="ORDER_KEY" type="Integer"/>
          </RDB_node>
        </attribute_node>
        <element_node name="Customer">
          <element_node name="Name">
            <text_node>
              <RDB_node>
                <table name="ORDER_TAB"/>
                <column name="CUSTOMER_NAME" type="VarChar(16)"/>
              </RDB_node>
            </text_node>
          </element_node>
          <element_node name="Email">
            <text_node>
              <RDB_node>
                <table name="ORDER_TAB"/>
                <column name="CUSTOMER_EMAIL" type="VarChar(16)"/>
              </RDB_node>
            </text_node>
          </element_node>
          <element_node name="Phone">
            <text_node>
              <RDB_node>
                <table name="ORDER_TAB"/>
                <column name="CUSTOMER_PHONE" type="VarChar(16)"/>
              </RDB_node>
            </text_node>
          </element_node>
        </element_node>
        <element_node name="Part" multi_occurrence="YES">
          <attribute_node name="color">
            <RDB_node>
              <table name="PART_TAB"/>
              <column name="COLOR" type="Character(6)"/>
            </RDB_node>
          </attribute_node>
          <element_node name="key">
            <text_node>
              <RDB_node>
                <table name="PART_TAB"/>
                <column name="PART_KEY" type="Integer"/>
              </RDB_node>
            </text_node>
          </element_node>
          <element_node name="Quantity">
            <text_node>
              <RDB_node>
                <table name="PART_TAB"/>
                <column name="QUANTITY" type="Integer"/>
              </RDB_node>
            </text_node>
          </element_node>
          <element_node name="ExtendedPrice">
            <text_node>
              <RDB_node>
                <table name="PART_TAB"/>
                <column name="PRICE" type="Decimal(10,2)"/>
              </RDB_node>
            </text_node>
          </element_node>
          <element_node name="Tax">
            <text_node>
              <RDB_node>
                <table name="PART_TAB"/>
                <column name="TAX" type="Real"/>
              </RDB_node>
            </text_node>
          </element_node>
          <element_node name="Shipment" multi_occurrence="YES">
            <element_node name="ShipDate">
              <text_node>
                <RDB_node>
                  <table name="SHIP_TAB"/>
                  <column name="DATE" type="Date"/>
                </RDB_node>
              </text_node>
            </element_node>
            <element_node name="ShipMode">
              <text_node>
                <RDB_node>
                  <table name="SHIP_TAB"/>
                  <column name="MODE" type="Character(6)"/>
                </RDB_node>
              </text_node>
            </element_node>
            <element_node name="Comment">
              <text_node>
                <RDB_node>
                  <table name="SHIP_TAB"/>
                  <column name="COMMENT" type="VarChar(64)"/>
                </RDB_node>
              </text_node>
            </element_node>
          </element_node>
        </element_node>
      </element_node>
    </root_node>
  </Xcollection>
</DAD>

This operation is implemented by dxxShredXML if a <DAD_ref> element is used and by dxxInsertXML if a <collection_name> element is used. The dxxShredXML stored procedure takes a DAD document and an XML document as input.  Consider the following example:
 
<operation name="storeOrder">
  <documentation>Stores an automotive part order.</documentation>
  <storeXML>
    <DAD_ref>getstart_xcollection-rdb.dad</DAD_ref>
  </storeXML>
</operation>

The WSDL message definitions generated for this example are:
 
<message name="storeOrderInput">
  <part name="input" element="dtd1:Order"/>
</message>

<message name="storeOrderOutput"/>

The storeXML operation is implemented by the dxxInsertXML stored procedure if a <collection_name> element is used instead of a <DAD_ref> element. It is the same as dxxShredXML except that is uses the name of a collection instead of a DAD document.

<query>

The operation is defined by an SQL SELECT statement in the <SQL_select> element and is implemented by the java.sql.PreparedStatement.executeQuery method. The statement may have zero or more named input parameter. If the statement has input parameters then each parameter is described by a <parameter> element. DxxInvoker scans the SQL statement for the declared input parameters and replaces them with '?' IN parameter markers, then calls the java.sql.Connection.prepareStatement method to create a prepared statement. DxxInvoker then extracts the parameter values from the input message and sets them in the prepared statement. DxxInvoker executes the query, and returns the result set as XML by mapping each column value to an element.

The following table lists the SQL types that are supported in result sets, and their mapping to 2001 XML Schema types;
 
Table of Supported SQL Types in JDBC Result Sets
SQL Type XML Type
BIGINT long
CHAR string
CLOB string
DATE date
DECIMAL decimal
DOUBLE double
FLOAT double
INTEGER int
NUMERIC decimal
REAL float
SMALLINT short
TIME time
TIMESTAMP dateTime
TINYINT byte
VARCHAR string

This operation provides simple XML mapping and can be used without DXX. If more control over the mapping is required, then a DAD file must be used.

The query must be constructed so that the name of each column can be mapped to a valid XML element name. If a result column contains an XML document, then an XSD element can be associated with the column using the <XML_result> element. Consider the following example which selects all of the orders for a given customer:
 
<operation name="findCustomerOrders">
  <documentation>Returns all the orders for a given customer.</documentation>
  <query>
    <SQL_query>select * from order_tab where customer_name = :customer_name</SQL_query>
    <parameter name="customer_name" type="xsd:string"/>
  </query>
</operation>

The WSDL message definitions are:
 
<message name="findCustomerOrdersInput">
  <part name="customer_name" type="xsd:string"/>
</message>

<message name="findCustomerOrdersOutput">
  <part name="return" element="xsd1:findCustomerOrdersResult"/>
</message>

DxxInvoker generates the XSD definition for the result element by examining the java.sql.ResultSetMetaData associated with the prepared statement. The metadata defines the SQL types of the columns in the result set. If any of these columns contain XML documents then the XSD element can be associated with the column using an <XML_result> element. The generated XSD type for the example is:
 
<element name="findCustomerOrdersResult"> 
  <complexType>
    <sequence>
      <element name="findCustomerOrdersRow"  minOccurs="0" maxOccurs="unbounded">
        <complexType> 
          <sequence>
             <element name="ORDER_KEY" type="xsd:integer" nullable="true"/>
              <element name="CUSTOMER_NAME" type="xsd:string" nullable="true"/> 
              <element name="CUSTOMER_EMAIL" type="xsd:string" nullable="true"/> 
              <element name="CUSTOMER_PHONE" type="xsd:string" nullable="true"/>
           </sequence>
         </complexType>
       </element>
     </sequence>
   </complexType>
</element>

The following examples show the use of UDTs and UDFs. The retrieveOrders operation retrieves all the XML Order documents from the SALES_TAB table. The documents are stored using the DXX UDT XMLVARCHAR:
 
<operation name="retrieveOrders">
  <documentation>Retrieves all the Order documents.</documentation>
  <query>
    <SQL_query>select db2xml.varchar(order) from sales_tab</SQL_query>
    <XML_result name="ORDER" element="dtd1:Order"/>
  </query>
<operation>

The findCustomersByMinimumPrice operation extracts the names of all customers that have orders with prices above a minimum price. It uses the DXX UDT extractVarchar:
 
<operation name="findCustomersByMinimumPrice">
  <documentation>Finds all customers that have orders with price greater than a minimum price.</documentation>
  <query>
    <SQL_query>
      select extractVarchar(Order, '/Order/Customer/Name') from sales_order_view
      where price > :minprice
    </SQL_query>
    <parameter name="minprice" type="xsd:decimal"/>
  </query>
</operation>

<update>

The operation is defined by an SQL INSERT, DELETE, or UPDATE statement in the <SQL_update> element and is implmented by the java.sql.PreparedStatement.executeUpdate method. The statement may have zero or more named input parameters and it returns an integer which is the number of rows modified by the operation. If the statement has input parameters then each parameter is described by a <parameter> element. DxxInvoker scans the SQL statement for the declared input parameters and replaces them with '?' IN parameter markers, then calls the java.sql.Connection.prepareStatement method to create a prepared statement. DxxInvoker then extracts the in parameter values from the input message and sets them in the prepared statement. Finally, DxxInvoker executes the update.

This operation can be used without DXX. Consider the following example which updates the email address of a customer for a given order:
 
<operation name="updateOrderEmail">
  <documentation>Updates the email address for an order.</documentation>
  <update>
    <SQL_update>update order_tab set customer_email = :email where order_key = :key</SQL_update>
    <parameter name="key" type="xsd:integer"/>
    <parameter name="email" type="xsd:string"/>
  </update>
</operation>

The generated WSDL message definitions for this example are:
 
<message name="updateOrderEmailInput">
  <part name="key" type="xsd:integer"/>
  <part name="email" type="xsd:string"/>
</message>

<message name="updateOrderEmailOutput">
  <part name="return" type="xsd:integer"/>
</message>

An input paramete may be associated with an XSD element. For example, suppose the ORDER column of the SALES_TAB table has been enabled as an XML column. The following operation inserts an Order document in the table in a row defined by the :invoice_number and :sales_person input parameters:
 
<operation name="createInvoice">
  <documentation>Creates an invoice given an order, invoice number and sales person.</document>
  <update>
   <SQL_update>
      insert into sales_tab (invoice_num, sales_person, order)
      values (:invoice_number, :sales_person, db2xml.XMLVarchar(:order))
    </SQL_update>
    <parameter name="invoice_number" type="xsd:string"/>
    <parameter name="sales_person" type="xsd:string"/>
    <parameter name="order" element="dtd1:Order"/>
  </update>
</operation>

The WSDL message definitions generated for this example are:
 
<message name="createInvoiceInput">
  <part name="invoice_number" type="xsd:string"/>
  <part name="sales_person" type="xsd:string"/>
  <part name="order" element="dtd1:Order"/>
</message>

<message name="createInvoiceOutput">
  <part name="return" type="xsd:integer"/>
</message>

The following operation updates an existing invoice:
 
<operation name="updateInvoice">
  <documentation>Updates an invoice with new order information.</documentation>
  <update input="order">
     <SQL_update>
        update sales_tab set order=db2xml.XMLVarchar(:order)
        where invoice_number = :invoice_number
      </SQL_update>
    <parameter name="order" element="dtd1:Order"/>
    <parameter name="invoice_number" type="xsd:string"/>
  </update>
</operation>

The WSDL message definitions generated for this example are:
 
<message name="updateInvoiceInput">
  <part name="order" element="dtd1:Order"/>
  <part name="invoice_number" type="xsd:string"/>
</message>

<message name="createInvoiceOutput">
  <part name="return" type="xsd:integer/>
</message>

<call>

This operation is implemented by the SQL CALL statement which calls a stored procedure. The processing is similar to the update operation, but the parameters for the call operation may be defined as 'in', 'out', or 'in/out'. The default parameter kind is 'in'.The 'out' and 'in/out' parameters appear in the output message.

Consider the following example:
 
<operation name="callFoo"/>
  <documentation>Call the foo stored procedure.</documentation>
  <call>
    <SQL_call>
      :a = call foo (:x, :y, :z)
    </SQL_call>
    <parameter name="a" type="xsd:decimal" kind="out"/>
    <parameter name="x" type="xsd:string" kind="in"/>
    <parameter name="y" type="xsd:integer" kind="in/out"/>
    <parameter name="z" element="dtd1:Order" kind="out"/>
  </call>
</operation>

The WSDL messages definitions are:
 
<message name="callFooInput">
  <part name="x" type="xsd:string"/>
  <part name="y" type="xsd:integer"/>
</message>

<message name="callFooOutput">
  <part name="return" element="xsd1:callFooResult"/>
</message>

where:
 
<element name="callFooResult">
  <complexType>
    <sequence>
      <element name="a" type="xsd:decimal"/>
      <element name="y" type="xsd:integer"/>
      <element name="z">
        <complexType>
          <sequence>
            <element ref="dtd1:Order"/>
          </sequence>
        </complexType>
      </element>
    </sequence>
  </complexType>
</element>

Result Sets

Stored procedures can also return one or more result sets which can be included in the output message. Since the JDBC metadata for a CALL statement does not include the result set metadata, it must be defined explicitly in the DADX file using the <result_set_metadata> element. At runtime, the metadata of the result set can be obtained and it must match the definition contained in the DADX file. Therefore, only stored procedures that have result sets with fixed metadata can be invoked. This restriction is necessary in order to have a well-defined WSDL file for the Web Service.

A result set metadata definition can be referenced by several call operations. The result set metadata definitions are global to the Web Service and must preceed all the operation definition elements.

The following example shows how to define the result set metadata and result set outputs for the twoResultSets stored procedure that is defined in the Spserver.java sample that comes with the DB2 Software Development Kit (the complete DADX file for this example is Spserver.dadx):
 
<?xml version="1.0"?>
<DADX xmlns="http://schemas.ibm.com/db2/dxx/dadx"
      xmlns:dtd1="http://schemas.myco.com/sales/getstart.dtd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema"
      xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
      xsi:schemaLocation="http://schemas.ibm.com/db2/dxx/dadx dadx.xsd
                          http://schemas.xmlsoap.org/wsdl/ wsdl.xsd">

  <wsdl:documentation xmlns="http://www.w3.org/1999/xhtml">
Calls the stored procedures defined by the DB2 SDK sample Spserver.java.
See, e.g., <pre>D:\Program Files\SQLLIB\samples\java\README</pre> for
instructions on how to install the Spserver.java stored procedure.
</wsdl:documentation>

<result_set_metadata name="employeeSalaryReport" rowName="employee">
  <column name="NAME" type="VARCHAR" nullable="true"/>
  <column name="JOB" type="CHAR" nullable="true"/>
  <column name="3" as="SALARY" type="DOUBLE" nullable="true"/>
</result_set_metadata>

<operation name="twoResultSets"> 
<wsdl:documentation xmlns="http://www.w3.org/1999/xhtml">
returns two result sets to the client application
<pre>
CREATE PROCEDURE TWO_RESULT_SETS (
  IN salary DOUBLE,
  out sqlCode INTEGER
)
DYNAMIC RESULT SETS 2
LANGUAGE JAVA 
PARAMETER STYLE JAVA
NO DBINFO
FENCED
READS SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'Spserver.twoResultSets'
</pre>
</wsdl:documentation> 
  <call> 
    <SQL_call>CALL TWO_RESULT_SETS (:salary, :sqlCode)</SQL_call> 
    <parameter name="salary" type="xsd:double" kind="in"/> 
    <parameter name="sqlCode" type="xsd:int" kind="out"/> 
    <result_set name="employees1" metadata="employeeSalaryReport"/>
    <result_set name="employees2" metadata="employeeSalaryReport"/>
  </call> 
</operation>

The result set metadata has a name, which is used for the root element of the result set, a row name, which is used as the element name for each row of the result set, and a sequence of one or more column definitions. The order of the columns must match that of the result set returned by the stored procedure. Each column has a name, type, and nullability, which must match the result set. The name and type are required. The supported types are the same as those for result sets in query operations.

The nullable attribute is optional. If absent, the nullability has the value of false. The result set column is deemed to be nullable unless its runtime metadata specifies that it cannot contain nulls. Therefore if the column can contain nulls or its nullability is not know at runtime then it is nullable.

The column definition can have an optional as attribute which overrides the column name in the XML tagging for the column. The column name, or the as attribute if present, is converted to a valid XML identifier and is used as the element name for the column.

The column definition can also have an optional QName element attribute. If present, the column type must map to the XML string type and contain XML documents. The DTDID is determined by the entry in the namespace table (see below) that maps to the namepace of the QName. The root element name matches the local part of the QName. This attribute plays the same role as the element attribute of the <parameter> element.

Within the call operation, each return result set is defined by a <result_set> element which must follow any <parameter> elements. The result set element has a name which must be unique among all the parameters and result sets of the operation. The type of the result set if defined by the metadata attribute which must must the name of a <result_set_metadata> element. At runtime, the defined result sets must be present, but any additional undefined result sets are simply ignored.

Mapping DTDIDs to XSD Namespaces and Locations

The DTDID used by DXX is typically the local file path of the DTD. DXX retreives the DTD either from the file system or the DTD_REF table. However, the use of a local file path is not appropriate for Web Services since the result is sent to remote clients that do not have access to the server file system. The correct way to specify the document structure is by giving the namespace and location of an XML Schema (XSD) document for the result. The namespace and location are specified using an <import> element in the WSDL document that describes the Web Service.

DxxInvoker must therefore associate an XSD namespace and location with each DTDID that is used in the DAD documents that are referenced by the service. The mapping between DTDIDs and XML namespaces is defined by the following group.properties parameter:

The algorithm for mapping a DTDID to an XSD namespace and location is as follows:
  1. Lookup the DTDID in the namespaceTable. If an entry exists then use the defined namespace and location.
  2. Otherwise, the DTDID cannot be mapped so throw an exception.
In our example group.properties file we have the following paramter value: The contents of sales_db.nst is:
 
Listing of sales_db.nst
<?xml version="1.0"?>
<namespaceTable xmlns="http://schemas.ibm.com/db2/dxx/nst">
  <mapping dtdid="c:\dxx\samples\dtd\getstart.dtd"
    namespace="http://schemas.ibm.com/db2/dxx/samples/dtd/getstart.dtd"
    location="/dxx/samples/dtd/getstart.dtd/XSD"/>
  <mapping dtdid="getstart.dtd"
    namespace="http://schemas.myco.com/sales/getstart.dtd"
    location="/getstart.dtd/XSD"/>
  <mapping dtdid="order.dtd"
    namespace="http://schemas.myco.com/sales/order.dtd"
    location="/order.dtd/XSD"/>
</namespaceTable>

The XSD document for the namespace table is nst.xsd:
 
Listing of nst.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema
  targetNamespace="http://schemas.ibm.com/db2/dxx/nst"
  xml:lang="en"
  xmlns="http://www.w3.org/2001/XMLSchema"
  xmlns:nst="http://schemas.ibm.com/db2/dxx/nst">
  <element name="namespaceTable">

    <annotation>
      <documentation>
        Defines a namespace table of zero or more mappings from DB2 XML Extender DTDIDs 
        to XML Schema namespaces and locations, each of which is unique.
      </documentation>
    </annotation>

    <complexType>
      <sequence>
        <element name="mapping" minOccurs="0" maxOccurs="unbounded">

    <annotation>
      <documentation>
        Defines a mapping from an DB2 XML Extender DTDID 
        to an XML Schema namespace and location.
        The DTDID is either a file name or a primary key value in the DTD_REF
        table of the database.
        The location may be either absolute or relative. If the location begins
        with a / it is relative to the Web Services group. Otherwise it is absolute.
      </documentation>
    </annotation>

          <complexType>
            <attribute name="dtdid" type="string" use="required"/>
            <attribute name="namespace" type="anyURI" use="required"/>
            <attribute name="location" type="anyURI" use="required"/>
          </complexType>
        </element>
      </sequence>
    </complexType>

    <unique name="dtdids">
      <selector xpath="mapping"/>
      <field xpath="@dtdid"/>
    </unique>

    <unique name="namespaces">
      <selector xpath="mapping"/>
      <field xpath="@namespace"/>
    </unique>

    <unique name="locations">
      <selector xpath="mapping"/>
      <field xpath="@location"/>
    </unique>

  </element>
</schema>

The mapping from DTDIDs to XSD is used for the following purposes:

Converting DTD to XSD

Although DXX currently uses DTDs to define document structure, WSDL uses XSD. A DTD can be automatically translated into an XML Schema. DxxInvoker automatically translates a DTD into XSD when the URL has the extra path info XSD and there is a matching entry in the namespace table. For example, the following URL requests the translation of c:\dxx\samples\dtd\getstart.dtd to XSD: The algorithm for translating DTD documents to XSD is as follows:
  1. Look for an entry in namespaceTable that has a location attribute that is equal to the request URL, e.g. the location attribute /dxx/samples/dtd/getstart.dtd/XSD is relative to the group so it matches the URL http://www.mycompany.com/services0/sales/dxx/samples/dtd/getstart.dtd/XSD.
  2. If an entry exists, get the dtdid attribute, e.g. c:\dxx\samples\dtd\getstart.dtd, and retrieve the DTD document from either the file system or the DTD_REF table, and translate it to XSD.
  3. Otherwise, the DTD cannot be translated, so throw an exception.
For getstart.dtd, the result of the automatic translation is getstart.xsd:
 
Listing of getstart.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://schemas.ibm.com/db2/dxx/samples/dtd/getstart.dtd"
        xmlns:tns="http://schemas.ibm.com/db2/dxx/samples/dtd/getstart.dtd"
        xmlns="http://www.w3.org/2001/XMLSchema">
  <element name="Part">
    <complexType>
      <sequence>
        <element ref="tns:key"/>
        <element ref="tns:Quantity"/>
        <element ref="tns:ExtendedPrice"/>
        <element ref="tns:Tax"/>
        <element ref="tns:Shipment" minOccurs="1" maxOccurs="unbounded"/>
      </sequence>
      <attribute name="color" type="string" use="required"/>
    </complexType>
  </element>
  <element name="Quantity" type="string"/>
  <element name="ShipDate" type="string"/>
  <element name="Customer">
    <complexType>
      <sequence>
        <element ref="tns:Name"/>
        <element ref="tns:Email"/>
      </sequence>
    </complexType>
  </element>
  <element name="ShipMode" type="string"/>
  <element name="Name" type="string"/>
  <element name="key" type="string"/>
  <element name="Shipment">
    <complexType>
      <sequence>
        <element ref="tns:ShipDate"/>
        <element ref="tns:ShipMode"/>
      </sequence>
    </complexType>
  </element>
  <element name="ExtendedPrice" type="string"/>
  <element name="Tax" type="string"/>
  <element name="Email" type="string"/>
  <element name="Order">
    <complexType>
      <sequence>
        <element ref="tns:Customer"/>
        <element ref="tns:Part" minOccurs="1" maxOccurs="unbounded"/>
      </sequence>
      <attribute name="key" type="string" use="required"/>
    </complexType>
  </element>
</schema>

Generating WSDL from DADX

The DADX document contains the information required to implement the Web Service. It also contains the information required to generate the WSDL document that describes the Web Service. The algorithm used to generate the WSDL document from the DADX document is illustrated here using the PartOrders.dadx example given above deployed in the Web Services group at http://localhost:8080/service/sales.

DxxInvoker dynamically generates the WSDL document PartOrders.wsdl in response to the URL:

Listing of PartOrders.wsdl
<?xml version="1.0" encoding="UTF-8"?>
<definitions
  targetNamespace="http://localhost:8080/services/sales/PartOrders.dadx/WSDL"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
  xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
  xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:tns="http://localhost:8080/services/sales/PartOrders.dadx/WSDL"
  xmlns:xsd-1999="http://www.w3.org/1999/XMLSchema"
  xmlns:xsd1="http://localhost:8080/services/sales/PartOrders.dadx/XSD">
  <wsdl:documentation
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
    Provides queries for part order information at myco.com.
    See 
    <a href="../documentation/PartOrders.html" target="_top">PartOrders.html
    </a> for more information.

  </wsdl:documentation>
  <types>
    <schema
      targetNamespace="http://localhost:8080/services/sales/PartOrders.dadx/XSD"
      xmlns="http://www.w3.org/2001/XMLSchema"
      xmlns:imp1="http://schemas.ibm.com/db2/dxx/samples/dtd/getstart.dtd"
      xmlns:tns="http://localhost:8080/services/sales/PartOrders.dadx/XSD">
      <import
        nameSpace="http://schemas.ibm.com/db2/dxx/samples/dtd/getstart.dtd"
        schemaLocation="http://localhost:8080/services/sales/dxx/samples/dtd/getstart.dtd/XSD"/>
      <element name="findAllResult">
        <complexType>
          <sequence>
            <element maxOccurs="unbounded" minOccurs="0" ref="imp1:Order"/>
          </sequence>
        </complexType>
      </element>
      <element name="findByColorResult">
        <complexType>
          <sequence>
            <element maxOccurs="unbounded" minOccurs="0" ref="imp1:Order"/>
          </sequence>
        </complexType>
      </element>
      <element name="findByMinPriceResult">
        <complexType>
          <sequence>
            <element maxOccurs="unbounded" minOccurs="0" ref="imp1:Order"/>
          </sequence>
        </complexType>
      </element>
    </schema>
  </types>
  <message name="findAllInput"/>
  <message name="findAllOutput">
    <part element="xsd1:findAllResult" name="return"/>
  </message>
  <message name="findByColorInput">
    <part name="color" type="xsd-1999:string"/>
  </message>
  <message name="findByColorOutput">
    <part element="xsd1:findByColorResult" name="return"/>
  </message>
  <message name="findByMinPriceInput">
    <part name="minprice" type="xsd-1999:decimal"/>
  </message>
  <message name="findByMinPriceOutput">
    <part element="xsd1:findByMinPriceResult" name="return"/>
  </message>
  <portType name="thePortType">
    <operation name="findAll">
      <documentation xmlns="http://schemas.xmlsoap.org/wsdl/">
      Returns all the orders with their complete details.

      </documentation>
      <input message="tns:findAllInput"/>
      <output message="tns:findAllOutput"/>
    </operation>
    <operation name="findByColor">
      <documentation xmlns="http://schemas.xmlsoap.org/wsdl/">Returns all the orders that include one or more parts that have the specified color, and only shows the details for those parts.
      </documentation>
      <input message="tns:findByColorInput"/>
      <output message="tns:findByColorOutput"/>
    </operation>
    <operation name="findByMinPrice">
      <documentation xmlns="http://schemas.xmlsoap.org/wsdl/">Returns all the orders that include one or more parts that have a price greater than or equal to the specified minimum price, and only shows the details for those parts.
      </documentation>
      <input message="tns:findByMinPriceInput"/>
      <output message="tns:findByMinPriceOutput"/>
    </operation>
  </portType>
  <binding name="theSoapBinding" type="tns:thePortType">
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http">
      <operation name="findAll">
        <soap:operation soapAction="urn:/sales/PartOrders.dadx"/>
        <input>
          <soap:body namespace="urn:/sales/PartOrders.dadx" use="literal"/>
        </input>
        <output>
          <soap:body namespace="urn:/sales/PartOrders.dadx" use="literal"/>
        </output>
      </operation>
      <operation name="findByColor">
        <soap:operation soapAction="urn:/sales/PartOrders.dadx"/>
        <input>
          <soap:body namespace="urn:/sales/PartOrders.dadx" use="literal"/>
        </input>
        <output>
          <soap:body namespace="urn:/sales/PartOrders.dadx" use="literal"/>
        </output>
      </operation>
      <operation name="findByMinPrice">
        <soap:operation soapAction="urn:/sales/PartOrders.dadx"/>
        <input>
          <soap:body namespace="urn:/sales/PartOrders.dadx" use="literal"/>
        </input>
        <output>
          <soap:body namespace="urn:/sales/PartOrders.dadx" use="literal"/>
        </output>
      </operation>
    </soap:binding>
  </binding>
  <binding name="theGetBinding" type="tns:thePortType">
    <http:binding verb="GET"/>
    <operation name="findAll">
      <http:operation location="findAll"/>
      <input>
        <http:urlEncoded/>
      </input>
      <output>
        <mime:mimeXml/>
      </output>
    </operation>
    <operation name="findByColor">
      <http:operation location="findByColor"/>
      <input>
        <http:urlEncoded/>
      </input>
      <output>
        <mime:mimeXml/>
      </output>
    </operation>
    <operation name="findByMinPrice">
      <http:operation location="findByMinPrice"/>
      <input>
        <http:urlEncoded/>
      </input>
      <output>
        <mime:mimeXml/>
      </output>
    </operation>
  </binding>
  <binding name="thePostBinding" type="tns:thePortType">
    <http:binding verb="POST"/>
    <operation name="findAll">
      <http:operation location="findAll"/>
      <input>
        <mime:content type="application/x-www-form-urlencoded"/>
      </input>
      <output>
        <mime:mimeXml/>
      </output>
    </operation>
    <operation name="findByColor">
      <http:operation location="findByColor"/>
      <input>
        <mime:content type="application/x-www-form-urlencoded"/>
      </input>
      <output>
        <mime:mimeXml/>
      </output>
    </operation>
    <operation name="findByMinPrice">
      <http:operation location="findByMinPrice"/>
      <input>
        <mime:content type="application/x-www-form-urlencoded"/>
      </input>
      <output>
        <mime:mimeXml/>
      </output>
    </operation>
  </binding>
  <service name="theService">
    <port binding="tns:theSoapBinding" name="theSoapPort">
      <soap:address location="http://localhost:8080/services/sales/PartOrders.dadx/SOAP"/>
    </port>
    <port binding="tns:theGetBinding" name="theGetPort">
      <http:address location="http://localhost:8080/services/sales/PartOrders.dadx/"/>
    </port>
    <port binding="tns:thePostBinding" name="thePostPort">
      <http:address location="http://localhost:8080/services/sales/PartOrders.dadx/"/>
    </port>
  </service>
</definitions>

Each of the generated WSDL elements is described below.

<definitions>

The <definitions> element declares the XML namespaces used in the document. All of the attributes are constant except for the following:

<import>

An <import> element is generated for each DTD that is referenced from the DADX file. The import associates an XSD namespace and  location with each DTDID that is used by the DAD documents that are referenced by the DADX document that defines the Web Service. The XSD namespace and location are associated with the DTDID using the DxxInvoker namespaceTable parameter described above.

<documentation>

The <documentation> element is directly copied from the DADX document element that has the XPath /DADX/documentation .

<types>

The <types> element contains XML Schema definitions used by the messages. In this example, each operation is implemented by retrieveXML which returns a result set that consists of zero or more documents that have the structure defined by the DTD referenced by the DAD document. Here all result sets use  getstart.dtd with the <Order> element as the root. The <schema> element uses the namespace associated with the xsd1 prefix as declared in the <definitions> element. Each result set in this example consists of zero or more <Order> elements. An XML Schema type is defined for the result set of each operation. The name of the result root element is the operation name suffixed by the string 'Result'.

<message>

The <message> element defines the input and output messages for each operation. The message names are generated by appending the strings 'Input' and 'Output' to the operation names. For retrieveXML, the input message contains a <part> element for each input parameter. For retrieveXML the output is a result set of zero or more documents. The result set elements are defined in the <types> element. The output message has a single part named return.

<portType>

The <portType> element defines the operations. Each operation in the DADX document corresponds to an <operation> element in the WSDL document. Within each <operation> element, the <documentation> element is copied from the DADX element that has XPath /DADX/operation/documentation. The input and output messages are as defined in the <message> elements.

<binding>

The <binding> element defines the binding of the Web Service to the protocols HTTP SOAP, HTTP GET, and HTTP POST. For each protocol binding, each operation is bound to the protocol.

For HTTP SOAP, a soapAction is set to the target namespace of the WSDL file that defines the operations. The style is set to rpc and the encoding is set to SOAP encoding.

For HTTP GET the input is set to http:urlEncoded, which means that the input parameters are encoded as the query string of the request URL. The output is set to mime:mimeXML which means that the response body is text/xml.

For HTTP POST the input is set to mime:application/x-www-form-urlencoded which means that the parameters are sent as a query string in the request body. The output is set to mime:mimeXml which means that the response body is text/xml.

<service>

The <service> element defines a port for each of the protocol bindings. The port includes the address of the service endpoint. The <service> element defines how the service instance is deployed.

For HTTP SOAP, the address is the URL of the DADX document.

For HTTP GET and POST, the address is the URL of the DADX document suffixed by '/' since this acts as the base for the URL for each operation. The operation name is appended to this base URL to define the complete URL for each operation. For example, the URL for findAll is:

UDDI Support

In the UDDI best practices document for using WSDL with UDDI Registries, it is recommended that the WSDL document be split into two parts, referred to as the deployment and reusable parts. The deployment part includes the <service> element which contains the URLs where the service is deployed. The deployment part imports the resuable part which contains the other top level WSDL elements.

The resuable part corresponds to a UDDI <tModel> element and the deployment part corresponds to a UDDI <businessService>. Within the <businessService> element, each WSDL <port> element corresponds to a UDDI <bindingTemplate> element.

To support UDDI we therefore need to generate the deployment and reusable WSDL documents. The URL to generate the deployment part is:

The URL to generate the reusable part is: In our example, the deployment part is PartOrders-service.wsdl and the reusable part is PartOrders-binding.wsdl.

Implementing a Standard Web Service

The preceeding example deals with the case where the service implementor creates a Web Service that is unique to his company. However, one of the usage scenarios that UDDI is designed to handle is the case in which a standards body or vendor defines a Web Service interface tModel, and service implementors use it. For example, the airline industry could define a Web Service that provided flight schedule which airlines would then implement. UDDI allows users to search for all registered services that implement a given tModel, so a travel planning application could locate all the airline flight schedule services.

For example, suppose the finctional Part Ordering Industry Association defined the Web Service for our example, and suppose the resuable WSDL for this service is hosted at http://www.poia.org/PartOrders.wsdl. The reusable WSDL  is poia-PartOrder.wsdl, which differs from PartOrders-binding.wsdl in its namespaces and documentation.

<implements>

The DADX <implements> element allows the service implementor to declare that the service implements a Web Service described by a reusable WSDL document defined elsewhere. The DADX document to implement the standard Web Service is PoiaPartOrders.dadx.

The generated deployment WSDL documents are PoiaPartOrders.wsdl, PoiaPartOrders-service.wsdl, and PoiaPartOrders-binding.wsdl.

If the Part Ordering Industry Association also defines its own XML Schemas, then the namespace table used by DxxInvoker must also be modified to map the DTDIDs to the standard XML Schema namespaces.

Summary

This document described the DADX document format and runtime. The DADX runtime supports the rapid development of Web Services through the use of SQL and the DB2 XML Extender. The DADX runtime allows the developer to focus on the definition of the service without requiring detailed knowledge of XML, XSD, SOAP, WSDL, or UDDI. DADX operations can be defined using standard SQL or can use the DB2 XML Extender.

This document described the DADX document format. For further information see the samples provided in the services Web application.

Resources

Changes from DADX 0.95