Monday, January 19, 2009

AIR-ifying a Flex/BlazeDS/Java EE Application

In my first blog post of 2009, I covered a simple example of applying BlazeDS's object remoting capabilities to associate a Flex client with a Java EE server. In this, my 250th overall blog posting, I intend to demonstrate how simple it is to adapt that Flex+BlazeDS application into an AIR+BlazeDS application.

Adobe Integrated Runtime (AIR) allows developers to apply their web development skills to desktop development. While AIR applications can be built from a starting point of DHTML/Ajax/JavaScript, I will be transitioning the Flex application demonstrated in my earlier blog posting into an AIR application for this example.

Douglas McCarroll provides informative coverage of a transition of a Flex application using BlazeDS remoting to an AIR application using BlazeDS remoting in his blog entry A Simple AIR / BlazeDS / Remoting Example. My posting here is a little different from his because mine does not rely on FlexBuilder, my example uses the same XML-based, statically configured channels used in the Flex example (McCarroll demonstrates dynamic, ActionScript-based configuration in his example), and I include some screen snapshots in this posting. Two other AIR+BlazeDS blog postings include Connecting an AIR Client with BlazeDS Using Spring/Hibernate and Connecting AIR with BlazeDS and Spring.

In my previous blog posting on Flex used in conjunction with BlazeDS object remoting, I had a very simple Flex MXML file that is reproduced here for convenience:

ComplexObjectRemoteClient.mxml (Flex)


<?xml version="1.0" encoding="UTF-8" ?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="1100" height="700">

<mx:Script>
import dustin.Person;

/**
* Prepare provided name information and send to server.
*
* @param firstName First name of person.
* @param lastName Last name of person.
*/
public function processAndSubmitName(firstName:String, lastName:String):void
{
const person:Person = new Person(firstName, lastName);
remoteObject.processName(person);
}
</mx:Script>

<!-- Associate client with BlazeDS destination via RemoteObject. -->
<mx:RemoteObject id="remoteObject" destination="HelloWorld" />

<mx:Panel id="mainPanel" title="BlazeDS Remoting Example - Complex Object Mapping">
<mx:Form>
<mx:FormItem label="Your First Name">
<mx:TextInput id="firstNameInput" />
</mx:FormItem>
<mx:FormItem label="Your Last Name">
<mx:TextInput id="lastNameInput" />
</mx:FormItem>
<mx:FormItem>
<mx:Button label="Submit Name!"
click="processAndSubmitName(firstNameInput.text, lastNameInput.text);" />
</mx:FormItem>
<mx:FormItem label="Server's Response">
<mx:Label text="{remoteObject.processName.lastResult}" />
</mx:FormItem>
</mx:Form>
</mx:Panel>
</mx:Application>



Not much is required to convert the above Flex client source file into an AIR client source file. In fact, I can keep the .mxml file extension for the AIR application source file and only need to make minor changes to the Flex source file just shown. The adapted source for AIR is shown next.

ComplexObjectRemotingAirClient.mxml (AIR)


<?xml version="1.0" encoding="UTF-8" ?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
title="Complex Object Remoting Migrated to AIR">

<mx:Script>
import dustin.Person;

/**
* Prepare provided name information and send to server.
*
* @param firstName First name of person.
* @param lastName Last name of person.
*/
public function processAndSubmitName(firstName:String, lastName:String):void
{
const person:Person = new Person(firstName, lastName);
remoteObject.processName(person);
}
</mx:Script>

<!-- Associate client with BlazeDS destination via RemoteObject. -->
<mx:RemoteObject id="remoteObject" destination="HelloWorld" />

<mx:Panel id="mainPanel" title="BlazeDS Remoting Example - Complex Object Mapping">
<mx:Form>
<mx:FormItem label="Your First Name">
<mx:TextInput id="firstNameInput" />
</mx:FormItem>
<mx:FormItem label="Your Last Name">
<mx:TextInput id="lastNameInput" />
</mx:FormItem>
<mx:FormItem>
<mx:Button label="Submit Name!"
click="processAndSubmitName(firstNameInput.text, lastNameInput.text);" />
</mx:FormItem>
<mx:FormItem label="Server's Response">
<mx:Label text="{remoteObject.processName.lastResult}" />
</mx:FormItem>
</mx:Form>
</mx:Panel>
</mx:WindowedApplication>


The most significant change was changing of the root element of the Flex source code (mx:Application) to the root element expected by AIR (mx:WindowedApplication). I also removed the width and height attributes associated with the Flex source code's root tag and replaced them with layout and title tags. The rest of the source file remain unchanged from the Flex version to the AIR version.

With the AIR source code easily in place thanks to the easy migration of Flex source code to AIR source code, I now move onto creating the AIR XML-based descriptor file. It is shown next (you can name it whatever you like as long as you reference it by the same name in the application packaging step shown later):

