Creating Web Services


Creating Web services that can be consumed by different platforms allows ColdFusion to communicate with a client over the Internet. The resulting Web service can expose internal information to the rest of a company's platforms or to platforms from a partner company that can communicate via the protocols we have previously discussed.

In ColdFusion MX, we create Web services using ColdFusion Components. We can deploy a prebuilt CFC as a Web service or we can create a CFC specifically for the purpose of deploying it as a Web service. Either way, in order to create and deploy Web services we need to understand the basics of CFCs and how they operate.

NOTE

For more information on ColdFusion Components, read Chapter 19, "Creating Advanced ColdFusion Components."


Components

By now we hope you have found the time to read up on and experiment with ColdFusion Components (CFCs), which take an objectlike approach to grouping related functions and encapsulating business logic. If you have any experience with CFCs, you should have no trouble following the relatively simple examples in this section. Let's first review Listing 24.6, which contains the SimpleCreditRating.cfc, so we can understand how this ordinary ColdFusion Component can become a powerful Web service.

Listing 24.6. Web Service with a Simple Data Type (SimpleCreditRating.cfc)
 <!--- DATE: 06/01/02 AUTHOR: Brendan O'Hara (bohara@etechsolutions.com) WEB SERVICE: SimpleCreditRating.cfc DESCRIPTION: ColdFusion CFC deployed as a Web Service to return a Credit Rating "string" for a passed-in Social Security number which is a string represented by the argument "SSN". ---> <cfcomponent output="false"> <!--- We define the CFC's single function that retrieves the credit  rating for a passed-in Social Security number and returns it ---> <cffunction name="getCreditRating" returnType="string" output="false"             access="remote">   <!--- The GetCreditRating function takes a single         argument SSN of type string, which is required --->   <cfargument name="SSN" type="string" required="yes">   <!--- var scope the result --->   <cfset var result = "">   <!--- This is where the logic would normally go. --->   <cfset result = randRange(500,900)>   <!--- Then the CreditRating is returned --->   <cfreturn result> </cffunction> </cfcomponent> 

The SimpleCreditRating CFC starts with a <cfcomponent> tag, which wraps the component's content. Then the <cffunction> tag with a name and return type defines a single function that retrieves the credit rating for a passed Social Security number. The optional access attribute is set to remote, which exposes this CFC to the world as a Web service. The getCreditRating function takes a single argument named SSN, which is of type string and is required. We create a credit rating by simply using the randRange() function. (In practice, there would be some real logic here.) The credit rating is then returned to the Web service client.

NOTE

The <cffunction> attribute Required is ignored when a CFC is called as a Web service. For a Web service, all arguments are required. Because ColdFusion MX doesn't support method overloading, you need to define different method names for all possible parameter combinations. These methods can call a private function within the CFC that does the processing and allows for defaults.


Now we have a simple CFC-based Web service, which we can publish and allow to be called by Web service clients across the Web. Those clients looking to find someone's credit rating need only have that person's Social Security number. Let's examine the ColdFusion MXgenerated WSDL for the Web service in Listing 24.7.

