Accessibility

Table of Contents

Exchanging Complex Data with Back-End Systems

Using HTTPService

There are two commonly used approaches to send data to the server using the HTTPService:

  • Passing request parameters
  • Sending XML over HTTP

Passing Request Parameters

The request-parameters approach works fine for simple data. In the Employee Directory application (see Figure 1), we send basic employee information (first name, last name, salary, and start date) to a JavaServer page.

Simple Employee Directory application

Figure 1. Simple Employee Directory application

Here is the source code for the simple Employee Directory application:

employeehttp.mxml

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml"
    backgroundColor="#FFFFFF">

    <mx:HTTPService id="srv" url="employeehttp.jsp" method="POST">
        <mx:request>
            <firstName>{firstName.text}</firstName>
            <lastName>{lastName.text}</lastName>
            <salary>{salary.text}</salary>
            <startDate>{startDate.text}</startDate>
        </mx:request>
    </mx:HTTPService>

    <mx:Form>
        <mx:FormItem label="First Name">
            <mx:TextInput id="firstName"/>
        </mx:FormItem>
        <mx:FormItem label="Last Name">
            <mx:TextInput id="lastName"/>
        </mx:FormItem>
        <mx:FormItem label="Salary">
            <mx:TextInput id="salary"/>
        </mx:FormItem>
        <mx:FormItem label="Start Date">
            <mx:DateField id="startDate"/>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button label="Add Employee" click="srv.send()"/>
        </mx:FormItem>
    </mx:Form>

</mx:Application>

At the server side, it's business as usual: You access the request parameters using the traditional API provided by your server-side language. Here is a JSP example:

employeehttp.jsp

<%
    String firstName= request.getParameter("firstName");
    String lastName= request.getParameter("lastName");
    String salary= request.getParameter("salary");
    String startDate= request.getParameter("startDate");
// Some business logic to process the data
%>
<status>ok</status>

One advantage of this approach is that, from the server point of view, it works exactly like an HTML front end. This makes it particularly easy to replace an HTML-based user interface with a Flex front end.

In HTML, the request parameters approach works fine, mainly because the client side of the application is stateless and because the data-entry process is split across multiple pages. Therefore the data submitted to the server in one single request is never overly complex.

By contrast, a Flex application is stateful; the data-entry process is not constrained by the page-centric nature of HTML. You use rich user interface components to allow users to enter more complex data in a single integrated user interface. For example, Figure 2 represents an improved version of the Employee Directory application in Figure 1, where users can enter an unlimited number of phone numbers for an employee.

Improved Employee Directory application

Figure 2. Improved Employee Directory application

With the availability of more sophisticated user interfaces, you will often need to submit more complex data to the server in one single request than you do in HTML. When the complexity of the data increases, the request-parameters approach becomes cumbersome. In that case, sending an XML document is usually a better approach.

Sending XML Over HTTP

There are two major approaches to sending XML data over HTTP:

  • Sending XML as a request parameter
  • Sending XML in an "application/xml" request

Sending XML as a Request Parameter: The code below provides an implementation of the Employee Directory application, where data is sent to the server in an XML string passed as a request parameter:

employeexml.mxml

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml"
    backgroundColor="#FFFFFF"
    initialize="initApp()">

    <mx:Script>

        var employee: Employee;

        function initApp() {
            employee=new Employee();
            employee.phoneNumbers=new Array();
        }

        function addEmployee() {
            employee.firstName=firstName.text;
            employee.lastName=lastName.text;
            employee.startDate=startDate.selectedDate;
            employee.salary=Number(salary.text);
            srv.send({xml: XMLUtil.as2xml(employee, "employee")});
        }

    </mx:Script>

    <mx:HTTPService id="srv" url="employeexml.jsp" method="POST"/>

    <mx:Form>

        <mx:FormItem label="First Name">
            <mx:TextInput id="firstName"/>
        </mx:FormItem>
        <mx:FormItem label="Last Name">
            <mx:TextInput id="lastName"/>
        </mx:FormItem>
        <mx:FormItem label="Salary">
            <mx:TextInput id="salary"/>
        </mx:FormItem>
        <mx:FormItem label="Start Date">
            <mx:DateField id="startDate"/>
        </mx:FormItem>

        <mx:FormItem label="Phone Numbers" verticalGap="1">
            <mx:DataGrid id="dg" editable="true"
                dataProvider="{employee.phoneNumbers}">
                <mx:columns>
                    <mx:Array>
                        <mx:DataGridColumn columnName="type" headerText="Type" 
                            cellRenderer="PhoneTypeRenderer"/>
                        <mx:DataGridColumn columnName="number" headerText="Number"/>
                    </mx:Array>
                </mx:columns>
            </mx:DataGrid>
            <mx:HBox horizontalGap="1" width="100%" horizontalAlign="right">
                <mx:Button label="+" 
