Developing a Flex WebService client

This is my first article on Flex. I thought my first article would be a simple “Hello World” type of example, but it  is not to be. I had been trying to get a flex based WebServices client running on Flex and it had become a struggle. Fortunately “Google” came to my rescue and I have WebServices client up and running as a standalone application and also using LiveCycle Data Services(LCDS).

So let’s begin with a setting up a direct Flex based WebServices client. But first, a list of softwares I am using:

  • Flex Builder 3
  • Web Tools Project Eclipse plugin (Extremely useful tool to do simultaneous Flex and Java development. Installation instructions are available here
  • Tomcat Web Server 5.5

Create a new Flex project, select application type as Web Application Server technology as J2EE, ensure that the use remote object access service checkbox and LiveCycle Data Services radio button is checked. Additionally if the WTP plugin is installed properly a check box for Create combined Java/Flex project using WTP will be displaced. Select this checkbox. In J2EE settings select Apache Tomcat, if not available create a new Tomcat server. The rest of the project settings are default.

If the project name is Test the folder structure will be as below (Note I am only pointing to folders that are of interest to the developer):

Test --
       |
       |-- flex_src
       |
       |-- WebContent -|
       |-- WEB-INF--|
       |--flex
Create a new Flex MXML application. Here’s the content of the application.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
	<mx:Script>
		<![CDATA[
			import mx.rpc.events.ResultEvent;.
			import mx.rpc.events.FaultEvent;
			import mx.controls.Alert;

			private function handleResult(event:ResultEvent):void {
				configuration.dataProvider = event.result;
			}

			private function handleFault(event:FaultEvent):void {
				Alert.show(event.message.body.toString(), "Body");
				Alert.show(event.fault.message, "Fault Message");
				Alert.show(event.fault.faultString, "Fault");
				Alert.show(event.fault.faultDetail, "Root Cause");

			const faultEventTarget:String = event.currentTarget.toString();
		        const faultErrorId:int = event.fault.errorID;
       		        const faultErrorCode:String = event.fault.faultCode;
		     	const faultErrorDetail:String = event.fault.faultDetail;
			const faultString:String = event.fault.faultString;
			const faultMessage:String = event.fault.message;
			const faultName:String = event.fault.name;
			const faultErrorString:String =
			         "Fault " + faultErrorId + " (" + faultName + "):\n"
				       + "[" + faultErrorCode + "]\n\n"
				       + "FAULT MESSAGE: " + faultMessage + "\n\n"
				       + "FAULT DETAILS: " + faultErrorDetail + "\n\n"
				       + "FAULT STRING: " + faultString;;
			    const faultVerboseErrorString:String =
			       faultErrorString + "\n\n" + "FAULT ON TARGET:\n" + 				faultEventTarget;
			    Alert.show(faultVerboseErrorString, "Root Cause");
			}
		]]>
	</mx:Script>

	<mx:WebService id="sampleWS" useProxy="false" result="handleResult(event);"
		fault="handleFault(event);"
		service="WSServiceName"
		port="WSPort"
		endpointURI="http://abc.com/soap"
		wsdl="http://abc.com/wsdl"/>
	<!--mx:WebService id="sampleDestWS" useProxy="true" result="handleResult(event);"
		fault="handleFault(event);" destination="sampleDestination"/>-->
	<mx:Button x="241" y="281" label="Invoke" id="invoke" click="sampleWS.getConfigurations()" />
	<mx:ComboBox x="229" y="160" editable="true" enabled="true" id="configuration"></mx:ComboBox>

</mx:Application>

Here I am beginning with an assumption that the reader is familiar with the basics of Flex. Our focus area is between lines 38 to 43. Here lies the definition of flex web service client. In line 38, we provide a unique identifier to the flex web service component called “sampleWS”. Since this is a direct WebService client and does not use any Flex based middleware like BlazeDS or LCDS, the useProxy attribute is specified as false. To handle the result processing, we create an ActionScript function called handleResult. In the application the WebService client’s result attribute is used to specify the result processing logic. Similarly fault/error handling logic is defined using the attribute fault as defined in line 39. In line 40 and 41, we have defined the WebService service name and port. In line 42 and 43, the endpointURI points to the URL handling the WebService’s SOAP requests and wsdl points to the WebService WSDL URL.

A typical webservice WSDL is in the following format.
<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
	xmlns:xs="http://www.w3.org/2001/XMLSchema" name="WSServiceName"
	targetNamespace="http://abc.com/" xmlns:tns="http://abc.com/"
	xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
	xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
	xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
	xmlns:ns1="http://www.abc.com/namespaces/Types">
	<types>
		<xs:schema targetNamespace="http://www.abc.com/namespaces/Types"
			xmlns="http://www.abc.com/namespaces/Types">
			<xs:complexType name="TStringDynArray">
				<xs:complexContent>
					<xs:restriction base="soapenc:Array">
						<xs:sequence />
						<xs:attribute ref="soapenc:arrayType"
							n1:arrayType="xs:string[]"
							xmlns:n1="http://schemas.xmlsoap.org/wsdl/" />
					</xs:restriction>
				</xs:complexContent>
			</xs:complexType>
		</xs:schema>
	</types>
	<message name="getConfigurations0Request" />
	<message name="getConfigurations0Response">
		<part name="return" type="ns1:TStringDynArray" />
	</message>
	<portType name="sampleWS">
		<operation name="getConfigurations">
			<input message="tns:getConfigurations0Request" />
			<output message="tns:getConfigurations0Response" />
		</operation>
	</portType>
	<binding name="SOAPbinding" type="tns:sampleWS">
		<soap:binding style="rpc"
			transport="http://schemas.xmlsoap.org/soap/http" />
		<operation name="getConfigurations">
			<soap:operation soapAction="urn:WS#getConfigurations"
				style="rpc" />
			<input>
				<soap:body use="encoded"
					encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
					namespace="urn:sample" />
			</input>
			<output>
				<soap:body use="encoded"
					encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
					namespace="urn:sample" />
			</output>
		</operation>
	</binding>
	<service name="WSServiceName">
		<port name="WSPort" binding="tns:SOAPbinding">
			<soap:address location="http://abc.com/soap" />
		</port>
	</service>
</definitions>

Here’s how the WSDL specific parameters point to the mx:WebService component attributes. The service, port, endpointURI and WSDL mentioned in MXML application from lines 40 to 43. The service attribute maps to name attribute of the service element in the WSDL, refer line 52. The port attribute maps to name attribute of port element in WSDL, refer line 53. The endpointURI points to the service provider URL consuming SOAP requests, in WSDL this maps to the location attribute of the soap:address element (refer line 54 of WSDL). And finally, wsdl attribute points to the location of the WSDL file. Typically it is the SOAP endpoint URI with a “?WSDL” appended to the URI.

Now for getting the Flex WebService client working the following attributes need to be mandatorily defined. They are id, useProxy, result, fault and wsdl. The others are optional and need not be defined.

Typically webservices are invoked across domains. Flash has defined certain policies which prevent crossdomain access. The only way to bypass this security feature is to put a crossdomain.xml file within the server root of the webservice provider i.e. in our case at http://abc.com. A sample example of crossdomain.xml is as below:

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
	<site-control permitted-cross-domain-policies="all" />
	<allow-access-from domain="*" secure="false"/>
	<allow-http-request-headers-from domain="*" headers="*" secure="false" />
</cross-domain-policy>

To learn more about features and how to fine-tune your cross domain access refer to this blog.

If the crossdomain.xml is not added the developer will get “Security Error accessing URL” type of messages.

The above mentioned information should be enough for you to get your flex based WebService client up and running.

OK, now we have got our web service client ready, but this approach has a certain limitation. As long as the web service invoked is an in-house webservice, crossdomain.xml files can be used to bypass the flash security restrictions, but an enterprise webservice external to the organization may not be so accomodating. To overcome this  constraint, Flex provides two server based remoting and messaging technology namely BlazeDS and LiveCycle Data Services(LCDS). I have developed this tutorial around LCDS, however I believe implementing WebService functionality would be similar if not same in BlazeDS.

There are not many changes required. Uncomment the lines 44 and 45 in the mxml application file. In line 46, change the code snippet for click attribute to the following “sampleDestWS.getConfigurations()”. Within the Flex project, go to the flex folder within Test\WebContent\. This folder will contain a number of flex configuration files like data-management-config.xml, messaging-config.xml, proxy-config.xml, remoting-config.xml and services-config.xml. Details around the significance of these files are explained in this blog.

Please open the proxy-config.xml, and add the following xml snippet within the service xml tag.

    <destination id="sampleDestination">
    	<adapter ref="soap-proxy"/>
        <properties>
            <wsdl>http://abc.com/wsdl</wsdl>
            <soap>http://abc.com/soap</soap>
        </properties>
    </destination>

The proxy-config.xml will have an adapter definition named “soap-proxy” mapping to the flex.messaging.services.http.SOAPProxyAdapter.

Even with this setup, one might encounter issues such as “Send failed” “Unable to load WSDL” etc. To overcome this open the Flex project properties in the Flex Builder IDE. Select the property titled “Flex Server” and update the Context root attribute to “/Test”. This should get the web service client running.

I hope this article proves useful in getting your flex web service client configured and running.

Advertisements

2 thoughts on “Developing a Flex WebService client

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s