Friday, October 28, 2011

Using Java to Handle Custom WSDL Data Types

What happens when neither the default WSDL type system nor the default encoding meet your application's needs? Don't worry, you can use custom data types and encoding formats in conjunction with Java to solve the problem.
he onslaught of Web services messaging and XML-based data transfer has led to a need to express these message exchanges in some structured way. The Web services Description Language (WSDL) deals with this need by defining an XML grammar for exposing services as sets of endpoints for exchanging related messages. WSDL (pronounced "wizdle") documents provide a standard means for describing services by outlining the data types consumed by the services, the URL for communicating with the services, and the names by which services are known.

WSDL documents are quickly becoming the key to successful B2B interoperability. A WSDL document provides a generic Web service description without regard for the specific programming language in which the services are written. Developers can use WSDL documents to generate client code that can communicate with the corresponding Web services. This generic form of service/component description has been attempted in the past by various binary forms of interface description languages (IDLs), but never has it seen such widespread use as with WSDL and Web services.

One reason for the success of WSDL-based service description is the pervasive use of XML and its ability to define virtually any data type for any programming language in a generic way. This article discusses how to handle custom WSDL data types in the Java programming language.

Introducing WSDL
WSDL documents are XML documents that describe services as a set of message-enabled or procedure-oriented abstract endpoints. These operations and/or messages and their associated data types are described conceptually, and then bound concretely to a network protocol, message format, and programming language as needed.

A WSDL document defines the following elements for describing services:

  • Types—data type definitions
  • Message—an abstract definition of the data being transferred
  • Operation—an abstract description of a service procedure
  • Port Type—an abstract set of operations supported by one or more endpoints
  • Binding—a concrete protocol and data format for a given port type
  • Port—a single endpoint defined as a binding and a network address
  • Service—a collection of related endpoints or ports
WSDL and Data Types
It's challenging for Web services providers to expose a data type system that can be understood by the broadest range of Web services consumers, yet that understanding must be in place for Web service consumers and providers to communicate effectively. Because different programming languages each have their own set of idiosyncrasies, creating a common data type system is of primary importance.

In contrast to previous attempts at a generic interface definition language (IDL) and a common data-type system, such as COM, DCOM, and CORBA, WSDL solves the common data-type problem by aiming for maximum flexibility rather than attempting to create an all-inclusive data-typing standard. Thus, WSDL is not bound to any one data type system. However, WSDL does recommend the W3C XML Schema specification as the canonical type system, thereby intrinsically treating the most widely used data type system as the default.




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

The WSDL <types> element defines data types that are to be exchanged between service consumers and providers. If the service defined by the WSDL document uses only the built-in XML Schema simple types, you don't have to include a <types> element; instead, you can use the element to define your own types. Listing 1 shows a simple WSDL document that includes a <types> element:




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 type—the element is required to appear because the value of the minOccurs attribute is greater than zero.

A more sophisticated use of a custom data type might include contact information for a user such as the following:

   <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 Data Types and Java Data Types
The Java programming language provides data types that can be mapped to represent most of the standard XSD data types. Table 2 contains a list of mappings from XSD data types to Java data types:

Table 2. XSD-to-Java Mappings: The table shows how you can map a list of XSD data types to their equivalents in Java.
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

The mappings in Table 2 illustrate a comprehensive list of simple data type mappings; however, as you need more complex abstractions and need to extend XSD types with custom type declarations, it also becomes more complex to map such types to Java. Mapping custom type declarations is the focus of this article. First, though, here's a brief overview of the XML tools you'll need to implement the mapping operation.

Streaming API for XML (StAX)
XSD and WSDL are XML-based grammars that you can process using standard XML-processing techniques. XML processing in Java has evolved into two main approaches:

  1. The Simple API for XML processing (SAX)
  2. The Document Object Model (DOM)
SAX exposes a callback-style parsing API while DOM provides a randomly-accessible tree-like structure.