Listing 24.7. WSDL Display with Simple Data Type (SimpleCreditRating.cfc)
 <?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://c24.cfadv/"                   xmlns="http://schemas.xmlsoap.org/wsdl/"                   xmlns:apachesoap="http://xml.apache.org/xml-soap"                   xmlns:impl="http://c24.cfadv/"                   xmlns:intf="http://c24.cfadv/"                   xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"                   xmlns:tns1="http://rpc.xml.coldfusion/"                   xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"                   xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"                   xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!--WSDL created by Macromedia ColdFusion MX version 7,0,0,89494--> <wsdl:types>   <schema targetNamespace="http://rpc.xml.coldfusion/"           xmlns="http://www.w3.org/2001/XMLSchema">     <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>     <complexType name="CFCInvocationException">       <sequence/>     </complexType>   </schema> </wsdl:types> <wsdl:message name="getCreditRatingResponse">   <wsdl:part name="getCreditRatingReturn" type="xsd:string"/> </wsdl:message> <wsdl:message name="getCreditRatingRequest">   <wsdl:part name="SSN" type="xsd:string"/> </wsdl:message> <wsdl:message name="CFCInvocationException">   <wsdl:part name="fault" type="tns1:CFCInvocationException"/> </wsdl:message> <wsdl:portType name="SimpleCreditRating">   <wsdl:operation name="getCreditRating" parameterOrder="SSN">     <wsdl:input message="impl:getCreditRatingRequest"                 name="getCreditRatingRequest"/>     <wsdl:output message="impl:getCreditRatingResponse"                  name="getCreditRatingResponse"/>     <wsdl:fault message="impl:CFCInvocationException"                 name="CFCInvocationException"/>   </wsdl:operation> </wsdl:portType> <wsdl:binding name="SimpleCreditRating.cfcSoapBinding"               type="impl:SimpleCreditRating">   <wsdlsoap:binding style="rpc"                     transport="http://schemas.xmlsoap.org/soap/http"/>   <wsdl:operation name="getCreditRating">     <wsdlsoap:operation soapAction=""/>     <wsdl:input name="getCreditRatingRequest">       <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"                      namespace="http://c24.cfadv/" use="encoded"/>     </wsdl:input>     <wsdl:output name="getCreditRatingResponse">       <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"                      namespace="http://c24.cfadv/" use="encoded"/>     </wsdl:output>     <wsdl:fault name="CFCInvocationException">       <wsdlsoap:fault encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"                       name="CFCInvocationException"                       namespace="http://c24.cfadv/" use="encoded"/>     </wsdl:fault>   </wsdl:operation> </wsdl:binding> <wsdl:service name="SimpleCreditRatingService">   <wsdl:port binding="impl:SimpleCreditRating.cfcSoapBinding"              name="SimpleCreditRating.cfc">     <wsdlsoap:address              location="http://127.0.0.1:8501/cfadv/c24/SimpleCreditRating.cfc"/>   </wsdl:port> </wsdl:service> </wsdl:definitions> 

Now when we look at this WSDL document, it should quickly be apparent what is important. On the line with the first <wsdl:operation> tag, we see the operation getCreditRating, which is the method clients will wish to invoke. On the next line we see that the input message is getCreditRatingRequest, which is displayed on the first line with a <wsdl:message> tag. It has a single <wsdl:part> tag named SSN, which is of data type xsd:string. The message getCreditRatingResponse describes the return variable and its data type. Figure 24.6 shows the CFC.

Figure 24.6. CFC Explorer SimpleCreditRating.cfc Web service.


Our relatively simple CFC is now a powerful Web service that can be used by businesses around the world to access credit ratings for potential customers before deciding to extend credit to them. Listing 24.8 shows an example of ColdFusion consuming the SimpleCreditRating Web service; this action will also be reviewed later in this chapter.

Listing 24.8. Invocation Example with Simple Data Type (TestSimpleCreditRating.cfm)
 <!--- DATE: 06/01/02 AUTHOR: Brendan O'Hara (bohara@etechsolutions.com) WEB SERVICE: TestSimpleCreditRating.cfm DESCRIPTION: Test the CFC. ---> <!--- Construct the URL dynamically ---> <cfif not findNoCase("https", cgi.server_protocol)>   <cfset theURL = "http://"> <cfelse>   <cfset theURL = "https://"> </cfif> <!--- Add the server and current path ---> <cfset theURL = theURL & cgi.server_name & ":" & cgi.server_port &        cgi.script_name> <!--- Now remove this file's name, which is at the end ---> <cfset theURL = listDeleteAt(theURL, listLen(theURL,"/"), "/")> <cfinvoke webservice="#theURL#/SimpleCreditRating.cfc?wsdl"           method="getCreditRating" returnvariable="creditRating">   <cfinvokeargument name="SSN" value="000000001"/> </cfinvoke> <cfoutput>The result is: #creditRating#</cfoutput> 

