WSDL and the XML Schema Specification
Even though you can use any encoding format for WSDL type definitions, the WSDL specification suggests using XML Schema Definitions (XSD). XSD or XML Schema is a W3C standard that seeks to supersede the document type definition (DTD) standard for defining structure within an XML document. XML Schema defines a comprehensive set of programming-language independent, primitive/simple data types, such as doubles, strings, and integers, as well as a mechanism for creating complex types using the predefined simple types (see Table 1).
Table 1. XML Schema Simple Types: The table shows a list of the simple types predefined in XSD.
| Simple Type | Examples |
| string | This is a string |
| normalizedString | This is a normalized string |
| token | This is a token |
| base64Binary | GpM7 |
| hexBinary | 0FB7 |
| integer | -1, 0, 103 |
| positiveInteger | 1, 2, 215 |
| negativeInteger | -563, -2, -1 |
| nonNegativeInteger | 0, 1, 2, 672 |
| nonPositiveInteger | 37 -2, -1, 0 |
| long | -9223372036854775808, ... -1, 0, 1, ... 9223372036854775807 |
| unsignedLong | 0, 1, ... 18446744073709551615 |
| int | -2147483648, ... -1, 0, 1, ... 2147483647 |
| unsignedInt | 0, 1, ...4294967295 |
| short | -32768, ... -1, 0, 1, ... 32767 |
| unsignedShort | 0, 1, ... 65535 |
| byte | -128, ...-1, 0, 1, ... 127 |
| unsignedByte | 0, 1, ... 255 |
| decimal | -1.23, 0, 123.4, 1000.00 |
| float | -INF, -1E4, -0, 0, 12.78E-2, 12, INF, NaN |
| double | -INF, -1E4, -0, 0, 12.78E-2, 12, INF, NaN |
| boolean | true, false, 1, 0 |
| duration | P1Y2M3DT10H30M12.3S |
| dateTime | 1999-05-31T13:20:00.000-05:00 |
| date | 1999-05-31 |
| time | 13:20:00.000, 13:20:00.000-05:00 |
| gYear | 1999 |
| gYearMonth | 1999-02 |
| gMonth | 05 |
| gMonthDay | 05-31 |
| gDay | -31 |
| Name | shipTo |
| QName | po:USAddress |
| NCName | USAddress |
| anyURI | http://www.example.com/,http://www.example.com/doc.html#ID5 |
| language | en-GB, en-US, fr |
Declaring New Data Types in a WSDL Document
The XML Schema specification provides a feature for defining custom data types. Whenever a service requires data that can be represented more conveniently with abstractions beyond the scope of the simple XML Schema data types, these abstractions can be declared as new data types within the WSDL <types> element. The example in Listing 1 defined the custom data type shown below:
<complexType name="HelloWorld">
<sequence>
<element name="message"
type="string"
minOccurs="1"/>
</sequence>
</complexType>
The definition represents the message data type as a simple string, and the new type definition adds a constraint to the data typethe element is required to appear because the value of the minOccurs attribute is greater than zero. <complexType name="AddressType">
<sequence>
<element name="streetName"
type="string"
minOccurs="1"/>
<element name="city"
type="string"
minOccurs="1"/>
<element name="state"
type="string"
minOccurs="1"/>
<element name="zip"
type="string"
minOccurs="1"/>
<element name="phoneNumber"
type="string"
minOccurs="1"/>
</sequence>
</complexType>
In the preceding example, <AddressType> defines a custom data type that encapsulates user contact information. Notice that the <state> element is defined as a simple string, allowing virtually any text content of any length to occur in the element. A more robust method would constrain the state element to a two-letter abbreviation by defining a custom "two-letter-state" data type and then referencing that in the <AddressType> data type. Here's a custom string data type restricted to a length of two: <simpleType name="two-letter-state">
<restriction base="string">
<length value="2"/>
</restriction>
</simpleType>
It's relatively easy to see the relationship between data type definitions in XSD schema and object definitions in Java (or other languages) expressed in code. You can make these relationships explicit using mapping software.| XSD Type | Java Type |
| base64Binary | byte[] |
| hexBinary | byte[] |
| boolean | Boolean |
| byte | Byte |
| dateTime | java.util.Calendar |
| date | java.util.Calendar |
| time | java.util.Calendar |
| decimal | java.math.BigDecimal |
| double | Double |
| float | Float |
| hexBinary | byte[] |
| int | Int |
| unsignedShort | Int |
| integer | java.math.BigInteger |
| long | Long |
| unsignedInt | Long |
| QName | javax.xml.namespace.QName |
| short | Short |
| unsignedByte | Short |
| string | java.lang.String |
| anySimpleType | java.lang.String |
Building Custom WSDL Interpreters with XMLBeans
The WSDL2Java class below is an example of a simple WSDL-to-Java interpreter using XMLBeans. You can download all the source code for this article to follow along.
package com.jeffhanson.clienttier;
import org.apache.xmlbeans.*;
import org.apache.xmlbeans.impl.xb.xsdschema.*;
import org.apache.xmlbeans.impl.xb.xsdschema.impl.*;
import org.apache.xmlbeans.impl.xb.substwsdl.*;
import org.apache.xmlbeans.impl.util.FilerImpl;
import
org.apache.xmlbeans.impl.schema.SchemaTypeSystemCompiler;
import
org.apache.xmlbeans.impl.schema.SchemaTypeLoaderImpl;
import org.apache.xmlbeans.impl.schema.StscState;
import org.apache.xmlbeans.impl.common.XmlErrorWatcher;
import org.apache.xmlbeans.impl.common.IOUtil;
import java.util.*;
import java.io.File;
import repackage.Repackager;
public class WSDL2Java
{
private static class MyResolver
implements org.xml.sax.EntityResolver
{
public
org.xml.sax.InputSource resolveEntity(
String publicId,
String systemId)
{
System.out.println("System ID: " + systemId);
return null;
}
}
...
The generate method shown in Listing 2 parses a given WSDL file and generates Java code representing the data types found in the <Types> section of the WSDL document. private SchemaTypeSystem compileSchemas(
String schemaFilesDir, ArrayList scontentlist,
MyResolver entityResolver,
XmlErrorWatcher errorListener)
{
SchemaDocument.Schema[] sdocs =
(SchemaDocument.Schema[])scontentlist.toArray(
new SchemaDocument.Schema[scontentlist.size()]);
ResourceLoader cpResourceLoader = null;
SchemaTypeLoader linkTo =
SchemaTypeLoaderImpl.build(null,
cpResourceLoader, null);
File baseDir = new File(System.getProperty(
"user.dir"));
java.net.URI baseURI = baseDir.toURI();
XmlOptions opts = new XmlOptions();
opts.setCompileNoValidation();
opts.setEntityResolver(entityResolver);
Map sourcesToCopyMap = new HashMap();
File schemasDir = IOUtil.createDir(new File("."),
schemaFilesDir);
// create parameters for the main compile function
SchemaTypeSystemCompiler.Parameters params =
new SchemaTypeSystemCompiler.Parameters();
params.setName(null);
params.setSchemas(sdocs);
params.setLinkTo(linkTo);
params.setOptions(opts);
params.setErrorListener(errorListener);
params.setJavaize(true);
params.setBaseURI(baseURI);
params.setSourcesToCopyMap(sourcesToCopyMap);
params.setSchemasDir(schemasDir);
System.out.println("Compiling schemas...");
try
{
// create schema files (.xsb's)
SchemaTypeSystem sts =
SchemaTypeSystemCompiler.compile(params);
// now save .xsb's to disk
sts.saveToDirectory(schemasDir);
System.out.println(
"Schema compilation succeeded");
return sts;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
The generateJavaSource method generates Java source files for the WSDL data types that have previously been added to a given type system. private List generateJavaSource(String schemaClassesDir,
String schemaSrcDir, SchemaTypeSystem sts)
{
File classesDir = new File(schemaClassesDir);
File srcDir = IOUtil.createDir(new File("."),
schemaSrcDir);
// now, generate the source files
XmlOptions options = new XmlOptions();
boolean verbose = false;
boolean incrSrcGen = false;
Repackager repackager = null;
FilerImpl filer = new FilerImpl(classesDir,
srcDir, repackager, verbose, incrSrcGen);
System.out.println("Generating Java source...");
if (SchemaTypeSystemCompiler.generateTypes(sts,
filer, options))
{
System.out.println(
"Java source generation succeeded");
return filer.getSourceFiles();
}
else
{
System.out.println("Java source generation failed");
}
return null;
}
The addWsdlSchemas method shown in Listing 3 extracts the <Types> array from a WSDL definition document and adds the schemas representing each type to the content list. package com.jeffhanson.clienttier;
import org.apache.xmlbeans.impl.tool.CodeGenUtil;
import org.apache.xmlbeans.impl.common.IOUtil;
import java.io.File;
import java.util.List;
public class JavaSourceCompiler
{
public JavaSourceCompiler()
{
}
public void generate(String schemasDirName,
List sourceFiles,
String classesDirName)
{
File classesDir = new File(classesDirName);
File schemasDir = IOUtil.createDir(new File("."),
schemasDirName);
boolean verbose = false;
// now, compile source files
String compiler =
"/tools/VMs/j2sdk1.4.2_04/bin/javac.exe";
File[] tempClasspath = CodeGenUtil.systemClasspath();
File[] classpath = new
File[tempClasspath.length + 1];
System.arraycopy(tempClasspath, 0, classpath, 0,
tempClasspath.length);
classpath[tempClasspath.length] = schemasDir;
boolean debug = false;
String javasource = null;
String memoryInitialSize =
CodeGenUtil.DEFAULT_MEM_START;
String memoryMaximumSize =
CodeGenUtil.DEFAULT_MEM_MAX;
boolean quiet = true;
System.out.println("Compiling Java source files...");
if (CodeGenUtil.externalCompile(
sourceFiles, classesDir,
classpath, debug, compiler, javasource,
memoryInitialSize, memoryMaximumSize,
quiet, verbose))
{
System.out.println("Source compile succeeded");
}
else
{
System.out.println("Source compile failed");
}
}
}
I urge you to download the source code for this article and experiment with it yourself.
Web services messaging and XML-based data transfer has created a need to for a structured way to express message exchanges. The Web services Description Language (WSDL) deals with this need by defining an XML-based service description and generic data-type system for any programming language.
| DevX is a division of Jupitermedia Corporation © Copyright 2007 Jupitermedia Corporation. All Rights Reserved. Legal Notices |