The Streaming API for XML (StAX) specification defines a new and highly-efficient API for parsing and streaming XML. The StAX specification defines a bi-directional API for reading and writing XML. StAX allows developers to maintain parsing control by exposing a simple iterator-based API, with intuitive methods such as next() and hasNext(), as well as an underlying stream of events. This iterator-based API lets you "pull" the next event rather than handling the event in a callback. The cursor API facilitates processing-control even further by letting you stop processing, skip ahead to sections of a document, and retrieve subsections of a document.

Introducing XMLBeans
Apache XMLBeans is an open source, XML-Java binding tool based on the StAX specification. You can use XMLBeans to generate Java classes and interfaces from an XML schema, subsequently using those generated Java classes to parse or generate XML documents that conform to the schema.

BEA originated XMLBeans and then donated it to the Apache Software Foundation. XMLBeans provides three major APIs for access to XML and schema:

  • Strongly-typed access—XMLBeans can compile an XML schema to generate Java classes and interfaces. The generated classes and interfaces all extend a common base class and provide strongly-typed getters and setters for each of the elements found in the schema.
  • Cursor-style access—From any generated class you can get instance of a positional cursor object that allows low-level access to the XML information.
  • Schema-style access—XMLBeans provides a schema object model that you can use to reflect on the XML schema.
Installing XMLBeans
To install XMLBeans, download the binary distribution of XMLBeans, and extract the archive into the directory of your choice. Next, define an XMLBEANS_HOME environment variable with a value set to the directory where you extracted the binary distribution files. Finally, add the .jar and .zip files contained in the XMLBeans distribution to your project.

The remainder of this article demonstrates how to implement a simple WSDL-to-Java interpreter using the XMLBeans framework and APIs. It's important to understand that as Web service providers increasingly adopt WSDL as the doctrine of exchange for integrating with their systems via publicly-accessible services, service clients must have the ability to process WSDL dynamically to leverage those services. That's because the WSDL document may often be the only point of access to service information. Fortunately, when properly prepared, the WSDL document is also all that clients need.

The XMLBeans framework facilitates the ability to compile a WSDL file into Java objects. With this facility, developers can dynamically generate Web service clients from WSDL documents, using the resulting Java classes and interfaces associated with the data types and methods of the Web service. Interpreting WSDL dynamically offers a degree of power greater than standard static XML-parsing and processing techniques.




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.

The compileSchemas method creates the XMLBeans-specific schema files (.xsb's) and saves them to disk.

   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.

The JavaSourceCompiler class uses utilities from the XMLBeans API to compile previously generated Java source files:

   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.

The WSDL data-type system defines data types that can be exchanged between service consumers and providers. WSDL allows you to use the built-in XML-Schema simple types, or you can define your own custom types.

The Streaming API for XML (StAX) specification defines a new API using a bi-directional API for parsing and streaming XML. StAX allows you to maintain parsing control by exposing a simple iterator-based API, as well as a cursor API. The iterator-based API lets you "pull" events as needed. The cursor API facilitates processing-control even further by letting you stop processing, skip ahead to sections of a document, and retrieve subsections of a document.

Apache XMLBeans (originated by BEA and then donated to Apache) is an open source, XML-Java binding tool based on the StAX specification that can be used to generate Java classes and interfaces from an XML schema. These classes and interfaces can then be used to parse or generate XML documents that conform to the schema.

The combination of StAX and the XMLBeans framework allows developers to dynamically interpret and operate on WSDL documents and the data-types declared therein with a greater degree of power and flexibility than standard static XML-parsing and processing techniques.

http://www.devx.com/Java/Article/29286/1954

Parse WSDL effectively

As a WSDL’s constituents are well-defined already, it is feasible to use a parser that can get the elements of the WSDL using APIs that are already defined. This will minimize complexity in the code and will help in achieving better performance.

Oracle WSDL parser is one such option.

It is only needed to import the necessary classes as the APIs are already defined and packaged with wsdl.jar.

//importing the necessary classes from library
import oracle.wsdl.WSDLDocument;
import oracle.wsdl.internal.Binding;
import oracle.wsdl.internal.Definitions;
import oracle.wsdl.internal.Documentation;
import oracle.wsdl.internal.Import;
import oracle.wsdl.internal.Message;
import oracle.wsdl.internal.PortType;
…….


WSDLDocument wsdldoc = new WSDLDocument(wsdl_url);
//getting definition element
Definitions definition = wsdldoc.getDefinitions();
//getting service element
Map servicesMap = definition.getServices();
//getting binding element
Map bindingsMap = definition.getBindings();
//getting PortType element
Map ptypesMap = definition.getPortTypes();
//getting message element
Map messagesMap = definition.getMessages();
//getting import details
Map importsMap = definition.getImports();
//getting documentation details
Documentation docs = definition.getDocumentation();


As there can be multiple elements, an “iterator” can be used to parse an individual element.
For Example:

Iterator iterator = servicesMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry me = (Map.Entry) iterator.next();
            …….
        }

