Accessibility

Table of Contents

Put a Flex UI on your application

Calling XML-RPC services from Flex and Adobe AIR

One thing I've found a little puzzling about Flex is the decision about which libraries are included in the standard distribution. For example, in earlier versions of Flex there was an MP3 player component, but for some reason this has vanished (even though the Flash player itself directly supports MP3). And I personally like XML-RPC a lot, so it would seem logical (to me) to include that as well. Fortunately, other people have written replacements, and the Flex packaging mechanism makes these easy to incorporate into your own projects.

After hunting around, I found an ActionScript XML-RPC client library, along with a description and an example. It was written by a user named Akeem. I basically worked from his code but I trimmed it down to make it easier to read.

To use the library, download it and unpack it somewhere on your machine. The package includes all the source code and the compiled as3-rpclib.swc library—the SWC extension indicates an archive file, and pieces of this library can be pulled out and incorporated into your final SWF file. To include the library in your project, you must tell Flex Builder 2 (you can get a free trial or just use the free command-line tools, and add on the Apollo, now called Adobe AIR, portion) where the library is located by going to Project|Properties and selecting "Apollo Build Path," then choosing the "Library path" tab and pressing the "Add SWC..." button. Next, you add the namespace ak33m to your project as seen in the code below, and you're ready to create an XMLRPCObject. If you download the beta of Flex Builder 3, Adobe AIR is included with Flex Builder.

Note: The only reason I used Adobe AIR here was that I was thinking in terms of desktop applications with nice user interfaces. You can just as easily make it a Flex app.

Here's the entire Adobe AIR application as a single MXML file. Below this code snippet, I explain the code in detail.

<?xml version="1.0" encoding="utf-8"?>
<mx: WindowedApplication
      xmlns:mx="/2006/mxml" 
      xmlns:ak33m="http://ak33m.com/mxml"
    layout="absolute">
   <mx:Form>
       <mx:FormHeading label="String Modifier"/>
       <mx:FormItem label="Input String">
           <mx:TextInput id="instring" change="manipulate()"/>
       </mx:FormItem>
       <mx:FormItem label="Reversed">
           <mx:Text id="reversed"/>
       </mx:FormItem>
       <mx:FormItem label="Scrambled">
           <mx:Text id="scrambled"/>
       </mx:FormItem>
   </mx:Form>
   <ak33m:XMLRPCObject id="server" endpoint="http://localhost:8000"/>
   <mx:Script>
       <![CDATA[
           import mx.rpc.events.ResultEvent;
           import mx.rpc.events.FaultEvent;
           import mx.rpc.AsyncToken;
           import mx.controls.Alert;
           import mx.collections.ItemResponder;
           private function manipulate() : void {
            server.reverse(instring.text).addResponder(new ItemResponder(reverseResult, onFault));
            server.scramble(instring.text).addResponder(new ItemResponder(scrambleResult, onFault));
           }
           private function reverseResult(event : ResultEvent, token : AsyncToken = null) : void {
            reversed.text = event.result.toString();
           }
           private function scrambleResult(event : ResultEvent, token : AsyncToken = null) : void {
            scrambled.text = event.result.toString();
           }
           private function onFault (event : FaultEvent, token : AsyncToken = null) : void {
            Alert.show(event.fault.faultString, event.fault.faultCode);
           }             
       ]]>
   </mx:Script>
</mx: WindowedApplication >

MXML is a higher-level abstraction of an application than ActionScript, but the compiler translates MXML into ActionScript, and you can choose to write your entire application in ActionScript instead (if you want to do a lot of extra work— you don't gain anything from it).

An MXML file is proper XML, so it begins with the standard XML tag. The body begins with a tag that determines whether it is a Flex or Adobe AIR application, followed by XML namespaces. The first namespace is the standard mx library that you'll see in every application, but the second ak33m library is the special one added to use Akeem's XMLRPCObject. This is a good example of how to incorporate an external library (you can also just place the source file in your project directory).

The focus of MXML is organizing and laying out components. Note that the main body tag includes a layout attribute; "absolute" means that the components will be glued to their positions regardless of the size or proportion of the application.

MXML provides support for form creation via various Form... tags; it's possible to create these more verbosely, but notice that using the Form... tags requires less work than it would in HTML. (There are also helpful fancy components like calendar date choosers, and a number of standard validators which automatically check user input.) The fact that the result will look the same under every browser on every platform, without any extra effort, makes creating forms this way very appealing.

Each FormItem can have a label, and it neatly organizes the label with the item (something that would take a table in HTML). The TextInput component allows the user to enter text, while the Text component is for display. I'm just showing you the very basic use of these components; they can do a lot more.

Every component can be given an id so it can be referenced elsewhere in the program. The id is like a variable name for that instance of a component. In this program I only give ids to components that I actually reference.

Each component supports a set of events, and you can attach functionality to an event. In the case of the TextInput, the change event (fired when the text in the input box is changed in any way) calls the manipulate() method, defined at the bottom of the program.

The XMLRPCObject, in this case, only needs an id and the "endpoint" to tell it where the server is.

A Script object is wrapped in CDATA because it may contain special characters that need to be escaped. Here, you see ActionScript code embedded directly into the MXML file, but it could also have been placed in an external AS file and referenced from within the MXML file.

One of the first things you'll notice about ActionScript, as a Java programmer, is how remarkably similar it is to Java. Many of the basic concepts and even keywords are the same, which makes it relatively easy for a Java programmer to learn. However, ActionScript often makes things a lot easier than Java does. For example, while packaging and import statements are very similar, you are not faced with the nightmares of Java's CLASSPATH.

Some things are different. As you can see, it's possible to have free-standing functions. And when you define a function, you must actually use the function keyword (ActionScript is a superset of JavaScript). Type declarations are optional (although Flex Builder issues warnings, and I like my warnings to be useful so I add the necessary syntax); without them you get dynamic typing. Type declarations are expressed after type identifiers or function argument lists, following a colon.

Note the manipulate() function, which takes no arguments and returns void. Remember that you set up the TextInput instring to call manipulate() whenever the input text is changed. When this method is called, it uses the server XMLRPCObject to call both the methods available on the server. At first glance, it looks similar to the Python client.

However, the Python client was making synchronous calls—it waited for the XML-RPC server to return the result before continuing. Flex is set up for asynchronicity, which means that it can initiate a call and continue processing while that call runs. The problem with asynchronicity is that you need to somehow catch the result, and the solution is to install a callback function that will automatically be called when the result comes back. Flex comes with built-in support for installing asynchronous callbacks, as you can see from the import statements.

The callbacks are attached as ItemResponders to the object returned from the XML-RPC call, using the addResponder() method. The first argument of the ItemResponder constructor is the function to be called upon success, the second argument is the function to be called in the event of failure. For both calls we are only interested in the first argument that comes back, which contains the result value from the XML-RPC call (from the code, you can see that it's possible to construct more complex callbacks). All the "success" methods do is insert the results in the appropriate text fields.