Welcome!

SOA & WOA Authors: Yeshim Deniz, Salvatore Genovese, Mark O'Neill, Irfan Khan, Vikas Aggarwal

Related Topics: SOA & WOA

SOA & WOA: Article

Discover Web Services for Yourself

Discover Web Services for Yourself

The Web services phenomenon has finally arrived. All of the developer conferences and symposiums are talking about how Web services will revolutionize the world. Well, it takes action to start a riot, and this article should set your wheels in motion. In this article, you'll learn how to locate available Web services, and systematically integrate discovered services into your existing application by using XPath to parse the services, WSDL file.

First, we need a service to work with. For our example we'll focus on the RPC-style Web services as these are the most common and easiest of the Web service solutions to implement. Since UDDI is still a relatively distant option for discovering services, we will turn to our good friends over at Xmethods.net, who have an extensive listing of available Web services. Let's select the Global Ski Resort Finder (GSRF) service (a nifty little tool that locates ski resorts within a certain radius of a given longitude/latitude point) and take a brief look at the WSDL file, located at www.transactionalweb.com/SOAP/ globalskilocator.wsdl.

WSDL Architecture
The WSDL file, which is simply an XML file that describes the Web service, contains the following general format (for brevity, we will discuss the main contents of a WSDL file and try to apply them to our example file).

<description> element has at least one each of the following children elements: <type/>, <message/>, <portType/>, <service Type/>, <binding/>, <service/>, </description>.

The <description> element is the root element. This is where you see the namespaces for the collective properties of the WSDL file. The <type> element contains the definitions of the datatypes used for the services operations. In the GSRF file, notice that the <type> element contains a definition for the "Entry" datatype, which in this case is of type array. (We won't discuss this custom type in this article.) Next is the <message> element that defines the structure of the messages sent between the client and the host. We have two <message> elements of names "findWithin RadiusResponse" and "ski". Notice that each <message> element contains a <part> element. The <part> element defines the encoding type for that particular message (either a response message or a call message). After that, we have the <portType> element that defines the parameters for all operations available. The <portType> attribute "name" is used as an internal reference, which we will tie together a little later. Next comes the <binding> element, which is used to provide the operation details.

In our example, we see an <operation> element inside the <binding> element, which defines the input and output parameters for the service named "findWithinRadius". Finally, we have our <service> element, which contains the names of the services available. The GSRF has one <operation> tag with a name attribute whose value is "findWithinRadius". The <operation> tag will have any of the following children elements: <input>, <output>, and/or <fault>. The children tags inform us of the existence of input, output, and fault parameters.

XPath and Scripting
XPath has been a W3C recommendation since November 1999. XPath is designed to provide a common interface to searching XML documents for XSLT and Xpointer, but it can also be incorporated into scripting languages such as JSP, PHP, and ColdFusion. By implementing XPath syntax and expressions in a scripting language, you can search the WSDL file and dynamically map all the properties of a Web service. Most scripting languages that have integrated XPath support will allow XML path searches. Specifically, it's possible to locate nodes and discover XML attributes of those nodes. Within the XPath recommendation, there are additional node tests available that can be used to discover further attributes of the returned XML nodes. We will assume here that the scripting language makes these attributes available with a standard API. In our example, we would take the following steps to discover the Web service properties:

1.   Make sure that we are working with an RPC-style service, using this bit of code:

//*[contains(name(),'binding')][@style=]

Select any nodes named 'binding' that have an attribute named 'style' with the value 'encoded'

2.   Next, we want to discover the name of the service:

//*[contains(name(), 'service')]

Select the <service> node. (This will return the name of the Web service.)

3.   Now, let's discover what ports (methods) are available for this service:

//*[contains(name(), 'binding')]/[@name]

Select all of the children of the <binding> node that have children with an attribute name.

4.   From step 3, we now know that the context node (our first node returned from the search) will have an attribute 'name' and the value of this attribute will be the method. (It is possible to have multiple methods returned from this initial query, which means each sibling node, at the same level as the context node, would also have an attribute 'name' and the value of it would be its method name.)

5.   Next, in order to discover the input, output, and/or fault codes available for each port (method), we make the following call on our WSDL file:

//*[contains(name(), 'binding')]/*[contains(name(),
'operation')][@name='$port']