Most of this script simply creates the theURL variable. This allows the script to run on any Web server and any directory. The script assumes that it lies in the same directory as the Web service. Once the URL is figured out, the script simply uses the <cfinvoke> tag to call it.

Now let's take a look at a similar CFC that takes a struct data type. While a struct is similar to a number of data types in C++ and Java, it does not exactly match any of those defined in the XML Schema used by WSDL and SOAP for data-type representation and conversion. Listing 24.9 shows the Credit Rating Web Service, which for its only argument takes a map or ColdFusion structure as the data type for its only argument.

Listing 24.9. Web Service with struct or map Data Type (MapCreditRating.cfc)
 <!--- DATE: 06/01/02 AUTHOR: Brendan O'Hara (bohara@etechsolutions.com) WEB SERVICE: MapCreditRating.cfc DESCRIPTION: ColdFusion CFC deployed as a Web Service to return a Credit Rating string for a passed-in "Person" struct. ARGUMENTS: name="Person" type="struct" required="yes" ---> <cfcomponent output="false"> <!--- We define the CFC's single function that retrieves the credit  rating for a passed-in "Person" and returns it --->  <cffunction name="getCreditRating" output="false" returnType="string"              access="remote">   <!--- The getCreditRating function takes a single argument         called "Person" of type struct, which is required --->   <cfargument name="Person" type="struct" required="yes">   <!--- var scope the result --->   <cfset var result = "">   <!--- This would be real logic here --->   <cfset result = len(arguments.person.ssn) * randRange(50,100)>   <!--- Then the CreditRating is returned --->   <cfreturn result> </cffunction> </cfcomponent> 

Other than the data type change, the only thing new here is the fake logic used to return the credit rating. The problem we face is this: When clients other than ColdFusion call this Web service, they will need additional information to convert the arguments to a data type that CFMX expects and understands. Let's look at a portion of the generated WSDL for the mapCreditRating Web service to see what we are talking about. It is displayed in Listing 24.10.

Listing 24.10. WSDL Portion with struct or map Data Type (MapCreditRating.cfc)
 <wsdl:types>   <schema targetNamespace="http://xml.apache.org/xml-soap"           xmlns="http://www.w3.org/2001/XMLSchema">     <import namespace="http://c24.cfadv/"/>     <import namespace="http://rpc.xml.coldfusion/"/>     <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>     <complexType name="mapItem">            <sequence>              <element name="key" nillable="true" type="xsd:anyType"/>              <element name="value" nillable="true" type="xsd:anyType"/>            </sequence>     </complexType>     <complexType name="Map">       <sequence>         <element maxOccurs="unbounded" minOccurs="0" name="item"                  type="apachesoap:mapItem"/>       </sequence>     </complexType>   </schema> 

This map complex type is generated by all uses of the struct data type in <cffunction> arguments. You will notice that both the key and value can be of any data type. A call to this Web service will work if it comes from a ColdFusion page, but it's not the most platform-independent way of accepting structured data. Because ColdFusion doesn't predefine data types for all variables, we need to be aware of data types that may be problematic. The struct or map data type common to ColdFusion is not exactly represented in the XML Schema that SOAP uses for automatic data-type translation. Another unsupported data type is query. That is why we need to limit the use of unsupported data types in Web services when interacting with other platforms.

Defining Complex Data Types

Web services may be significantly more complex than our "simple" example, and their input parameters may be custom or unsupported data types. A Web service may need to accept multiple fields, or a single field containing a complex data type, in order to process the called function and return data to the caller. Object-oriented languages such as Java, C++, and C# have direct mappings from their complex data types to the XML Schema data types used by SOAP and WSDL. Unfortunately, ColdFusion doesn't have direct mappings to many of these complex data types. What it does have is the capacity to let you define your own complex data types using CFCs and the <cfproperty> tag.