The above code fragments keep things fairly simple while processing a WSDL.

Apache Woden

Woden provides Java class library for reading, manipulating, creating and writing WSDL documents.

Woden’s DOM-based XML parsing depends on Apache Xerces 2.7.1. Its XML Schema support it depends on the schema parser and object model implemented by the Apache Web Services Commons (ws-commons) XmlSchema project.

//importing necessary classes from woden jars
import org.apache.woden.WSDLException;
import org.apache.woden.WSDLFactory;
import org.apache.woden.WSDLReader;
import org.apache.woden.wsdl20.Binding;
import org.apache.woden.wsdl20.Description;
import org.apache.woden.wsdl20.Interface;
import org.apache.woden.wsdl20.Service;
….

  

WSDLFactory factory = WSDLFactory.newInstance();
WSDLReader reader = factory.newWSDLReader();
reader.setFeature(WSDLReader.FEATURE_VALIDATION, true);
String wsdlurl = “C://axis2-1.4.1//newwsdl.wsdl”;

//reading the WSDL Document
DescriptionElement descElem = (DescriptionElement) reader.readWSDL(wsdlurl);
Description descComp = descElem.toComponent();

//getting Interface, Binding and Service elements
InterfaceElement[] interfaces = descElem.getInterfaceElements();
BindingElement[] bindings = descElem.getBindingElements();
ServiceElement[] services = descElem.getServiceElements();
  

Complete details about usage and extensibility of woden are available at:


JWSDL:


JWSDL is another option that is intended for use by developers of Web services tools and others who need to utilize WSDL documents in Java.
JWSDL is designed to allow users to read, modify, write, create and re-organize WSDL documents in memory. JWSDL is not designed to validate WSDL documents beyond syntactic validity. One use of JWSDL is to develop a tool that validates WSDL semantically.
JWSDL is designed for use in WSDL editors and tools where a partial, incomplete or incorrect WSDL document may require representation.
 
Details of JWSDL can be obtained by accessing the following link:




Source: http://oracled.wordpress.com/2009/02/04/parse-wsdl-effectively/

Create SOAP Request with Java

Create SOAP Request with Java

The Membrane SOA Model can create SOAP requests out of a WSDL document and a Java Map filled with the data for the request.
01.package sample.wsdl;
02. 
03.import groovy.xml.MarkupBuilder;
04.import java.io.StringWriter;
05.import java.util.HashMap;
06. 
07.import com.predic8.wsdl.*;
08.import com.predic8.wstool.creator.*;
09. 
10.public class CreateSOAPRequest {
11. 
12.public static void main(String[] args) {
13. 
14.WSDLParser parser = new WSDLParser();
15. 
16.Definitions wsdl = parser.parse("resources/article/article.wsdl");
17. 
18.StringWriter writer = new StringWriter();
19. 
20.HashMap<String, String> formParams = new HashMap<String, String>();
21.formParams.put("xpath:/create/article/name", "foo");
22.formParams.put("xpath:/create/article/description", "bar");
23.formParams.put("xpath:/create/article/price/amount", "00.00");
24.formParams.put("xpath:/create/article/price/currency", "USD");
25.formParams.put("xpath:/create/article/id", "1");
26. 
27.SOARequestCreator creator = new SOARequestCreator();
28.creator.setBuilder(new MarkupBuilder(writer));
29.creator.setDefinitions(wsdl);
30.creator.setFormParams(formParams);
31.creator.setCreator(new RequestCreator());
32. 
33.//creator.createRequest(PortType name, Operation name, Binding name);
34.creator.createRequest("ArticleServicePT", "create", "ArticleServicePTBinding");
35. 
36.System.out.println(writer);
37.}
38.}
Listing 1: CreateSOAPRequest

