Friday

Analyze WSDL to understand a service

you've probably got some good ideas about exactly what the WSDL describes. But keep in mind that in many cases, you won't have the source code for a service you want to use. All you'll have is the WSDL to get by with. At those times, your understanding of WSDL is critical to using an RPC service (or any other type of Web service) correctly and effectively.

WSDL is namespace-heavy

Most of the time, programmers and even document authors quickly scan through — or outright skip over — the root element declaration in a WSDL file. In WSDL, though, that declaration contains a lot of information, as shown in Listing 1:

Listing 1. Root element declaration

   1: <wsdl:definitions targetNamespace="http://localhost:8080/axis/BookSearcher.jws" 


   2:    xmlns:apachesoap="http://xml.apache.org/xml-soap" 


   3:   xmlns:impl="http://localhost:8080/axis/BookSearcher.jws" 


   4:   xmlns:intf="http://localhost:8080/axis/BookSearcher.jws" 


   5:   xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 


   6:   xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 


   7:   xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 


   8:   xmlns:xsd="http://www.w3.org/2001/XMLSchema">




Each of the xmlns: attributes defines a namespace and associated prefix. So there's an Apache SOAP namespace, a SOAP encoding namespace, both a WSDL and WSDL SOAP namespace, the XML Schema namespace ... and the list goes on. The target namespace is also set, and its Uniform Resource Identifier (URI) is the JWS file representing your published service.



The good news is that although these namespaces are important to SOAP, RPC, Axis, XML parsers, and almost every other technology used in Web services, you needn't worry much about them. It's enough to know that most of the elements in the WSDL are defined by a WSDL specification and associated with the wsdl prefix, and that the XML Schema namespace (and its associated types, which will become important soon) is associated with the xsd prefix. The rest is useful, but not something you'll need to write effective Web service clients.







WSDL defines object-based types



The next key section of the WSDL is contained within the <wsdl:types> element, shown in Listing 2:



Listing 2. The <wsdl:types> element





   1: <wsdl:types>


   2: space="http://xml.apache.org/xml-soap" 


   3: p://www.w3.org/2001/XMLSchema">


   4: ="http://localhost:8080/axis/BookSearcher.jws"/>


   5: ="http://schemas.xmlsoap.org/soap/encoding/"/>


   6: ="mapItem">


   7:     <sequence>


   8: key" nillable="true" type="xsd:anyType"/>


   9: value" nillable="true" type="xsd:anyType"/>


  10:     </sequence>


  11:    </complexType>


  12: ="Map">


  13:     <sequence>


  14: urs="unbounded" minOccurs="0" 


  15: item" type="apachesoap:mapItem"/>


  16:     </sequence>


  17:    </complexType>


  18: ="Vector">


  19:     <sequence>


  20: urs="unbounded" minOccurs="0" 


  21: item" type="xsd:anyType"/>


  22:     </sequence>


  23:    </complexType>


  24:   </schema>


  25: space="http://localhost:8080/axis/BookSearcher.jws" 


  26: p://www.w3.org/2001/XMLSchema">


  27: ="http://xml.apache.org/xml-soap"/>


  28: ="http://schemas.xmlsoap.org/soap/encoding/"/>


  29: ="ArrayOf_xsd_anyType">


  30:  


  31: se="soapenc:Array">


  32: ="soapenc:arrayType" wsdl:arrayType="xsd:anyType[]"/>


  33:  


  34: >


  35:    </complexType>


  36:   </schema>


  37: </wsdl:types>




WSDL and Web services know about some basic types, such as string and int and float, but aren't very smart about types more complex than what amount to Java primitives. However, the BookSearcher class has methods that take in or return both lists and maps. To handle these complex, object-based types, the WSDL must define them in terms of XML Schema types. This section of the document defines all of those types. For example, Listing 3 shows the definition of a map that RPC clients and services can understand:



Listing 3. Definition of a map RPC clients and services can understand





   1: <complexType name="mapItem">


   2:     <sequence>


   3: "key" nillable="true" type="xsd:anyType"/>


   4: "value" nillable="true" type="xsd:anyType"/>


   5:     </sequence>


   6:    </complexType>


   7: e="Map">


   8:     <sequence>


   9: curs="unbounded" minOccurs="0" 


  10: "item" type="apachesoap:mapItem"/>


  11:     </sequence>


  12: </complexType>




The Vector type is used to represent lists in the same fashion, providing upper and lower bounds for the lists. These are of limited use, because once you've written a few services and clients, you'll become familiar with the basic mappings between Java objects and custom WSDL types. Still, if you see a method that takes in a Vector, you'll know to look for the <wsdl:types> element to find out more about that type, including any constraints it might have for the values it can contain.







Every send and return is a message