Listing 24.11 shows a CFC completely empty of content except for <cfproperty> tags.

Listing 24.11. Complex Data Type for Use with a Web Service (CreditPerson.cfc)
 <!--- DATE: 06/01/02 AUTHOR: Brendan O'Hara (bohara@etechsolutions.com) COMPONENT: CreditPerson.cfc DESCRIPTION: ColdFusion CFC deployed as a complex data type for use with Web Services. No functions. No arguments. ---> <cfcomponent>   <cfproperty name="FirstName" type="string">   <cfproperty name="Lastname" type="string">   <cfproperty name="Address" type="string">   <cfproperty name="City" type="string">   <cfproperty name="State" type="string">   <cfproperty name="ZipCode" type="string">   <cfproperty name="SSN" type="string"> </cfcomponent> 

The <cfproperty> tag is used in order for Web services to define a complex data type. In ColdFusion this would be a structure, but because a struct is not a supported data type, we use another CFC without arguments to define the structure of our complex data type. The Credit Rating CFC Web Service using a complex data type is shown in Listing 24.12.

Listing 24.12. Web Service with Complex Data Type (ComplexCreditRating.cfc)
 <!--- DATE: 06/01/02 AUTHOR: Brendan O'Hara (bohara@etechsolutions.com) WEB SERVICE: ComplexCreditRating.cfc DESCRIPTION: ColdFusion CFC deployed as a Web Service to return a Credit Rating "string" for a passed-in "Person", which is a Complex Data Type which is defined in the CFC Person.cfc. ARGUMENTS: name="SSN" type="string" required="yes" ---> <cfcomponent output="false"> <!--- We define the CFC's single function that retrieves the credit  rating for a passed-in "Person" and returns it ---> <cffunction name="GetCreditRating" returnType="string" output="false"             access="remote">   <!--- The GetCreditRating function takes a single argument         called "Person" of type struct, which is required --->   <cfargument name="person" type="CreditPerson" required="yes">   <!--- var scope the result --->   <cfset var result = "">   <!--- This would be real logic here --->   <cfset result = len(arguments.person.ssn) * randRange(50,100)>   <!--- Then the CreditRating is returned --->   <cfreturn result> </cffunction> </cfcomponent> 

When the type attribute in the <cfargument> tag is not a recognized type, the attribute is assumed to be the name of a ColdFusion Component. The CFC is converted to a complex data type when represented in WSDL. This will take extra work to extract and convert the data on the client side, so the attribute should be used only when it is clearly advantageous.

Take a look at the generated WSDL, and notice that the complex type is represented differently than our struct and map exampleseven though the processing in the CFC Web service is virtually identical. Listing 24.13 shows the WSDL for our ComplexCreditRating Web service.