The following table shows the input for the SOARequestCreator.
Key Value
xpath:/create/article/name foo
xpath:/create/article/description bar
xpath:/create/article/price/amount 00.00
xpath:/create/article/price/currency USD
xpath:/create/article/id 1

Using the table above you get the following soap request message.
01.<s11:Envelope xmlns:s11='http://schemas.xmlsoap.org/soap/envelope/'>
02.<s11:Body>
04.<article xmlns:ns1='http://predic8.com/material/1/'>
05.<name xmlns:ns1='http://predic8.com/material/1/'>foo</name>
06.<description xmlns:ns1='http://predic8.com/material/1/'>bar</description>
07.<price xmlns:ns1='http://predic8.com/common/1/'>
08.<amount xmlns:ns1='http://predic8.com/common/1/'>00.00</amount>
09.<currency xmlns:ns1='http://predic8.com/common/1/'>USD</currency>
10.</price>
11.<id xmlns:ns1='http://predic8.com/material/1/'>1</id>
12.</article>
13.</ns1:create>
14.</s11:Body>
15.</s11:Envelope>
Listing 2: Created soap request message

Unbounded Elements

To create a list of repeating elements in a SOAP request square brackets can be used.
Listing 3 shows how to set the formParams from Listing 1 to create a request with more than one item.
01....
02.HashMap<String, String> formParams = new HashMap<String, String>();
03.formParams.put("xpath:/order/items/item[1]/name", "apple");
04.formParams.put("xpath:/order/items/item[1]/quantity", "3");
05.formParams.put("xpath:/order/items/item[1]/price", ".95");
06.formParams.put("xpath:/order/items/item[2]/name", "orange");
07.formParams.put("xpath:/order/items/item[2]/quantity", "5");
08.formParams.put("xpath:/order/items/item[2]/price", "1.45");
09....
Listing 3: CreateSOAPRequest with unbounded number of elements

Parsing WSDL with Java

The Membrane SOA Model makes it easy to parse a WSDL. See listing 1 for an example. It parses a WSDL document and prints out the interface of the service with its operations.
01.package sample.wsdl;
02. 
03.import com.predic8.wsdl.*;
04. 
05.public class ListWSDLOperations {
06. 
07.public static void main(String[] args) {
08.WSDLParser parser = new WSDLParser();
09. 
10.Definitions defs = parser
12. 
13.for (PortType pt : defs.getPortTypes()) {
14.System.out.println(pt.getName());
15.for (Operation op : pt.getOperations()) {
16.System.out.println(" -" + op.getName());
17.}
18.}
19.}
20.}
Listing 1: ListWSDLOperations.java
In listing 2 you can see the output.
01.XWebBlogInterface
02.-LoadEntry
03.-LoadBlog
04.-LoadBlogPaged
05.-GetNewEntryID
06.-AddEntry
07.-UpdateEntry
08.-DeleteEntry
09.-LoadBlogByDateRange
10.-LoadBlogByDateRangePaged
11.-ProcessEntry
12.-AddReply
13.-UpdateReply
14.-DeleteReply
15.-ProcessReply
16.-GetNewReplyID
17.-LoadReply
 
http://www.membrane-soa.org/parse-wsdl-java-api.htm
 

Understanding WSDL - Basics