Select all of the nodes that exist in the <binding> node that have the name 'operation' and contain the attribute 'name' whose value is $port' (note: the use of the $ here denotes that we are working with a variable of some sort). Basically you would want to do this for each <operation> node returned from step 2.

6.   From step 4, we can search for the existence of either an <input> and/or <output> and/or <fault> node, which indicates what is in use for this service. Commonly, a service will have an <input> and <output>, but it's entirely possible for a service to have just an <input> or just an <output>.

<breath> What we have done so far is significant enough for reflection. Basically, we have just discovered the Method names for all of the services available and for each Method, whether or not it has input, output, and/or fault messages. This is only the beginning, but it is a solid foundation with which to work.

<breath/>

7.   The portType will help us discover the mapping for the datatypes of the messages related to the service. For each found node in step 5, execute the following to discover the mapping for the node's datatype:

//*[contains(name(), 'portType')][*[contains(name(),
'operation')][@name='$port']]/*/*

Select all nodes whose names contain 'portType' with children nodes whose names contain 'operation' and have an attributed called 'name' with value $port. (Note: XML is a case-sensitive language so "findwithinradius" is NOT the same as "findWithinRadius".)

8.   What we need from step 7 is the value of the message 'attribute' for each of the available messages (input/output and/or fault). The value for each will help us find in the WSDL document the datatype expected from the client for that message. (Note: each message will be prefaced with the namespace for its encoding style. Commonly, this will appear as tns:mapping. In our case, we are merely interested in the 'mapping', not the 'tns:'.)

9.   For each value returned by step 7, we can perform the following search to determine the location of the datatype:

//*[contains(name(), 'message'][@name=$mapping]
Select all nodes whose names contain 'message'
with an attribute 'name' whose value is $mapping
(again, we use the $ to denote dynamic variable here)

10.   The data from step 8 will contain a <part> element(s) that define the name of the expected part, but more importantly, we now have the datatype. Here is where things get a little tricky. The datatype can either be a standard datatype like String or Boolean, in which case we are done with the discovery process. However, if this datatype is a custom or complex datatype (denoted by a prefix other than "tns:"), a little more discovery is required. The complex data type is just that - complex. For now, we will leave that for another article.

What Should We See?
From our example (The Global Ski Resort Finder), you should have discovered the following properties:
1.   A service named "QueryInterfaceService".
2.   A port (method) named "findWithin Radius" with an input and output parameter.
3.   The input message for the "findWithin Radius" port was mapped to the "intf:ski" message type.
4.   The output message for the "findWithin Radius" port was mapped to the "intf:find WithinRadiusResponse" message type.
5.   The "ski" message contained three parts
a. Latitude (of type string)
b. Longitude (of type string)
c. Radius (of type string)

6.   The "findWithinRadiusResponse" message contained one part: Noname (of type ArrayOfEntry - the locally defined complex type).

You now have all of the information you need to dynamically call this service and systematically incorporate it into your application.

The Revolution Begins
We all know that Web services are here, and that Web services create a new paradigm for the distributed application model. Once the security model is put in place (hopefully by the WS-I), we can use examples like these to at least understand what is needed to architect dynamic discovery and use of the ever-growing population of publicly available services. Happy Web servicing!

More Stories By Ron West

Ron West is a Senior Applications Developer with PaperThin, Inc., a privately held Web content management vendor headquartered in Quincy, Massachusetts. Ron has been working with Web applications for seven years. He is one of the directors of the Rhode Island ColdFusion User Group, and is an established writer for several industry publications.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.