Working with Based Web ServicesSOAP-IN THIS CHAPTERUnderstanding SOAP Understanding WSDL Using the WebService component Handling WebService component events Calling Web service operation
Trang 1If you want to identify namespaces by their URI, use the ActionScript’s namespace keyword to create a namespace object by the URI:
private namespace train = “http://www.bardotech.com/train”;
private namespace plane = «http://www.bardotech.com/airplane»;
private namespace car = “http://www.bardotech.com/automobile”;
Alternatively, if you want to identify namespaces by their prefixes as assigned in the XML ture, create variables typed as the Namespace class Assign each namespace by calling the XMLobject’s namespace() method and passing the selected namespace prefix:
struc-private var train:Namespace = xTravel.namespace(“train”);
private var plane:Namespace = xTravel.namespace(“plane”);
private var car:Namespace = xTravel.namespace(“car”);
con-After the namespace objects have been declared, you can use them as element and attribute fixes in E4X expressions The namespace object’s name is separated from the element or attribute name with the :: operator to qualify the node as being a member of the selected namespace
pre-The following code extracts the <traveltime> element that’s qualified with the planenamespace:
Trang 2font-weight:bold;
} </fx:Style>
private var travelTime:String=”Choose a vehicle”;
private var xTravel:XML = <travel
private namespace train = “http://www.bardotech.com/train”;
private namespace plane = “http://www.bardotech.com/airplane”;
private namespace car = “http://www.bardotech.com/automobile”;
private function getTravelTime():void {
var vehicle:String = vehicleGroup.selectedValue as String;
switch (vehicle) {
Trang 4In this chapter, I described how to use E4X to parse and modify data stored in XML objects in Flex application memory at runtime You learned the following:
l E4X stands for EcmaScript for XML
l E4X is a standard of Ecma International that is implemented in ActionScript 3 and in certain other languages and platforms
l E4X enables you to parse, extract, and modify XML-based data at runtime with simple, concise expressions
l E4X is a part of the compiled ActionScript language and is not designed for runtime evaluation of arbitrary expressions
l Array-style syntax is combined with various operators to “walk” the XML hierarchy
l The delete operator removes elements and attributes at runtime
l XML with namespaces can be accurately parsed using namespace objects and the namespace qualification operator (::)
Trang 5Part IV
Integrating Flex Applications with Application Servers
IN THIS PARTChapter 25
Working with SOAP-Based Web Services
Trang 7Working with Based Web Services
SOAP-IN THIS CHAPTERUnderstanding SOAP
Understanding WSDL Using the WebService
component Handling WebService
component events Calling Web service operations and displaying data with Flash Builder data connections
In Chapter 23, I described the use of the Flex HTTPService
compo-nent to make requests and handle responses from Web resources matted as arbitrary XML data structures The strength of REST (Representational State Transfer) and generic XML is that you can create and use Web services that employ any arbitrary data structure The potential weakness of this strategy is that each application must have specific knowl-edge of the particular XML structure being used
for-SOAP-based Web services take a different approach: They employ standard XML languages to format both messages and metadata The SOAP language itself is used to format requests and responses between a client and
industry-a server, while WSDL (Web Services Description Lindustry-anguindustry-age) is used to declare to Web service consumers the structure and capabilities of Web ser-vice operations
Note
The term SOAP started as an acronym for Simple Object Access Protocol
Starting with version 1.2, it became simply SOAP n
The strength of SOAP-based Web services lies in their industry-level dardization and their capability to accept strongly typed parameters and return values in a way that RESTful operations typically can’t Their weak-ness lies in the verbose nature of the messages that are exchanged between the client and the server Because SOAP-based Web services send and receive data in XML, the message packets are significantly larger than the same data encoded in AMF (Action Message Format; the binary format used by the RemoteObject class)
Trang 8stan-SOAP servers and clients are designed to be interoperable, so that you can easily call functions
(known in SOAP as operations) from objects on remote servers without knowing what platform is
hosting the service or what programming language was used to develop it, because many support SOAP And, as data is passed between client and server, its data types are maintained as long as both tiers of the application use compatible types
Understanding SOAP
SOAP is an XML language that’s used to format messages sent between clients and servers in RPC (Remote Procedure Call)–style applications Its purpose is to allow client applications to call func-tions of remote objects that are defined and hosted in a server-based environment
When a remote operation is called from a SOAP client application, the request message is encoded
in the SOAP language as an XML package with a root element named <Envelope> The following SOAP packet was generated by a Flex application calling a remote operation named helloWorld:
<SOAP-ENV:Envelope xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>
<SOAP-ENV:Body SOAP-ENV:encodingStyle=
Trang 9<?xml version=”1.0” encoding=”utf-8”?>
<soapenv:Envelope xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/”
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>
<soapenv:Body>
<ns1:helloWorldResponse soapenv:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”
xmlns:ns1=”http://flex4bible”>
<helloWorldReturn xsi:type=”xsd:string”>Hello World</helloWorldReturn>
of namespace prefixes (Flex uses SOAP-ENV, while ColdFusion uses soap-env), but they agree
on the important elements of Web-based communications
The magic of SOAP, however, is that you don’t need to know these details SOAP-based client and server software is responsible for creating an abstraction layer that enables the developer to make calls
to remote operations using code that’s only minimally different from that used to call local methods
A SOAP-based Web service can be built with many different programming languages and hosted
on many operating systems To host a service, you need an application server that knows how to read and write SOAP message packets Similarly, the client application uses an implementation of SOAP that handles the serialization and deserialization of the SOAP message packets as data is sent and received
Some SOAP-based software packages implement both server and client functionality For example, Apache’s Axis (http://ws.apache.org/axis/) is a popular Java-based implementation of SOAP that implements client and server functionality and can be used freely with any Java-based application Other implementations, such as the Flex SDK’s WebService component, include only a SOAP client
This chapter describes how to use the WebService component to make calls to SOAP-based Web services While the examples in this chapter are written against a Web service built and hosted in Adobe ColdFusion, Flex applications are interoperable with many SOAP server implementations
For example:
l Microsoft ASP.NET implements SOAP as a feature named XML Web Services
l Apache Axis includes implementations of SOAP for client-side and server-side Java-based applications on most operating systems
l Adobe ColdFusion (used in this chapter) implements SOAP as an option for calling ColdFusion Component (CFC) functions and uses the <cfinvoke> command to call
Trang 10functions from most SOAP servers The most recent versions, ColdFusion 8 and 9, run on Windows, Mac OS X, Linux, Solaris, and AIX.
l Many open-source and built-in implementations of SOAP also are available for various scripting languages, including PHP, Python, and Ruby
Note
Whenever possible, most developers prefer to use the RemoteObject component to integrate Flex tions with ColdFusion, Java-based applications like LiveCycle Data Services and BlazeDS, and other non-Adobe products, such as OpenAMF, AMFPHP, and WebOrb, that support the Remoting Service architecture and binary AMF This is primarily due to the performance advantage you get with AMF.
applica-SOAP, while supporting strongly defined data types, is formatted as XML and generates much larger data ets than AMF-enabled architectures Web service integration tends to be used for integration with third-party data vendors who support the SOAP standard or with application servers with particularly strong SOAP sup- port, such as ASP.NET n
pack-Understanding WSDL
Web Services Description Language (WSDL) is an XML language that’s used to declare to Web vice consumers the structure and capabilities of Web service operations In order to consume a Web service, a Flex application must be able to read and parse a WSDL file at runtime that tells the WebService component everything it needs to know in order to successfully call the service’s operations
ser-WSDL is a somewhat complex language, but many SOAP server implementations, including Apache Axis, ASP.NET’s XML Web Services, and ColdFusion, can dynamically generate a WSDL file for a native class exposed as a Web service in response to an HTTP request from a client appli-cation For all these application servers, you generate a WSDL file by sending an HTTP request from a client application to the service URL and appending a query string variable named wsdl
Take as an example a ColdFusion Component (CFC) named SoapService.cfc that’s designed
to be called as a Web service If the CFC is stored in a subfolder of the Web root named services, and ColdFusion is installed on your local server and connected to a Web server running on the default port 80, the CFC’s URL would be:
http://localhost/services/SoapService.cfc
To generate the WSDL file, append a query string parameter named wsdl:
http://localhost/services/SoapService.cfc?wsdlColdFusion responds by generating the WSDL content and returning it to the requesting applica-tion Similar patterns are used by other common SOAP server applications This is an example of a WSDL URI for Apache Axis:
http://localhost/myJEEApp/services/MyWebService?wsdl
Trang 11And this is an example for ASP.NET:
http://localhost/myDotNetApp/MyWebService.asmx?wsdlNote
The address of the WSDL document on the Web is referred to in Flash Builder and the Flex documentation as the WSDL URI (Uniform Resource Identifier) n
Trang 12namespace=»http://flex4bible» use=»encoded»/>
</wsdl:input>
<wsdl:output name=»helloWorldResponse»>
<wsdlsoap:body encodingStyle=»http://schemas.xmlsoap.org/soap/encoding/»
namespace=»http://flex4bible» use=»encoded»/>
</wsdl:output>
<wsdl:fault name=»CFCInvocationException»>
<wsdlsoap:fault encodingStyle=»http://schemas.xmlsoap.org/soap/encoding/»
Web Resource
You can find many tutorials on WSDL on the Web For one that’s concise, check out http://msdn2
microsoft.com/en-us/library/ms996486.aspx n
Trang 13Using the WebService Component
In this section, I describe how to use the WebService component to make calls to Web service functions and handle the resulting data The sample applications call Web services written in CFML and hosted on ColdFusion 8, so if you want to run the sample applications on your own system, you’ll first need to download and install ColdFusion 8 from Adobe Systems
success-After installing ColdFusion, follow these steps to set up the sample Web service included with the Flex project:
1 Create a folder under the ColdFusion server’s Web root named flex4bible The
default Web root folder in this environment is C:\ColdFusion9\wwwroot on Windows and /Applications/ColdFusion9/wwwroot on Mac OS X
2 Locate the files and directories in the ColdFusionFiles folder within the chapter25
project.
3 Copy and paste the files into the new flex4bible folder under the ColdFusion
Web root.
You should have these files and directories:
l Application.cfc A file that controls the ColdFusion application’s configuration
l data A folder containing an XML file that represents the data used in the Web service
l SoapService.cfc The Web service file
l TestPage.cfm A ColdFusion page you can call from a browser to make sure the code works before using it as a Web service
Trang 14com-Creating a WebService object
As with the HTTPService component that was described in Chapter 23, the WebServicecomponent can be instantiated with either MXML or ActionScript code The component’s wsdlproperty is a String value that contains the URL from which the service’s WSDL can be retrieved at runtime
To create a WebService object in MXML, declare it with a unique id and set its wsdl property
As with the HTTPService component, if a Web-based Flex application and a Web service it calls are hosted
in the same domain, you can use a relative URL in the wsdl property In this example, you could shorten the
Alternatively, you can pass the wsdl location into the WebService constructor method:
var myService:WebService = new WebService(
“http://localhost:8500/flex4bible/SoapService.cfc?wsdl”);
Loading the WSDL content
When you use MXML to declare a WebService object, it requests and downloads the WSDL tent from the wsdl location upon object construction (usually as the application starts up) When using ActionScript code to declare the WebService object, you have to explicitly load the WSDL content by calling the object’s loadWSDL() method If the wsdl property is already set, you can call loadWSDL() without any arguments:
con-var myService:WebService = new WebService(
“http://localhost:8500/flex4bible/SoapService.cfc?wsdl”);
myService.loadWSDL();
Another approach is to pass the wsdl location into loadWSDL() and handle both tasks at the same time:
Trang 15var myService:WebService = new WebService();
Handling the load event
Whether you use ActionScript or MXML to declare a WebService object, it dispatches an event named load when the WSDL content has been successfully retrieved and parsed The WebServiceobject can make calls to Web service operations only after this task is complete, so it’s common to make initial calls to Web service operations upon the load event being dispatched In MXML, the code to make an initial call when the WebService component is ready looks like this:
myService.helloWorld();
}Note
The LoadEvent class implements a document property typed as XMLDocument that represents the WSDL document that was loaded from the server This is a legacy XML object that you can parse with Document Object Model (DOM)–style programming In highly dynamic applications, the document property enables you to parse and present options to users for calling Web service operations without having to hard code the operation names in your Flex application n
Tip
You also can make initial calls to Web service operations from the Application component’s life cycle events, such as initialize or creationComplete If these events are dispatched before the
WebService component has successfully read its WSDL content, your pending calls are placed in a queue
When the load event is dispatched, queued calls are sent to the Web service provider automatically n
Trang 16Handling Web service results
As with the HTTPService component, Web service requests and responses are handled chronously This means that when you send a request, Flash Player’s ActionScript Virtual Machine (AVM) doesn’t pause in its code execution and wait for data to be returned Instead, you call the Web service operation and then use either binding expressions or event listeners to handle and process the returned data
asyn-Using binding expressions
A binding expression can be used to pass data returned from a call to a Web service operation to a visual control or other component that’s capable of acting as a binding destination A binding expression for a Web service operation consists of three parts, separated with dots:
l The WebService object’s unique id or variable name
l The name of the Web service operation
l The lastResult propertyUsing the example in the previous section, where the WebService object has an id of myServiceand the Web service operation is named helloWorld(), the binding expression to pass returned data to a Flex component would be:
myService.helloWorld.lastResultCaution
The operation name is used to create a temporary instance of the Operation class that, in turn, implements the lastResult property There are a number of versions of this class, including versions for SOAP and Remoting, and within each of these categories are separate versions for use with WebService objects declared in ActionScript and in MXML n
The application in Listing 25.1 uses binding expressions to handle and display both a simple String returned from the Web service’s helloWorld() operation and an ArrayCollectionreturned from the service’s getAllContacts() operation
Trang 17<s:VerticalLayout horizontalAlign=”center” paddingTop=”20”/>
</s:layout>
<s:Button label=”Get String” click=”myService.helloWorld()”/>
<s:Label text=”{myService.helloWorld.lastResult}” fontSize=”12”/>
<s:Button label=”Get Data” click=”myService.getAllContacts()”/>
<mx:DataGrid dataProvider=”{myService.getAllContacts.lastResult}”>
<mx:columns>
<mx:DataGridColumn dataField=”firstname” headerText=”First Name”/>
<mx:DataGridColumn dataField=”lastname” headerText=”Last Name”/>
</mx:columns>
</mx:DataGrid>
</s:Application>
On the Web
The code in Listing 25.1 is available in the Web site files as WebServiceWithBindings.mxml in the src
folder of the chapter25 project n
Figure 25.1 shows the resulting application, displaying a simple string and a complex data set returned from the Web service
FIGURE 25.1
Displaying Web service results
Using the result event
As with the HTTPService component, you can handle results of a call to a Web service operation with the WebService component’s result event This event dispatches an event object typed as mx.rpc.events.ResultEvent, the same event object that’s used by HTTPService and RemoteObject The event object’s result property references the returned data
Trang 18To handle and save data using the result event, follow these steps:
1 Declare a bindable variable outside of any functions that acts as a persistent
refer-ence to the returned data Cast the variable’s type depending on what you expect to be
returned by the Web service operation For example, if the data type declared in the WSDL document is soapenc:Array or is a custom type derived from that type (such
as ColdFusion’s impl:ArrayOf_xsd_anyType), the WebService component casts the returned data as an ArrayCollection:
import mx.collections.ArrayCollection;
[Bindable]
private var myData:ArrayCollection
2 Create an event handler function that will be called when the event is dispatched
The function should receive a single event argument typed as ResultEvent and return void:
private function resultHandler(event:ResultEvent):void{
}
3 Within the event handler function, use the event.result expression to refer to
the data that’s returned from the server Unlike with the HTTPService component, where you have to walk down the XML hierarchy to get to the returned data, the expres-sion event.result returns a strongly typed ArrayCollection and can be passed directly to the persistent variable:
myData = event.result as ArrayCollection;
Note
When passing the value of event.result directly to a variable, you have to explicitly declare the type of the returned data using the ActionScript as operator ResultEvent.result is typed in the API as an Object; explicit casting tells both the compiler and Flash Builder’s code syntax checker that the data is expected to arrive already formatted as an ArrayCollection n
You can listen for the result event with either an MXML attribute-based event listener or a call to the ActionScript addEventListener() method The attribute-based event listener looks like this:
Trang 19Listing 25.2 uses a result event handler function to capture and save data that’s been returned from a Web service operation.
private var contactData:ArrayCollection;
private function resultHandler(event:ResultEvent):void {
contactData = event.result as ArrayCollection;
} ]]>
<mx:DataGridColumn dataField=”firstname” headerText=”First Name”/>
<mx:DataGridColumn dataField=”lastname” headerText=”Last Name”/>
</mx:columns>
</mx:DataGrid>
</s:Application>
On the Web
The code in Listing 25.2 is available in the Web site files as WebServiceResultEvent.mxml in the src
folder of the chapter25 project n
Trang 20Handling fault events
When a call to a Web service operation fails, the WebService object dispatches a fault event
Just like the HTTPService and RemoteObject components, the event object is typed as mx.rpc.events.FaultEvent This event object has a fault property typed as mx.rpc
Fault, which has these properties:
l faultCode:String A code that indicates the nature of the fault and whether it
occurred in the client or server environment
l faultDetail:String An additional message that sometimes contains useful information
l faultString:String The error message
l message:String A string consisting of all of the previous values concatenated together with | characters used as separators
To handle a fault event, create an event handler function that receives an event argument typed
as FaultEvent Within the body of the function, you can deal with the fault however you like
This code collects fault information from the event object and displays it to the user with an Alert pop-up window:
private function faultHandler(event:FaultEvent):void{
Alert.show(event.fault.faultString, event.fault.faultCode);
}The application in Listing 25.3 generates a fault by calling a nonexistent operation from the Web service
Trang 21import mx.rpc.events.ResultEvent;
[Bindable]
private var contactData:ArrayCollection;
private function resultHandler(event:ResultEvent):void {
contactData = event.result as ArrayCollection;
} private function faultHandler(event:FaultEvent):void {
Alert.show(event.fault.faultString, event.fault.faultCode);
} ]]>
<mx:DataGridColumn dataField=”firstname” headerText=”First Name”/>
<mx:DataGridColumn dataField=”lastname” headerText=”Last Name”/>
</mx:columns>
</mx:DataGrid>
</s:Application>
On the Web
The code in Listing 25.3 is available in the Web site files as WebServiceFaultEvent.mxml in the src
folder of the chapter25 project n
As shown in Figure 25.2, the application responds by displaying the fault information in a pop-up window produced by the Alert class
Handling events of multiple operations
When a Flex application needs to handle result and fault events from more than one operation of a single Web service, you need to distinguish which event handler method will be used for the results
of each operation call You can handle this requirement with either ActionScript or MXML code
To set up an event listener for a single method in ActionScript, call addEventListener() as a method of an Operation object either before or after making a call to the Web service operation
The following code calls a Web service’s getAllContacts() operation and then dispatches its result event to an event handler function named resultHandler():
myService.getAllContacts();
myService.getAllContacts.addEventListener(
ResultEvent.RESULT, resultHandler);
Trang 22Because addEventListener() is called as a method of the operation, not the WebServiceobject itself, the event listener is active only for that particular operation.
To set up a similar architecture with MXML, declare the WebService component as a paired
<s:WebService> tag set Within the tags, nest multiple <s:operation> tags, each ing an operation you want to call The <s:operation> tag is an instruction to the compiler rather than an instance of an ActionScript class Its purpose is to configure a single operation with its own unique event handlers
FIGURE 25.2
Responding to a fault event
The following MXML code declares an instance of the WebService component with distinct result event listeners for each of two operations Because the two operations return different types of data, it’s important that they each have their own event handler functions:
Trang 23private var helloData:String;
private function contactsResultHandler(event:ResultEvent):void {
contactData = event.result as ArrayCollection;
} private function helloResultHandler(event:ResultEvent):void {
helloData = event.result as String;
} private function faultHandler(event:FaultEvent):void {
Alert.show(event.fault.faultString, event.fault.faultCode);
} ]]>
</fx:Script>
<s:layout>
<s:VerticalLayout horizontalAlign=”center” paddingTop=”20”/>
</s:layout>
<s:Button label=”Get String” click=”myService.helloWorld()”/>
<s:Label text=”{helloData}” fontSize=”12”/>
<s:Button label=”Get Data” click=”myService.getAllContacts()”/>
<mx:DataGrid dataProvider=”{contactData}”>
continued
Trang 24LISTING 25.4 (continued)
<mx:columns>
<mx:DataGridColumn dataField=”firstname” headerText=”First Name”/>
<mx:DataGridColumn dataField=”lastname” headerText=”Last Name”/>
Using the CallResponder class
One alternative approach to handling result and fault events in a more granular way is to use the new CallResponder class
New Feature
The CallResponder class is new to the Flex 4 SDK n
As with all other RPC classes, you can declare a CallResponder object using either MXML or ActionScript If you declare it in MXML, you must place it inside the <fx:Declarations> sec-tion of an MXML document You can then move the result and fault event handlers to the CallResponder:
Trang 25The CallResponder class also supports the lastResult property You can bind a visual control to the data returned from an operation by using a binding expression that refers to the responder object:
<mx:DataGrid dataProvider=”{myResponder.lastResult}”/> n
Processing Web service operations with ActionScript
Everything you do with the WebService, CallResponder, and other components can be done with pure ActionScript code It’s a question of style: some developers prefer to minimize the use of MXML when dealing with these non-visual classes
There are many ways to design the code; the version in Listing 25.5 uses a WebService and a CallResponder object Upon application startup, the service’s loadWsdl() method is called to retrieve the service description Then upon the load event, the operation is called Finally, the result is handled with yet another event handler
import mx.controls.Alert import mx.events.FlexEvent;
[Bindable]
private var contactData:ArrayCollection;
private var service:WebService = new WebService();
private var responder:CallResponder = new CallResponder();
protected function app_creationCompleteHandler(event:FlexEvent):void
continued