The next elements are represented by <wsdl:message>. Here's where things deviate from Java terms and focus instead on network- and SOAP-specific concepts. When you send a request to a method on a service, you're sending a message. If the method you're requesting has no parameters, your message doesn't have any data within it for the method to operate on. If the method does require parameter data, you must send that data as part of the message.



The same is true when the service returns from a method: it either contains no data from the method or one piece of data. But the key is that the send and the receive are separate messages. One is a message from a client to a service, and the other is a message from a service back to a client. The two are logically related, but they're not connected in a programming or technological sense.



So each of these messages must be declared and defined. Take the getKeywords() method of BookSearcher. It takes as a parameter a string title, and it returns a list. Each of these two messages must be represented in the WSDL:



Listing 4. Messages in WSDL





   1: <wsdl:message name="getKeywordsRequest">


   2: e="title" type="xsd:string"/>


   3:    </wsdl:message>


   4:  


   5: e="getKeywordsResponse">


   6: e="getKeywordsReturn" type="impl:ArrayOf_xsd_anyType"/>


   7: </wsdl:message>




The name of each message is simply the method name, plus either Request or Response. Each has a nested <wsdl:part> element that defines a parameter name and a type (a string title for the request, and a generically named array for the response). This enables you or a code-generation tool to figure out what a request to getKeywords() looks like, as well as what to expect in return.



If no parameter is sent, or if there's no return value, then there's no <wsdl:part> child element:



Listing 5. No <wsdl:part> child element





   1: <wsdl:message name="addKeywordResponse">


   2:    </wsdl:message>




The addKeyword() method has no return value, so it is represented by an empty addKeywordResponse() element.







A service is represented by a port type



With the possible messages delineated, the WSDL can now describe the entire Web service, via the <wsdl:portType> element, shown in Listing 6:



Listing 6. The <wsdl:portType> element





   1: <wsdl:portType name="BookSearcher">


   2: n name="setBooks" parameterOrder="books">


   3:  message="impl:setBooksRequest" name="setBooksRequest"/>


   4: t message="impl:setBooksResponse" name="setBooksResponse"/>


   5: on>


   6: n name="addBook" parameterOrder="title keywords">


   7:  message="impl:addBookRequest" name="addBookRequest"/>


   8: t message="impl:addBookResponse" name="addBookResponse"/>


   9: on>


  10: n name="addKeyword" parameterOrder="title keyword">


  11:  message="impl:addKeywordRequest" name="addKeywordRequest"/>


  12: t message="impl:addKeywordResponse" name="addKeywordResponse"/>


  13: on>


  14: n name="getKeywords" parameterOrder="title">


  15:  message="impl:getKeywordsRequest" name="getKeywordsRequest"/>


  16: t message="impl:getKeywordsResponse" name="getKeywordsResponse"/>


  17: on>


  18: n name="search" parameterOrder="keyword">


  19:  message="impl:searchRequest" name="searchRequest"/>


  20: t message="impl:searchResponse" name="searchResponse"/>


  21: on>


  22: </wsdl:portType>




Each operation maps to a method, and the various input and output messages are connected to each operation. The ordering of parameters is also supplied. These completely describe an exposed method, and when laid out like this, should make perfect sense to you.



WSDL provides some lower-level SOAP-specific information



As a programmer, you have everything you need, but some encoding and SOAP-specific details still need to be handled. These are wrapped into the <wsdl:binding> element, which maps to the port type already defined. Most of <wsdl:binding> is concerned with encodings and namespaces. For example, Listing 7 shows further SOAP-specific information related to how the getKeywords() method and operation is to be handled:



Listing 7. SOAP-specific information on handling getKeywords()





   1: <wsdl:operation name="getKeywords">


   2: peration soapAction=""/>


   3:  name="getKeywordsRequest">


   4: p:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 


   5:        namespace="http://DefaultNamespace" use="encoded"/>


   6: t>


   7: t name="getKeywordsResponse">


   8: p:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 


   9:        namespace="http://localhost:8080/axis/BookSearcher.jws" 


  10:        use="encoded"/>


  11: ut>


  12: </wsdl:operation>




 



Who is the WSDL for?



WSDL serves a dual role:




  • WSDL lets Web service and code-generation tools know the semantics and SOAP specifics that are required to connect to a service.


  • WSDL lets programmers know what methods are available and the data those methods expect and provide in return.



As you may know, JAX-RPC and the Axis framework provide tools for reading WSDL and then handling the building and connectivity of code that consumes (uses) an RPC service. So the WSDL is integral for that support code, and it allows you to avoid hours of menial SOAP-encoding semantics. But the WSDL is also essential for you, particularly when you don't have the source code for the service you're connecting to. You must use the WSDL to find out what to send, and what you'll get back.



You've probably already gotten a strong sense of how WSDL could tell you what you need to know about almost any set of methods and those methods' return types. Now it's time to put this knowledge to use and connect and interact with a Web service.

1 comment:

Victor Velazquez said...

Thanks a lot for this post. This is so clear.