cornerRadius="0" borderThickness="0" width="20" height="20" 
                    click="dg.addItem(new PhoneNumber('H'))"/>
                <mx:Button label="-" 
cornerRadius="0" borderThickness="0" width="20" height="20" 
                    click="dg.removeItemAt(dg.selectedIndex)" />
            </mx:HBox>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button label="Add Employee" click="addEmployee()"/>
        </mx:FormItem>

    </mx:Form>

</mx:Application>

Notice that the application uses a simple object-to-XML conversion utility. Here is its source code:

XMLUtil.as

class XMLUtil {

    static function as2xml(obj: Object, nodeName: String) {
        var xml:XML=new XML();
        xml.appendChild(xml.createElement(nodeName));
        for (var i in obj) {
            handleItem(xml, obj[i], i);
        }
        return xml;
    }

    private static function handleItem(xml, item, nodeName: String) {
        var type=typeof item;
        if (type=="string" || type=="number" || item instanceof Date) {
            var el=xml.createElement(nodeName);
            el.appendChild(xml.createTextNode(item));
            xml.firstChild.appendChild(el);
        } else if (item instanceof Array) {
            for(var i=0; i<item.length; i++)
                handleItem(xml, item[i], nodeName);
        } else if (item instanceof Object)
            xml.firstChild.appendChild(as2xml(item, nodeName));
    }

}

The Employee.as and PhoneNumber.as classes used in the application are defined as follows:

class Employee {
    public var firstName : String;
    public var lastName : String;
    public var salary : Number;
    public var startDate : Date;
    public var phoneNumbers : Array;
}

class PhoneNumber {

    public var number : String;
    public var type : String;

    function PhoneNumber(type: String) {
        this.type=type;
    }

}

In this example, the benefits of first loading the data in an ActionScript object (Employee.as) before creating the XML document might not be obvious. However, in Flex applications, you are typically manipulating data as objects. (Even when you retrieve an XML document from the server using the HTTPService, the data is deserialized into an object graph by default.) So when you use the HTTPService, the need to convert objects to XML is a very common scenario.

At the server side, you access the "xml" request parameter using the API provided by the language you are using. You then typically use the XML parsing API provided by that language to process the information further. Here is a JSP example:

employeexml.jsp

<%
    String xml=request.getParameter("xml");
    // Some business logic to process the data 
%>
<status>ok</status>

Sending XML in an "application/xml" Request: To use this approach, just add contentType="application/xml" to the HTTPService tag definition in employeexml.mxml, and replace the following:

srv.send({xml: XMLUtil.as2xml(employee, "employee")});

with this:

srv.send(XMLUtil.as2xml(employee, "employee"));

At the server side, your application now needs to handle an "application/xml" request. To do so, you typically use an input stream to read the incoming request. You then parse the received XML document using the parsing API provided by your server-side language. Here is a JSP example:

<%@ page import="java.io.BufferedReader,
                 javax.xml.parsers.DocumentBuilderFactory,
                 javax.xml.parsers.DocumentBuilder,
                 org.w3c.dom.Document,
                 org.xml.sax.InputSource"%>
<%
    BufferedReader br = new BufferedReader(request.getReader());
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = factory.newDocumentBuilder();
    Document doc = db.parse(new InputSource(br));
    // Process the XML document
%>
<status>ok</status>

One nice feature of Flex when you use "application/xml" requests is that you actually don't have to perform the object-to-XML transformation yourself. You can provide an object as the request content and let Flex convert it automatically to XML.

To use the automatic object-to-XML encoding in the Employee Directory application, replace the following:

srv.send(XMLUtil.as2xml(employee, "employee"));

with this:

srv.send(employee);

Flex also allows you to substitute the default encoding logic with your own logic by providing an implementation for the xmlEncode() method of the HTTPService. For example, to substitute the default encoding logic with the logic implemented in XMLUtil.as, add the following block of code to the initApp() method:

srv.xmlEncode=function(obj: Object) {
return XMLUtil.as2xml(obj, "data");
}