AIR-ComplexObjectRemoting.xml


<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://ns.adobe.com/air/application/1.5">
<id>blog.dustin.ComplexObjectRemoting</id>
<version>0.01</version>
<filename>ComplexObjectRemotingAirClient</filename>
<initialWindow>
<content>ComplexObjectRemotingAirClient.swf</content>
<visible>true</visible>
<systemChrome>none</systemChrome>
<transparent>true</transparent>
<width>1100</width>
<height>700</height>
</initialWindow>
</application>


It is important to note the AIR namespace used in this XML descriptor file. It is 1.5 because I am using AIR 1.5 and Flash Player 10. If I had 1.0 instead of 1.5 in that XML and was using AIR 1.5 and Flash Player 10, I might see an error message like that shown in the next screen snapshot.



The screen snapshot shown above states "Initial window content SWF version 10 exceeds namespace version http://ns.adobe.com/air/application/1.0" and provides the clue that either the namespace needs to be changed to 1.5 as shown above or the version of AIR and Flash Player needs to be reduced.

The adt command was used in the screen snapshot above that showed the error message when the AIR XML-based descriptor used a different AIR-related namespace than what was expected by the version of AIR and associated Flash Player. Before we can run the adt command as shown above, however, we must first compile our AIR source code into an SWF.

If you already have the Flex 3.2 SDK, you automatically have the AIR 1.5 tools you need. In fact, if you look in the bin subdirectory of your Flex SDK installation, you will see AIR-specific commands such as adt alongside the Flex command-line options such as mxmlc. The AIR command-line compiler, amxmlc, is located in this same directory. While we could run amxmlc directly, it simply is a call to Flex's mxmlc with the option +configname=air provided to the mxmlc compiler. This is discussed in greater detail in Compiling an AIR Application with the amxmlc Compiler.

The command-line syntax to compile the AIR source code shown above is thus:

Compiling AIR MXML Source Code into AIR SWF


mxmlc +configname=air -debug=true -context-root=HelloWorldRemotingServer -services=services-config.xml -output=ComplexObjectRemotingAirClient.swf -- ComplexObjectRemotingAirClient.mxml


With the AIR-based SWF generated, it is time to package up the AIR application. However, before doing that we need to generate a security certificate using adt as shown next:

Generating a Security Certificate


adt –certificate –cn DustinSigned 1024-RSA sampleCertificate.pfx dustinWasHere


The important thing to note for now from the command shown above for certificate generation is the name (sampleCertificate.pfx) and the password (dustinWasHere).

With the Flex MXML source code converted easily to AIR MXML source code and then compiled into an AIR SWF, with the AIR XML descriptor file generated, and with the security certificate generated, we are ready to package it all up into an AIR application with a .air extension. That command is shown next:

Packaging the AIR Application


adt -package -storetype pkcs12 -keystore sampleCertificate.pfx -storepass dustinWasHere ComplexObjectRemotingClient.air AIR-ComplexObjectRemoting.xml ComplexObjectRemotingAirClient.swf


With careful examination of the above command, one can see that adt -package is the basic command for packaging an AIR application and that it allows for the keystore generated earlier to be specified along with the password set up earlier (dustinWasHere). The name of the generated file that is the AIR application is the name ending with an .air extension and the XML descriptor and SWF file that go into that generated AIR file are listed after the generated file's name in the command.

To run the generated AIR application, its name (ComplexObjectRemotingClient.air) can be typed on the command line or the file name can be clicked on in a Window. Two screen snapshots that follow show some of what one sees when running this AIR application for the first time. These snapshots assume previous installation of the AIR runtime.





Assuming that the server-side servlet demonstrated in my earlier Flex blog posting is deployed on GlassFish or other Java EE-compatible web server, the AIR client shown above will go through a cycle that includes the following two screen snapshots.





One final gotcha to mention here in relation to using BlazeDS and transitioning from Flex to AIR is the need to make a minor tweak to the services-config.xml file used in the AIR client. In the Flex client, we got away with using the token {context.root} and having the Flex mxmlc command replace this token with the value specified with the -services option. I found that with the AIR client I needed to replace this context.root token with the actual context name. The reason for this is documented in the Flex Cookbook Beta under How to Configure the services-config.xml for AIR Application to Communicate with BlazeDS.

Conclusion

BlazeDS can be used with AIR and rich desktop applications very similarly to how it is can be used with Flex for rich internet applications. The AIR development model that allows for Flex applications to be easily converted into AIR applications makes it possible for Flex developers to write code that is easily ported between a web browser environment and a desktop environment. Because BlazeDS is useful with both Flex and AIR, Java EE back-ends can provide logic and data to back up rich web applications and rich desktop applications.

2 comments:

Raju Bitter said...

Congratulations on your 250th blog post. Nice example, keep up the good blogging!

Krishna said...

Flex 3.0 Applications with BlazeDS in Eclipse