Listing 24.13. WSDL Display with Complex Data Type (ComplexCreditRating.cfc)
 <?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://c24.cfadv/"                   xmlns="http://schemas.xmlsoap.org/wsdl/"                   xmlns:apachesoap="http://xml.apache.org/xml-soap"                   xmlns:impl="http://c24.cfadv/"                   xmlns:intf="http://c24.cfadv/"                   xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"                   xmlns:tns1="http://rpc.xml.coldfusion/"                   xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"                   xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"                   xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!--WSDL created by Macromedia ColdFusion MX version 7,0,0,89494--> <wsdl:types>   <schema targetNamespace="http://c24.cfadv/"           xmlns="http://www.w3.org/2001/XMLSchema">     <import namespace="http://rpc.xml.coldfusion/"/>     <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>     <complexType name="creditperson">       <sequence>         <element name="SSN" nillable="true" type="xsd:string"/>        <element name="address" nillable="true" type="xsd:string"/>        <element name="city" nillable="true" type="xsd:string"/>        <element name="firstName" nillable="true" type="xsd:string"/>        <element name="lastname" nillable="true" type="xsd:string"/>        <element name="state" nillable="true" type="xsd:string"/>        <element name="zipCode" nillable="true" type="xsd:string"/>       </sequence>     </complexType>   </schema>   <schema targetNamespace="http://rpc.xml.coldfusion/"           xmlns="http://www.w3.org/2001/XMLSchema">     <import namespace="http://c24.cfadv/"/>     <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>     <complexType name="CFCInvocationException">       <sequence/>     </complexType>     </schema> </wsdl:types> <wsdl:message name="GetCreditRatingRequest">   <wsdl:part name="person" type="impl:creditperson"/> </wsdl:message> <wsdl:message name="GetCreditRatingResponse">   <wsdl:part name="GetCreditRatingReturn" type="xsd:string"/> </wsdl:message> <wsdl:message name="CFCInvocationException">   <wsdl:part name="fault" type="tns1:CFCInvocationException"/> </wsdl:message> <wsdl:portType name="ComplexCreditRating">   <wsdl:operation name="GetCreditRating" parameterOrder="person">     <wsdl:input message="impl:GetCreditRatingRequest"                 name="GetCreditRatingRequest"/>     <wsdl:output message="impl:GetCreditRatingResponse"                  name="GetCreditRatingResponse"/>     <wsdl:fault message="impl:CFCInvocationException"                 name="CFCInvocationException"/>   </wsdl:operation> </wsdl:portType> <wsdl:binding name="ComplexCreditRating.cfcSoapBinding"               type="impl:ComplexCreditRating">   <wsdlsoap:binding style="rpc"                     transport="http://schemas.xmlsoap.org/soap/http"/>   <wsdl:operation name="GetCreditRating">     <wsdlsoap:operation soapAction=""/>     <wsdl:input name="GetCreditRatingRequest">       <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"                      namespace="http://c24.cfadv/" use="encoded"/>     </wsdl:input>     <wsdl:output name="GetCreditRatingResponse">       <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"                      namespace="http://c24.cfadv/" use="encoded"/>     </wsdl:output>     <wsdl:fault name="CFCInvocationException">       <wsdlsoap:fault encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"                       name="CFCInvocationException"                       namespace="http://c24.cfadv/" use="encoded"/>     </wsdl:fault>   </wsdl:operation> </wsdl:binding> <wsdl:service name="ComplexCreditRatingService">   <wsdl:port binding="impl:ComplexCreditRating.cfcSoapBinding"              name="ComplexCreditRating.cfc">     <wsdlsoap:address location=                     "http://127.0.0.1:8501/cfadv/c24/ComplexCreditRating.cfc"/>   </wsdl:port> </wsdl:service> </wsdl:definitions> 

This example provides significantly more information than does the WSDL generated for our ColdFusion struct or map example. The map had undefined key values and an undefined number of elements in the map, so someone trying to call our Web service from only the WSDL would have no clue what parameters were required and what their true data types should be. Our custom complex data type, however, defines the elements in the structure and their associated types. In this case they are all strings, but they could just as easily have all been different. This Web service can work when called by a ColdFusion page, and with minimal adjustments and testing can be accessed by most other platforms. Figure 24.7 shows the CFC Explorer for the ComplexCreditRating Web service.

Figure 24.7. CFC Explorer for ComplexCreditRating.cfc Web service.


The CreditPerson data type is a link that takes you to the CFC Explorer for the CreditPerson complex data type. Figure 24.8 shows this display.

Figure 24.8. CFC Explorer for CreditPerson.cfc complex data type.




Advanced Macromedia ColdFusion MX 7 Application Development
Advanced Macromedia ColdFusion MX 7 Application Development
ISBN: 0321292693
EAN: 2147483647
Year: 2006
Pages: 240
Authors: Ben Forta, et al

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net