WSDL Essentials, Page 4
Complex Types
Our final topic is the use of complex data types. For example, consider a home monitoring service that provides a concise update on your home. The data returned could include multiple data elements, such as the current temperature, security status, and whether the garage door is open or closed. Encoding this data into WSDL requires additional knowledge of XML Schemas, which reinforces the main precept that the more you know about XML Schemas, the better you will understand complex WSDL files.
To explore complex types, consider the WSDL file in Example 6-10. This WSDL file describes our Product Service from Chapter 5. The complex types are indicated in bold.
Example 6-10: ProductService.wsdl
<?xml version="1.0" encoding="UTF-8"?><definitions name="ProductService"targetNamespace="http://www.ecerami.com/wsdl/ProductService.wsdl"xmlns="http://schemas.xmlsoap.org/wsdl/"xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"xmlns:tns="http://www.ecerami.com/wsdl/ProductService.wsdl"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:xsd1="http://www.ecerami.com/schema"><types><xsd:schematargetNamespace="http://www.ecerami.com/schema"xmlns="http://www.w3.org/2001/XMLSchema"><xsd:complexType name="product"><xsd:sequence><xsd:element name="name" type="xsd:string"/><xsd:element name="description" type="xsd:string"/><xsd:element name="price" type="xsd:double"/><xsd:element name="SKU" type="xsd:string"/></xsd:sequence></xsd:complexType></xsd:schema></types><message name="getProductRequest"><part name="sku" type="xsd:string"/></message><message name="getProductResponse"><part name="product" type="xsd1:product"/></message><portType name="Product_PortType"><operation name="getProduct"><input message="tns:getProductRequest"/><output message="tns:getProductResponse"/></operation></portType><binding name="Product_Binding" type="tns:Product_PortType"><soap:binding style="rpc"transport="http://schemas.xmlsoap.org/soap/http"/><operation name="getProduct"><soap:operation soapAction="urn:examples:productservice"/><input><soap:bodyencodingStyle="http://schemas.xmlsoap.org/soap/encoding/"namespace="urn:examples:productservice"use="encoded"/></input><output><soap:bodyencodingStyle="http://schemas.xmlsoap.org/soap/encoding/"namespace="urn:examples:productservice" use="encoded"/></output></operation></binding><service name="Product_Service"><port name="Product_Port" binding="tns:Product_Binding"><soap:address location="http://localhost:8080/soap/servlet/rpcrouter"/></port></service></definitions>
The service in Example
6-10 describes a getProduct operation that
returns a complex product type for encapsulating
product information, including product name, description, price, and SKU
number.
The new product type is defined in much the same manner as the
array definition from the previous example. The main difference is that we are
now using the sequence element. The sequence element specifies a list of subelements and
requires that these elements appear in the order specified. XML Schemas also
enable you to specify cardinality via the minOccurs
and maxOccurs attributes. If these attributes are
absent (as in our example), they default to 1,
requiring that each subelement must occur exactly one time.
Each subelement can also have its own data type, and you can see that we have mixed and matched string data types with double data types in our example.
Automatically invoking complex type services
To automatically invoke the Product Service, we return to the
GLUE wsdl2java tool. This time around, GLUE will
generate a Java interface class and a Java helper class, along with two
additional files for handling the new complex type.
For example, the following command:
wsdl2java.bat http://localhost:8080/wsdl/ProductService.wsdl -p com.ecerami.wsdl.glue
generates the following output:
write file IProduct_Service.javawrite file Product_ServiceHelper.javawrite file product.javawrite file Product_Service.map
The first two files in the output listing are familiar. The first file is a Java interface mirroring the service; the second file is a helper class for dynamically binding to the specified service. (See Example 6-11 and Example 6-12.)
Example 6-11: IProduct_Service.java
// generated by GLUEpackage com.ecerami.wsdl.glue;public interface IProduct_Service{product getProduct( String sku );}
Example 6-12: Product_ServiceHelper.java
// generated by GLUEpackage com.ecerami.wsdl.glue;import electric.registry.Registry;import electric.registry.RegistryException;public class Product_ServiceHelper{public static IProduct_Service bind( ) throws RegistryException{return bind( "http://localhost:8080/wsdl/ProductService.wsdl" );}public static IProduct_Service bind( String url )throws RegistryException{return (IProduct_Service)Registry.bind( url, IProduct_Service.class );}}
The third file in the output listing, product.java, represents a simple container class for
encapsulating product data. (See Example 6-13.) GLUE essentially takes all the
complex types defined within the WSDL file and creates a container class for
each type. Each subelement is then transformed into a public variable for easy
access. For example, the product class has four
public variables, name, description, price, and SKU, corresponding to our new complex data type. Note
also that the public variables match the XML Schema types specified within the
WSDL file; for example, name is declared as a String, whereas price is
declared as a double.
Example 6-13: product.java
// generated by GLUEpackage com.ecerami.wsdl.glue;public class product{public java.lang.String name;public java.lang.String description;public double price;public java.lang.String SKU;}
Finally, GLUE generates a Java-to-XML Schema mapping file. (See
Example
6-14.) The file itself is extremely concise and is responsible for
converting Java to XML Schema types and vice versa. (See Figure
6-13.) The root complexType element indicates
that elements of type product should be transformed
into the product class located in com.ecerami.wsdl.glue. Inside the root complex type,
there is a one-to-one mapping between the XML Schema type and the public Java
variable. For example, the element name is mapped
to the product.name variable, and the type is
specified as string. Likewise, the element price is mapped to the product.price variable, and the type is specified as
double.
|
|
Example 6-14: Product_Service.map
<?xml version='1.0' encoding='UTF-8'?><!--generated by GLUE--><mappings xmlns='http://www.themindelectric.com/schema/'><schemaxmlns='http://www.w3.org/2001/XMLSchema'targetNamespace='http://www.ecerami.com/schema'xmlns:electric='http://www.themindelectric.com/schema/'><complexType name='product' electric:class='com.ecerami.wsdl.glue.product'><sequence><element name='name' electric:field='name' type='string'/><element name='description'electric:field='description' type='string'/><element name='price' electric:field='price' type='double'/><element name='SKU' electric:field='SKU' type='string'/></sequence></complexType></schema></mappings>
To invoke the Product Service, you must first explicitly load
the mapping file via the GLUE Mappings class:
Mappings.readMappings("Product_Service.map");
You can then access the service just like in the previous example. See Example 6-15 for the complete invocation program. Here is some sample output:
Product ServiceName: Red Hat LinuxDescription: Red Hat Linux Operating SystemPrice: 54.99
Example 6-15: Invoke_Product.java
package com.ecerami.wsdl;import java.io.IOException;import electric.xml.io.Mappings;import electric.xml.ParseException;import electric.registry.RegistryException;import com.ecerami.wsdl.glue.*;/*** SOAP Invoker. Uses the Product_ServiceHelper to invoke the Product* SOAP service. All other .java files are automatically generated* by GLUE.*/public class Invoke_Product {/*** Get Product via SOAP Service*/public product getProduct (String sku) throws Exception {// Load Java <--> XML MappingMappings.readMappings("Product_Service.map");// Invoke ServiceIProduct_Service service = Product_ServiceHelper.bind( );product prod = service.getProduct(sku);return prod;}/*** Main Method*/public static void main (String[] args) throws Exception {Invoke_Product invoker = new Invoke_Product( );System.out.println ("Product Service");product prod = invoker.getProduct("A358185");System.out.println ("Name: "+prod.name);System.out.println ("Description: "+prod.description);System.out.println ("Price: "+prod.price);}}
This is a very small amount of code, but it is capable of doing very real work. Be sure to check The Mind Electric web site (http://themindelectric.com/) for new releases of the GLUE product.
About the Author
Ethan Cerami is a Software Engineer at the Institute for Computational Biomedicine at Mount Sinai School of Medicine and an Adjunct Faculty at NYU's Department of Computer Science. He is also the author of Delivering Push (McGraw-Hill, 1998) and co-author with Simon St. Laurent of Building XML Applications (McGraw-Hill, 2000).
Source of this material
![]() |
This is Chapter 6: WSDL Essentials from the book Web Services Essentials (ISBN:0-596-00224-6) written by Ethan Cerami, published by O'Reilly & Associates. |
To access the full Table of Contents for the book