XML makes it possible for developers to expose valuable resources in a highly interoperable fashion, where a resource is any type of application or data store used within an organization. The XML Web services architecture defines a standard mechanism for making resources available via XML messaging. Being able to access a resource by simply transmitting XML messages over standard protocols like TCP, HTTP, or SMTP greatly lowers the bar for potential consumers. The term "Web service" (or simply "service") typically refers to the piece of code implementing the XML interface to a resource, which may otherwise be difficult to access (see Figure 1).
Figure 1: Resources and services
This architecture makes it possible for any consumer with XML support to integrate with Web service applications. However, in order to accomplish this, consumers must determine the precise XML interface along with other miscellaneous message details a priori. XML Schema can partially fill this need because it allows developers to describe the structure of XML messages. XML Schema alone, however, can't describe the additional details involved in communicating with a Web service.
A schema definition simply tells you what XML messages may be used but not how they relate to each other. For example, if there's an XML element named Add and another named AddResponse, it's likely they're related to each other but there's no way to indicate that in the schema. Hence, in addition to being aware of the messages, consumers must also be aware of the possible message exchanges supported by the Web service (e.g., if you send an Add message, you get an AddResponse message back).
A message exchange is also referred to as an operation. Operations are what consumers care about most since they're the focal point of interacting with the service (see Figure 2). Whenever I approach a new Web service, I first inspect its list of supported operations to get an overall feel for what it offers.
Figure 2: Messages and operations
It's common for developers to group related operations into interfaces. Consumers must be aware of these groupings since it impacts the way they write their code. This is especially important to developers working with Web services in object-oriented environments since the XML interfaces can map to programmatic interfaces (or abstract classes) in their language of choice.
Consumers must also know what communication protocol to use for sending messages to the service, along with the specific mechanics involved in using the given protocol such as the use of commands, headers, and error codes. A binding specifies the concrete details of what goes on the wire by outlining how to use an interface with a particular communication protocol. A binding also influences the way abstract messages are encoded on the wire by specifying the style of service (document vs. RPC) and the encoding mechanism (literal vs. encoded). Check out Understanding SOAP for more background on these concepts.
A service can support multiple bindings for a given interface, but each binding should be accessible at a unique address identified by a URI, also referred to as a Web service endpoint (see Figure 3).
Figure 3: Interfaces and bindings
Consumers must discover all of the details described above before they can interact with a Web service. The Web Services Description Language (WSDL) provides an XML grammar for describing these details. WSDL picks up where XML Schema left off by providing a way to group messages into operations and operations into interfaces. It also provides a way to define bindings for each interface and protocol combination along with the endpoint address for each one. A complete WSDL definition contains all of the information necessary to invoke a Web service. Developers that want to make it easy for others to access their services should make WSDL definitions available.
WSDL plays an important role in the overall Web services architecture since it describes the complete contract for application communication (similar to the role of IDL in the DCOM architecture). Although other techniques exist for describing Web services, the WS-I Basic Profile Version 1.0 mandates the use of WSDL and XML Schema (see Figure 4) for describing Web services. This helps ensure interoperability at the service description layer.
Figure 4: WS-I Basic Profile 1.0 technologies
Since WSDL is a machine-readable language (e.g., it's just an XML file), tools and infrastructure can be easily built around it. Today developers can use WSDL definitions to generate code that knows precisely how to interact with the Web service it describes. This type of code generation hides the tedious details involved in sending and receiving SOAP messages over different protocols and makes Web services approachable by the masses.
The Microsoft® .NET Framework comes with a command-line utility named wsdl.exe that generates classes from WSDL definitions. Wsdl.exe can generate one class for consuming the service and another for implementing the service. (Apache Axis comes with a similar utility named WSDL2Java that performs the same function for Java classes.) Classes generated from the same WSDL definition should be able to communicate with each other through the WSDL-provided interfaces, regardless of the programming languages in use (see Figure 5).
Figure 5: WSDL and code generation
WSDL 1.1 is considered the de-facto standard today because of it's industry-wide support. Most Web services toolkits support WSDL 1.1, but there have been some interoperability problems across the different implementations. Many developers believe that the extensive flexibility of WSDL (and the resulting complexity) is the fundamental source of these problems. The WS-I has helped resolve some of these issues by encouraging developers to use certain parts of the specification and discouraging them from using others.
The W3C is actively working on the next "official" version of WSDL, WSDL 1.2, but it's currently only a Working Draft and not supported by the mainstream toolkits, if any. The remainder of this article discusses the details of a WSDL 1.1 definition and highlights some of the WS-I basic profile suggestions along the way.

WSDL Basics

A WSDL definition is an XML document with a root definition element from the http://schemas.xmlsoap.org/wsdl/ namespace. The entire WSDL schema is available at http://schemas.xmlsoap.org/wsdl/ for your reference. The definitions element may contain several other elements including types, message, portType, binding, and service, all of which come from the http://schemas.xmlsoap.org/wsdl/ namespace. The following illustrates the basic structure of a WSDL definition:
<!-- WSDL definition structure -->
<definitions 
    name="MathService"
targetNamespace="http://example.org/math/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
>
   <!-- abstract definitions -->
    <types> ...
    <message> ...
   <portType> ...

   <!-- concrete definitions -->
   <binding> ...
   <service> ...
</definition>
Notice that you must specify a target namespace for your WSDL definition, just like you would for an XML Schema definition. Anything that you name in the WSDL definition (like a message, portType, binding, etc.) automatically becomes part of the WSDL definition's target namespace defined by the targetNamespace attribute. Hence, when you reference something by name in your WSDL file, you must remember to use a qualified name.
The first three elements (types, message, and portType) are all abstract definitions of the Web service interface. These elements constitute the programmatic interface that you typically interface with in your code. The last two elements (binding and service) describe the concrete details of how the abstract interface maps to messages on the wire. These details are typically handled by the underlying infrastructure, not by your application code. Table 1 provides brief definitions for each of these core WSDL elements and the remaining sections discuss them in more detail.
Table 1. WSDL Elements
Element Name Description
types A container for abstract type definitions defined using XML Schema
message A definition of an abstract message that may consist of multiple parts, each part may be of a different type
portType An abstract set of operations supported by one or more endpoints (commonly known as an interface); operations are defined by an exchange of messages
binding A concrete protocol and data format specification for a particular portType
service A collection of related endpoints, where an endpoint is defined as a combination of a binding and an address (URI)

Types

The WSDL types element is a container for XML Schema type definitions. The type definitions you place here are referenced from higher-level message definitions in order to define the structural details of the message. Officially, WSDL 1.1 allows the use of any type definition language, although it strongly encourages the use of XML Schema and treats it as its intrinsic type system. The WS-I enforces this by mandating the use of XML Schema in the Basic Profile 1.0.
The types element contains zero or more schema elements from the http://www.w3.org/2001/XMLSchema namespace. The basic structure of the types element (with namespaces omitted) is as follows (* means zero or more):
<definitions .... >
    <types>
        <xsd:schema .... />*
    </types>
</definitions>
You can use any XML Schema construct within the schema element, such simple type definitions, complex type definitions, and element definitions. The following WSDL fragment contains an XML Schema definition that defines four elements of type MathInput (Add, Subtract, Multiply, and Divide) and four elements of type MathOutput (AddResponse, SubtractResponse, MultiplyResponse, and DivideResponse).
<definitions 
  xmlns="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:y="http://example.org/math/" 
  xmlns:ns="http://example.org/math/types/" 
  targetNamespace="http://example.org/math/"
>
  <types>
    <xs:schema 
      targetNamespace="http://example.org/math/types/" 
      xmlns="http://example.org/math/types/" 
    >
     <xs:complexType name="MathInput">
       <xs:sequence>
      <xs:element name="x" type="xs:double"/>
      <xs:element name="y" type="xs:double"/>
       </xs:sequence>
     </xs:complexType>
     <xs:complexType name="MathOutput">
       <xs:sequence>
         <xs:element name="result" type="xs:double"/>
       </xs:sequence>
     </xs:complexType>
     <xs:element name="Add" type="MathInput"/>
     <xs:element name="AddResponse" type="MathOutput"/>
     <xs:element name="Subtract" type="MathInput"/>
     <xs:element name="SubtractResponse" type="MathOutput"/>
     <xs:element name="Multiply" type="MathInput"/>
     <xs:element name="MultiplyResponse" type="MathOutput"/>
     <xs:element name="Divide" type="MathInput"/>
     <xs:element name="DivideResponse" type="MathOutput"/>
    </xs:schema>
  </types>
   ...
</definitions>
If you're new to XML Schema and need to ramp up, check out Understanding XML Schema. Once you have your XML Schema types defined, the next step is to define the logical messages that will constitute your operations.

Messages

The WSDL message element defines an abstract message that can serve as the input or output of an operation. Messages consist of one or more part elements, where each part is associated with either an element (when using document style) or a type (when using RPC style). The basic structure of a message definition is as follows (* means zero or more and ? means optional):
<definitions .... >
    <message name="nmtoken"> *
        <part name="nmtoken" element="qname"? type="qname"?/> *
    </message>
</definitions>
The messages and parts must be named making it possible to refer to them from elsewhere in the WSDL definition. If you're defining an RPC style service, the message parts represent the method's parameters. In this case, the name of the part becomes the name of an element in the concrete message and its structure is determined by the supplied type attribute. If you're defining a document style service, the parts simply refer to the XML elements that are placed within the body (referenced by the element attribute). The following example contains several message definitions that refer to elements by name:
<definitions 
  xmlns="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:y="http://example.org/math/" 
  xmlns:ns="http://example.org/math/types/" 
  targetNamespace="http://example.org/math/"
>
   ...
   <message name="AddMessage">
      <part name="parameter" element="ns:Add"/>
   </message>
   <message name="AddResponseMessage">
      <part name="parameter" element="ns:AddResponse"/>
   </message>
   <message name="SubtractMessage">
      <part name="parameter" element="ns:Subtract"/>
   </message>
   <message name="SubtractResponseMessage">
      <part name="parameter" element="ns:SubtractResponse"/>
   </message>
   ...
</definitions>
Although the message parts typically refer to XML types or elements, they can also refer to non-XML types. This allows WSDL to represent a wide range of messages that contain a mixture of data formats, as is the case with multi-part MIME.
Note   The message and type definitions in WSDL are considered to be abstract definitions. This means you don't know how they'll appear in the concrete message format until you've applied a binding to them. For example, if you use one abstract message with two different bindings, it's possible that the two concrete messages will look different. Only with 'literal' bindings are the abstract definitions guaranteed to accurately describe the concrete message format. See the Bindings section for more details.

Interfaces (portTypes)

The WSDL portType element defines a group of operations, also known as an interface in most environments. Unfortunately, the term "portType" is quite confusing so you're better off using the term "interface" in conversation. WSDL 1.2 has already removed "portType" and replaced it with "interface" in the current draft of the language.
A portType element contains zero or more operation elements. The basic structure of a portType is as follows (* means zero or more):
<definitions .... >
    <portType name="nmtoken">
        <operation name="nmtoken" .... /> *
    </portType>
</definitions>
Each portType must be given a unique name making it possible to refer to it from elsewhere in the WSDL definition. Each operation element contains a combination of input and output elements, and when you have an output element you can also have a fault element. The order of these elements defines the message exchange pattern (MEP) supported by the given operation.
For example, an input element followed by an output element defines a request-response operation, while an output element followed by an input element defines a solicit-response operation. An operation that only contains an input element defines a one-way operation, while an operation that only contains an output element defines a notification operation. Table 2 describes the four MEP primitives defined by WSDL.
Table 2. Message Exchange Patterns
MEP Description
One-way The endpoint receives a message.
Request-response The endpoint receives a message and sends a correlated message.
Solicit-response The endpoint sends a message and receives a correlated message.
Notification The endpoint sends a message.
The input, output, and fault elements used in an operation must refer to a message definition by name. The following example defines a portType named MathInterface that consists of four math operations: Add, Subtract, Multiply, and Divide.
<definitions 
  xmlns="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:y="http://example.org/math/" 
  xmlns:ns="http://example.org/math/types/" 
  targetNamespace="http://example.org/math/"
>
   ...
   <portType name="MathInterface">
      <operation name="Add">
         <input message="y:AddMessage"/>
         <output message="y:AddResponseMessage"/>
      </operation>
      <operation name="Subtract">
         <input message="y:SubtractMessage"/>
         <output message="y:SubtractResponseMessage"/>
      </operation>
      <operation name="Multiply">
         <input message="y:MultiplyMessage"/>
         <output message="y:MultiplyResponseMessage"/>
      </operation>
      <operation name="Divide">
         <input message="y:DivideMessage"/>
         <output message="y:DivideResponseMessage"/>
      </operation>
   </portType>   
    ...
</definitions>
A portType is still considered an abstract definition because you don't know how its messages are represented on the wire until you apply a binding.

Blog Archive