Quick AIR Development Trick – Send to Second Monitor

I’ve been developing and debugging an AIR app for an upcoming demo, and running into the same problem, I start debugging the app in ADL, and immediately have to move it over to my second monitor so I can see code while looking at the app.

Or I could just set the X and Y coordinates in my application manifest file. Now it launches on the second monitor every time.

Just have to remember to switch back before production.

AIR Launchpad

Greg Wilson announced yesterday the release of Adobe AIR Launchpad.

These days, I get inundated with new projects, releases, plugins and helpers, so it’s hard to catch my eye. However, let me say, if you are interested in AIR development, you need to take a look at AIR Launchpad.
There are things that many of the cool AIR applications do:

  • Install via a badge, which handles both AIR and app installation
  • Run an automatic updater
  • Have icons for multiple purposes
  • Store configurations locally
  • Use local storage
  • Use a local database
All of these things are relatively easy. However you have to wade through lots of API specific code to get started with it. Each of those bullet points is easily a blog entry. In many cases the blog entry is needed just to wrap your mind around these things.
However with Launchpad, you can create an application with any of these features and more already wired up with very well commented code. In short, why read about it, when you can just do it.
Hats off to Greg and his team for creating a major productivity jumpstart for AIR developers. If you are interested in AIR you need to download Launchpad now.

Interested in Making Money from AIR

Adobe and Intel are doing a joint event in San Francisco tomorrow. It’s focused on AIR and Intel’s AppUP Center for distributing apps.

Check it out

Date: Wednesday, July 21st

Location: Adobe Systems Office

Address: 601 Townsend, San Francisco, CA 94103

Parking: Parking will be extremely limited in the Adobe parking structure;however, there is street parking available.

ColdFusion AIR Synchronization

First, let me just cop to the fact that this post draws a lot from Jayesh Viradiya’s post on this ColdFusion/AIR Offline support. I had to simplify his stuff to wrap my mind around it enough to talk about it. So hats off to Jayesh, he’s done some awesome work here.

I was doing a demo on ColdFusion and AIR integration at the keynote for CFUnited, and I figured I would go into a little more detail here.

First off, to call it “ColdFusion and AIR integration” is to do it a bit of a disservice. What our engineers have accomplished is nothing short of “ORM for AIR.” It handles:

  • Creating and maintaining the SQLite database
  • Saving objects to SQLite without SQL statements
  • Handling relationships:
    • one-to-one
    • one-to-many
    • many-to-one
    • many-to-many
  • Syncing those records back to ColdFusion

So I have a sample application that shows a basic demo of this, without the relationships. Jayesh’s demo has the relationships. I’ve attached the code here, so if you want to look at it, just download the whole thing. Otherwise, let me take you through it. One little note, this stuff was written for ColdFusion 9 Beta. There are some bugs. I’ll point them out where I can, and assure you that the bugs are being worked on.

So let’s start in the ColdFusion. First I define an ORM cfc:

component persistent="true"{
property name="personID" fieldtype="id";
property name="firstName";
property name="lastName";
property name="twitter";

public string function serial(){
return "#This.getFirstName()#|#This.getLastName()#|#This.getTwitter()#|#This.getpersonID()#";

Pretty straightforward; then I define a corresponding ActionScript class:

package airdemo
public class Person
public var personID:int;
public var firstName:String;
public var lastName:String;
public var twitter:String;

Note the RemoteClass mapping to the CFC on the back end. Now let’s go to the application. I have a simple data grid and form designed to show and edit the details of these person objects. I’ll skip that and go right to the part where I hook up AIR to the ColdFusion server:

private function init():void
// Provide Credentials for Server side Connection and CFC
syncmanager = new SyncManager();
syncmanager.cfPort = 80;
syncmanager.cfServer = "centaur.dev";
syncmanager.syncCFC = "AirDemo.personManager";

// THis handler will be called when any COnflict
// occurs while writing back changes on serverside
syncmanager.addEventListener(ConflictEvent.CONFLICT, conflictHandler);

//Kick off the application.


This connects this application to the ColdFusion server centaur.dev on port 80 and wires the syncmanager to AIRDemo.personmanager. More on that later. But it also kicks off getRemote which takes care of populating this application with data from the server. So getRemote() fires:

//GET records from BACKEND SERVER
private function getRemote():void{
var token:AsyncToken= syncmanager.fetch("fetch");
token.addResponder(new mx.rpc.Responder(fetchSuccess, fetchFault));

Syncmanager.fetch calls the fetch method of the ColdFusion CFC we set as syncmanager.syncCFC above. That method just retrieves the records using ColdFusion ORM.

remote Array function fetch(){
return EntityLoad('person');;

In most cases it is successful, in which case fetchSuccess calls createLocalDB:

//CREATE the actual SQLite DB
private function createLocalDB():void{
//Create a pointer to actual SQLite db file
dbFile = File.userDirectory.resolvePath("AirDemo.db");

var sessiontoken:SessionToken =syncmanager.openSession(dbFile,017916);
sessiontoken.addResponder(new mx.rpc.Responder(connectSuccess,connectFault));

In most cases that is successful and connectSuccess calls createLocalCacheFromRemote

//PUT records from BACKEND SERVER in SQLite DB
private function createLocalCacheFromRemote():void{
var savetoken:SessionToken = session.saveUpdateCache(pc);
savetoken.addResponder(new mx.rpc.Responder(saveCacheSuccess, savefault));

Those three ActionScript functions in concert with the ColdFusion one:

  • Got the data from the ColdFusion server
  • Created a local SQLite database for the data
  • Populated the local SQLite data with that data

Okay, so now I go through the application, update some data, and want to save it back to the SQLite database:

//SAVE to SQLite DB
private function saveLocal():void
//Generate person object from form.
var person:Person = convertFormToObject();

//session.saveUpdate saves record to SQLite Database
var savetoken:SessionToken = session.saveUpdate(person);
savetoken.addResponder(new mx.rpc.Responder(saveSuccess, savefault));

ConvertFormToObject does exactly what it sounds like, converting values from a form into a Person object, then session.saveUpdate() handles saving the record back to the SQLite store. No SQL required. Then we need to send it off to the ColdFusion server:

private function saveRemote():void
var committoken:SessionToken = session.commit();
committoken.addResponder(new mx.rpc.Responder(commitSuccess, commitFault));

That’s it. That transmits all of that changes made in this session to the ColdFusion server, where it is processed:

remote any function sync(required array operations,
required array clientobjects,
array originalobjects = ArrayNew(1)){

var i= 0;
var conflicts = ArrayNew(1);
var conflictcount = 1;

for (i=1; i <= ArrayLen(operations); i++ ){

var operation = operations[i];
var clientobject = clientobjects[i];
var originalobject = originalobjects[i];

if (operation eq "INSERT" ){
var obj = ORMGetSession().merge(clientobject);

if (isinstanceOf(originalobject,"person")){
var serverobject = EntityLoadByPK("person",originalobject.getpersonID());
throw "Invalid Object";

if (not isdefined('serverobject')){
var conflict = New CFIDE.AIR.conflict();
conflict.clientobject = clientobject;
conflict.originalobject = originalobject;
conflict.operation = operation;
conflicts[conflictcount++] = conflict;

var isNotConflict = (originalobject.serial() eq serverobject.serial());
if (isNotConflict){
if (operation eq "UPDATE"){
obj = ORMGetSession().merge(clientobject);
else if (operation eq "DELETE"){
obj = ORMGetSession().merge(originalobject);
var text="is a conflict";
var conflict = New CFIDE.AIR.conflict();
conflict.clientobject = clientobject;
conflict.originalobject = originalobject;
conflict.operation = operation;
conflicts[conflictcount++] = conflict;
if (conflictcount gt 1){
return conflicts;

So this is a lot of code, but basically it performs the following steps:

  • Check to see if the record is new
    • If so insert it
  • Then check to see if the update is in conflict
    • If not, delete or update accordingly
    • If so, send a conflict back to the AIR client

Now back in the client you have to handle the conflict, in this version of the application, I just replace the client details with the server details:

public function conflictOverwrite(conflicts:ArrayCollection):void{
var token:SessionToken = session.keepAllServerObjects(conflicts);
token.addResponder(new mx.rpc.Responder(conflictSuccess, conflictFault));

Again, one function, session.keepAllServerObjects, handles overwriting everything on the client.

So that is the gist of what I was going to show at CFUnited. The code is attached, (Down at the bottom there is a “download” link) feel free to give it a try and see what you can do with it.

ColdFusion + AIR applications

I’m just getting started into this evangelist thing, and I’m having trouble figuring out what AIR applications out there are being powered by ColdFusion on the backend. The only one that comes to mind for me at the moment is Broadchoice.

Can the ColdFusion community help me find the following?

AIR applications using either Flex or HTML/JS that use ColdFusion for any part of their backend

Please send URL’s and any commentary to the comments of this page. Alternately, contact me through my contact page if you’re willing to help, but can’t talk about these things publicly.

DMD Project at Carnegie Mellon University

I got to see a very cool use for Flex and AIR in Higher Education today. It’s the DMD Project from the Masters in Human-Computer Interaction Program at Carnegie Mellon University.

It’s a prototype RIA for patient management at dental offices. It was designed for touch screens, but also can be used with the traditional keyboard and mouse interface as well. It shows everything dentists, hygienists, and front office staff would need to manage the entire patient interaction.

I got a chance to talk with one of the developers, Jaanus Kase, about it. He told me that they spent most of their time upfront researching how exactly dentist’s offices would need to interact with a system. That yielded a few custom interfaces, including the “radiograph view” which the rest of us just know as “an x-ray of all of your teeth.” The other cool thing I noticed was the high emphasis they place on important information like “Severe Penicillin Allergy.” Clearly, this program really does focus on quality computer-human interactions.

The project itself is a prototype; don’t expect to see it in your dentist’s office anytime soon. But the app is available as an AIR application for your review.

Jaanus is done with the Masters program now, and is working with an startup in New York named World Evolved.

…Hello Adobe

Wow that took less time than I thought… So yeah, I’m joining Adobe. Specifically I’m joining Adobe’s Platform Evangelism group. I’ll be working under Kevin Hoyt with the team that includes Ryan Stewart, Lee Brimelow and Danny Dura amongst others and ultimately headed by Ben Forta. So it will take all of my composure to not, you know, break down into an Adobe fanboy in my first staff meeting.

What does that mean? It means that I will be working with the rest of the team to spread excitement about the Adobe Platform Products:

  • Flash
  • Flex
  • Air
  • ColdFusion
  • LiveCycle
  • Flash Catalyst
  • BlazeDS

I’ll be promoting the entire platform, but considering my experience to date, I imagine that I’ll start with a slight focus on ColdFusion and AIR.

However in addition to that focus I will have an overriding goal:

Get Adobe Platform Technologies taught in the classrooms of Higher Ed.

It’s a big goal, and not a trivial challenge. I see a lot of different paths to achieving it. I can’t wait to work with all of you to accomplish it.

And as my first act of Evangelism I will remind you once again that both ColdFusion and Flex Builder are available free to Higher Education. All you have to do is go to one of their respective “freeriatools” sites, fill out a form, and upload a picture of your Academic ID.