| home / programming / coldfusion / 1 | [previous] |
|
|
Although we haven't yet covered publishing your own web services using ColdFusion MX, it is important that we talk about how to consume them, since there are two main differences between a ColdFusion MX web service and web services created using other technologies.
The first difference is the URL to the web service's WSDL file.
Because ColdFusion MX web services are really just CFCs, they generally end
in a .cfc extension as opposed to .wsdl.
In ColdFusion MX, you don't have to manually create a WSDL file for each of
your web services (although you could) the server does it for you automatically.
Whereas a typical URL to a WSDL file looks something like http://www.example.com/myWebService.wsdl,
the equivalent URL for a ColdFusion MX-based web service looks like http://www.example.com/myWebService.cfc?wsdl.
Note that it's the CFC and not a WSDL file that's referenced in the URL. The
?wsdl URL parameter tells ColdFusion that you want
to invoke the CFC as a web service and that it should generate the appropriate
WSDL for the service. If you leave off the ?wsdl,
referencing the CFC directly, ColdFusion thinks you are trying to call the CFC
directly and will attempt to invoke the CFC Explorer to show you the CFCs self-documentation.
The second difference between consuming a regular web service and one written in ColdFusion MX has to do with the datatypes of input and output parameters. Because you are using ColdFusion MX to consume a ColdFusion MX-based web service, there is no need for datatype mapping. This means that your web service can accept and return any valid ColdFusion datatype without worrying about conversion issues. While this may seem like a benefit, you need to be careful if you plan to let clients other than ColdFusion consume your web service, as it can be quite difficult for clients to handle data mapping for some of ColdFusion's datatypes.
All of the examples we've worked with thus far have used simple datatypes as both input and output parameters. For the most part, ColdFusion MX provides a one-to-one mapping of simple datatypes. ColdFusion strings map to strings in WSDL, Boolean to Boolean, etc. Complex datatypes are, well, a little more complex. By complex datatypes, I mean types such as arrays, structures, binary data, etc. In fact, the web services framework is designed in such a way that you can pass almost any kind of data structure, even ones you arbitrarily define.
Using ColdFusion, it's possible to pass complex datatypes as input parameters and receive complex datatypes as output parameters. Before we get into the specifics of how this is done, it's important you understand how ColdFusion automatically attempts to convert certain ColdFusion datatypes to WSDL datatypes and vice-versa when consuming web services. Table 24-1 shows the mapping between WSDL and ColdFusion datatypes.
| WSDL datatype |
ColdFusion datatype |
|---|---|
| SOAP-ENC:string |
String |
| SOAP-ENC:double |
Numeric |
| SOAP-ENC:boolean |
Boolean |
| SOAP-ENC:Array |
Array |
| xsd:base64Binary |
Binary |
| xsd:dateTime |
Date/time |
| Complex type |
Pseudo structure[3] |
Let's start by looking at another real-world example of a web
service that returns a complex datatype when called. In this case, the web service
is called the XMethods Query Service. It's a web service that allows you to
directly query the XMethods directory. It has several methods that allow you
to perform various operations. For the purposes of our example, we want to call
the getServiceSummariesByPublisher( ) method. This
method takes a single argument, publisherID of
type string, and uses the argument to return a
complex datatype containing a summary of each published web service by the specified
publisher. The datatype in this case happens to be of type SOAP-ENC:Array,
an array for all intents and purposes. What's particularly interesting about
this array, though, is that each element in the array is actually a complex
type defined in the WSDL as ServiceSummary:
<complexType name="ServiceSummary"><sequence><element name="name" nillable="true" type="xsd:string"/><element name="id" nillable="true" type="xsd:string"/><element name="shortDescription" nillable="true" type="xsd:string"/><element name="wsdlURL" nillable="true" type="xsd:string"/><element name="publisherID" nillable="true" type="xsd:string"/></sequence></complexType>
The ServiceSummary datatype is akin
to a ColdFusion structure, but it does not directly map to a ColdFusion structure.
It can be accessed using dot notation just like a ColdFusion structure can;
however, it must be converted to a ColdFusion structure manually before it can
be manipulated by the full spectrum of structure functions available in CFML.
Example 24-2 shows the code for calling the getServiceSummariesByPublisher(
) method of the XMethods Query Service for all web services published
by xmethods.net. The results, shown in Figure 24-5,
are output to the browser using the cfdump tag.
Example 24-2: Returning a complex datatype from a web service
<cfinvokewebservice="http://www.xmethods.net/wsdl/query.wsdl"method="getServiceSummariesByPublisher"returnvariable="aServiceSummaryArray"><cfinvokeargument name="publisherID" value="xmethods.net"/></cfinvoke><cfdump var="#aServiceSummaryArray#">
|
|
As you can see, aServiceSummaryArray
is automatically converted from a SOAP array to a ColdFusion array, and each
array element is shown as an object and not a ColdFusion structure. A quick
look back at the WSDL for the complex type known as ServiceSummary
shows that the returned "structure" contains five members: name,
id, shortDescription,
wsdlURL, and publisherID.
These can be referred to using dot notation, just as you would for a ColdFusion
structure, as shown in Example 24-3.
Example 24-3: Referencing data elements in a complex type using dot notation
<cfinvokewebservice="http://www.xmethods.net/wsdl/query.wsdl"method="getServiceSummariesByPublisher"returnvariable="aServiceSummaryArray"><cfinvokeargument name="publisherID" value="xmethods.net"/></cfinvoke><table border="1"><tr><th>Is Structure?</th><th>id</th><th>name</th><th>publisherID</th><th>shortDescription</th><th>wsdlURL</th></tr><cfloop index="i" from="1" to="10"><cfoutput><tr><td>#isStruct(aServiceSummaryArray[i])#</td><td>#aServiceSummaryArray[i].id#</td><td>#aServiceSummaryArray[i].name#</td><td>#aServiceSummaryArray[i].publisherID#</td><td>#aServiceSummaryArray[i].shortDescription#</td><td>#aServiceSummaryArray[i].wsdlURL#</td></tr></cfoutput></cfloop></table>
In this example, a loop is used to iterate over the first ten
elements in the aServiceSummaryArray array. A table
row is generated for each ServiceSummary structure
in the array. The table row contains columns corresponding to each element in
the array. An additional column is used to output the results of a test (using
isStruct( )) to evaluate whether each ServiceSummary
structure is a ColdFusion structure. Figure 24-6 shows the output. As you can
see, the answer is no, ServiceSummary structures
are not the same as ColdFusion structures.
|
|
It is possible to manually convert a complex type to a ColdFusion
structure. Example 24-4 shows how we can convert the ServiceSummary
structures contained in the aServiceSummaryArray
to ColdFusion structures.
Example 24-4: Manually converting a complex type to a ColdFusion structure
<cfinvokewebservice="http://www.xmethods.net/wsdl/query.wsdl"method="getServiceSummariesByPublisher"returnvariable="aServiceSummaryArray"><cfinvokeargument name="publisherID" value="xmethods.net"/></cfinvoke><cfset myArray = arrayNew(1)><cfloop index="i" from="1" to="10"><cfscript>myStruct = StructNew( );myStruct.id = aServiceSummaryArray[i].id;myStruct.name = aServiceSummaryArray[i].name;myStruct.publisherID = aServiceSummaryArray[i].publisherID;myStruct.shortDescription = aServiceSummaryArray[i].shortDescription;myStruct.wsdlURL = aServiceSummaryArray[i].wsdlURL;MyArray[i] = myStruct;</cfscript></cfloop><cfdump var="#myArray#">
Here, we create a new array (just for demonstration purposes)
to mimic the original aServiceSummaryArray array.
Next, we loop over the first ten elements (ServiceSummary
structures) in aServiceSummaryArray. During each
iteration, we create a new structure called myStruct
and assign the ServiceSummary structure values
to new ColdFusion structure keys. The resulting ColdFusion structure is then
inserted into the new myArray array. When the loop
is finished iterating, the contents of myArray
are output to the browser using cfdump. The results
can be seen in Figure 24-7.
|
|
Now the contents of each ServiceSummary
structure are contained in ColdFusion structures.
In the previous section, we discussed how to handle complex datatypes returned by a web service. Using similar techniques, we can also pass complex datatypes as input parameters to a web service.
For example, if the web service you are trying to consume expects
an input parameter called serviceSummary that's
defined as a complex type (and just happens to look like a ColdFusion structure),
you can create a ColdFusion structure containing the key/value pairs that serviceSummary
is made up of:
<cfset serviceSummary = structNew( )><cfset serviceSummary.id = "uuid:9BEDDB80-60DE-36F7-3957-9DBC8C235B67"><cfset serviceSummary.name = "Currency Exchange Rate"><cfset serviceSummary.publisherID = "xmethods.net">
When invoking our fictitious web service, we would pass the complex type like this:
<cfinvokewebservice="http://www.example.com/myBogusService.wsdl"method="setService"returnvariable="sService"><cfinvokeargument name="serviceSummary" value="#serviceSummary#"/></cfinvoke>
You can just as easily create even more complex data structures to pass. It's usually just a matter of studying the web services WSDL file and using combinations of ColdFusion structures, arrays, and other datatypes to model the complex type expected by the web service.
| <home / programming / coldfusion / 1 | [previous] |
Created: March 27 2003
Revised: Sept. 1, 2003
URL: http://webreference.com/programming/coldfusion/1