Flex 3, ColdFusion 8, and Error #1034

Posted on the December 11th, 2008 under ColdFusion, Flash Remoting, Flex by Mister

Working on project for a new client I had had the opportunity to use Flash Remoting from Flex to talk to services on a ColdFusion server without running the ColdFusion server locally on my machine. Since I am working remote these days (at home), I wanted to connect to the CFC's on the ColdFusion server remotely from my local Flex Builder 3 working environment. I setup a simple "Hello World" example that I found over at ASFusion.

I uploaded the HelloWorldService.cfc file to the remote server in "C:\ColdFurion8\wwwroot\components\com\test\HelloWolrdService". I then set up a RemoteObject with the endpoint property pointing to the remote ColdFusion server instead of the local host (since the example points to a local host):

<mx:remoteobject id="CFCService" endpoint="http://myremoteserver.com/flashservices/gateway/" source="components.com.test.HelloWorldService" result="getResponse(event.result)">

But I got a "Security Sandbox Error" right away from the call. This usually tells me that there needs to be a crossdomain.xml file on the root of server allowing access from my specific location or completely open using the "*" value. For more on the Flash security policy, check out plenty of info at Adobe's site.

I uploaded the crossdomain.xml file to the root with the proper security settings (completely open in my case) and gave the server a restart just for kicks (though I don't think its required when you change or modify the crossdomain.xml file under normal circumstances (I had some other issues unrelated to this blog post, but our admin was able to unblock those, basically the server also runs an additional web server on the same box as ColdFusion which was caused problems temporarily). So I ran the example again and received this error:

Error #1034: Type Coercion failed: cannot convert Object@359af2e1 to
mx.messaging.messages.ErrorMessage

This error really stumped me because I am by no means any expert at ColdFusion and it has been years since I have had to mess around with it in any fashion. I searched and searched for this error in relation to ColdFusion and Flex. I was pulling my hair out, was it the port, was it the server address, was it the location of the CFC files, what was the issue?

I was really surprised at all the examples I found, they all were setup with both Flex and ColdFusion running on the same machine. Almost nobody was running Flex locally and accessing ColdFusion CFC's remotely, and this is what I really needed. I eventually found a post on FlashComGuru where the author had the same exact problem as me.

It turns out that my RemoteObject had a couple of issues. First, it needed to have the destination property set, in this case ColdFusion is the default name set in services-config.xml file. Second, I had to change the endpoint property from "http://myremoteserver.com/flashservices/gateway/" to "http://myremoteserver.com/flex2gateway/", changing the default gateway of the remote server to "flex2gateway". So my updated RemoteObject code looks like this:

<mx:remoteobject id="CFCService" endpoint="http://myremoteserver.com/flex2gateway/" source="components.com.test.HelloWorldService" result="getResponse(event.result)">

Finally, the Hello World example worked great! However, when I tried the application I was working on to hit the application specific CFC files, I didn't get the results I wanted. As I mentioned briefly before, the server is also running another web server on the same box as the ColdFusion server. So the web root of the web server is "inetpub/wwwroot/" and the application CFC's were located under this web server's directory. In order to get them to work for me, I had to move them to the ColdFusion wwwroot folder "C:\ColdFurion8\wwwroot\components\".

I am sure there is a way to map the ColdFusion component directory to another server, but to save time and get myself back on schedule, I settled with placing my CFC file son the ColdFusion server instead, for now anyways.

I hope this post is at least a pointer to a very hard to track issue with using Flash Remoting with Flex and ColdFusion 8. The kind of lighthouse for those Flex developers who might find themselves in the same bind :).

-Mister

Reblog this post [with Zemanta]

Storing an ArrayCollection in the EncryptedLocalStore

Posted on the December 5th, 2008 under AIR, Flex by Mister

On one of my side AIR projects I got the idea to store an ArrayCollection (AC) object into the EncryptedLocalStore (ELS) to have a sort of mini data structure. I thought it would be no problem since you can basically throw anything you want into the EncryptedLocalStore as long as its not over 10MB where performance would be hampered. I built a little sample script to test the idea by filling an AC with a bunch of value objects. Upon retrieving the AC from the ELS, I cast it as an AC, but none of the value objects were readable. I tried casting the value objects, but that threw a runtime error in Flex.

I did some searching around and found one example from the Adobe AIR cookbook that stores and retrieves an value object from the ELS, casting the object as a value object when retrieved. However, I really wanted to store a whole AC of value objects and retrieve them. So I did a little more searching and found one blog post that outlines the same issue I was having: "when I read the object from disk back into my application, the type of objects from Array Collection is lost."

Ok, cool, so the blog post lists a generic function to solve the solution by transforming the objects stored in the AC back to a proper value object. I wanted to make a little demo that combines the AIR cookbook example with the solution for storing/retrieving AC from the ELS with a slight modification of the generic function.

The first step is to create our Contact value object similar to the cookbook example:

Contact.as

package com.thanksmister
{
    [Bindable]
    public class Contact
    {
        public var firstName:String;
        public var lastName:String;
        public var phoneNumber:String;
       
        public function Contact(firstName:String = "", lastName:String = "", phoneNumber:String = "")
        {
            this.firstName = firstName;
            this.lastName = lastName;
            this.phoneNumber = phoneNumber;
        }

    }
}

Now we create a function that creates an ArrayCollection of Contact value objects and stores those in the EncryptedLocalStore:

private function storeContacts():void
{
     var contact:Contact = new Contact( "Michael", "Ritchie", "555-555-5555" );
     var ac:ArrayCollection = new ArrayCollection();
          ac.addItem(contact);
     var bytes:ByteArray = new ByteArray();
           bytes.writeObject( ac );
    EncryptedLocalStore.setItem( "contacts", bytes );
}

Ok, now we have stored out ArrayCollection of Contact VO's in the EncryptedLocalStore, now we need to write a function that retrieves the AC and transforms all of the VO's back to something that we can utilize within Flex:

private function retrieveContacts():void
{
    // retrieve AC from ELS
     var bytes:ByteArray = EncryptedLocalStore.getItem( "contacts" );
     var collection:ArrayCollection = bytes.readObject() as ArrayCollection;
     collection = serializeContacts(Contact, collection);
    // trace our collection value
    trace(Contact(collection.getItemAt(0)).firstName);
}

private function serializeContacts(valueObject:Class, arryCollection:ArrayCollection):ArrayCollection
{
     // use the the flash.utils.describeType to create an XML of the property names within the object
     var xml:XML = describeType(new valueObject());
     var properties:XMLList = xml..accessor.@name;
     var tempac:ArrayCollection = new ArrayCollection();
     
     // iterate through the collection passed into the function and reassign the types to it's objects
     for each (var object:Object in arryCollection) {
          var tempvo:Object = new valueObject();
           for each(var name:Object in properties) {
                tempvo[name] = object[name];
           }
           tempac.addItem(tempvo); //add the item to collection
      }

       // return an ArrayCollection of the Class file passed into the function
       return tempac;
}

The above serializeContacts function takes a Class file (VO) and an ArrayCollection pulled from the EncryptedLocalStore using the retrieveContacts function. The VO is our Contact VO that we want to use to transform our ArrayCollection of objects. This generic function is pretty much what Mihai Corlan used on his blog post, but I changed" xml..value.@name;" from the example he posted to "xml..accessor.@name;" in my example in this post because the dump using the describeType() utility method the node we want is "accessor". (The describeType() method returns an xml dump of the details about the object that is passed into the method. This is a pretty cool function that I previously didn't know about.) Here is the dump of our Contact value object when I trace out the "xml" value from the above serializeContacts function:

xml:

<type name="com.thanksmister::Contact" base="Object" isdynamic="false" isfinal="false" isstatic="false">
  <extendsclass type="Object">
  <implementsinterface type="flash.events::IEventDispatcher">
  <constructor>
    <parameter index="1" type="String" optional="true">
    <parameter index="2" type="String" optional="true">
    <parameter index="3" type="String" optional="true">
  </parameter>
  <accessor name="lastName" access="readwrite" type="String" declaredby="com.thanksmister::Contact">
    <metadata name="Bindable">
      <arg key="event" value="propertyChange">
    </arg>
  </metadata>
  <method name="dispatchEvent" declaredby="com.thanksmister::Contact" returntype="Boolean">
    <parameter index="1" type="flash.events::Event" optional="false">
  </parameter>
  <method name="hasEventListener" declaredby="com.thanksmister::Contact" returntype="Boolean">
    <parameter index="1" type="String" optional="false">
  </parameter>
  <accessor name="phoneNumber" access="readwrite" type="String" declaredby="com.thanksmister::Contact">
    <metadata name="Bindable">
      <arg key="event" value="propertyChange">
    </arg>
  </metadata>
  <method name="willTrigger" declaredby="com.thanksmister::Contact" returntype="Boolean">
    <parameter index="1" type="String" optional="false">
  </parameter>
  <method name="removeEventListener" declaredby="com.thanksmister::Contact" returntype="void">
    <parameter index="1" type="String" optional="false">
    <parameter index="2" type="Function" optional="false">
    <parameter index="3" type="Boolean" optional="true">
  </parameter>
  <accessor name="firstName" access="readwrite" type="String" declaredby="com.thanksmister::Contact">
    <metadata name="Bindable">
      <arg key="event" value="propertyChange">
    </arg>
  </metadata>
  <method name="addEventListener" declaredby="com.thanksmister::Contact" returntype="void">
    <parameter index="1" type="String" optional="false">
    <parameter index="2" type="Function" optional="false">
    <parameter index="3" type="Boolean" optional="true">
    <parameter index="4" type="int" optional="true">
    <parameter index="5" type="Boolean" optional="true">
  </parameter>
</parameter>

We are interested in the name property of accessor node, and we store those names in an XMLList called "properties". This XMLList will be used later to assign the values of the Contact properties within the serializeContacts function. So this gives us a legitimate Contact value objects stored in the ArrayCollection, which we can then use in our application without any errors or null values.

Here is the complete sample application code that can be copied and used in an AIR application:

Main.mxml:

<mx:windowedapplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="435" height="277">
    <mx:script>
        <!--[CDATA[
            import mx.collections.ArrayCollection;
            import com.thanksmister.Contact;
            import flash.utils.describeType;
            import flash.utils.ByteArray;
           
            private function storeContacts():void
            {
                var contact:Contact = new Contact( "Michael", "Ritchie", "555-555-5555" );
              var ac:ArrayCollection = new ArrayCollection();
                ac.addItem(contact);
               
              var bytes:ByteArray = new ByteArray();
              bytes.writeObject( ac );
              
                EncryptedLocalStore.setItem( "contacts", bytes );
               
                outPutText.text = ("Contact Stored\n");
            }
           
            private function retrieveContacts():void
            {
                // retrieve AC from ELS
                var bytes:ByteArray = EncryptedLocalStore.getItem( "contacts" );
                var collection:ArrayCollection = bytes.readObject() as ArrayCollection;
                    collection = serializeContacts(Contact, collection);
                
                // trace our collection value
                outPutText.text = ("First Name: " + Contact(collection.getItemAt(0)).firstName) + "\n";
                outPutText.text = ("Last Name: " + Contact(collection.getItemAt(0)).lastName) + "\n";
                outPutText.text = ("Phone: " + Contact(collection.getItemAt(0)).phoneNumber) + "\n";
            }
           
            private function serializeContacts(valueObject:Class, arryCollection:ArrayCollection):ArrayCollection
            {
                 // use the the flash.utils.describeType to create an XML of the property names within the object
                 var xml:XML = describeType(new valueObject());
                 trace(xml.toString());
                 var properties:XMLList = xml..accessor.@name;
                 var tempac:ArrayCollection = new ArrayCollection();
                
                 // iterate through the collection passed into the function and reassign the types to it's objects
                 for each (var object:Object in arryCollection) {
                      var tempvo:Object = new valueObject();
                       for each(var name:Object in properties) {
                            tempvo[name]-->
    </mx:script>
    <mx:hbox width="300" x="10" y="10">
        <mx:button label="Store Contacts" click="storeContacts()">
        <mx:button label="Retrieve Contants" click="retrieveContacts()">
    </mx:button>
    <mx:textarea id="outPutText" width="400" height="200" x="10" y="40">
</mx:textarea>

Now we can store and retrieve ArrayCollections from the EncryptedLocalStore without dealing with the hosed object in our application. Many thanks to Daniel Dura and Mihai Corlan who helped tackle this problem in their contributions to the community. Sweet!

-Mister

Reblog this post [with Zemanta]

Cairngorm Plugin for Flex

Posted on the December 1st, 2008 under Cairngorm by Mister

If you are a heavy user or closet fan of Cairngorm (like me) then you would be interested in knowing that there is a new Cairngorm plug-in out from Adobe that generates some of the Cairngorm code automatically from Flex Builder 3. Also read some of the notes that Brian Deitte wrote after attending the Adobe MAX session "RIA Development with Cairngorm: Tips from the Experts" which I unfortunately did not attend. Brian will also be on the newly formed Cairngorm Committee which will guide the future of Cairngorm

Cairngorm Plugin

Just one small problem I ran into when installing the plugin, I received the following error:

Cairngorm Plugin (0.0.6.200811131413) requires plug-in "org.eclipse.emf.codegen".

To resolve this, I selected the Europa Discovery Site from the wizard along with the Caingrom plugin option created by following the installation instructions. I then used the "Select Required" button to install the needed eclipse plugins for codegen that are required by the Cairngorm plug-in. This installs the EMF (Eclipse Modeling Framework).

-Mister

Reblog this post [with Zemanta]

Drop your framework?

Posted on the November 20th, 2008 under Cairngorm, Flex by Mister

After attending an interesting session at Adobe MAX 2008 titled "The Flex Architecture Face-off". At first I though the speakers (Yakov Fain, Chafic Kazoun, Todd Anderson, and Joshua Noble) were going to debate which framework was the best, you know, Cairngorm, PureMVC, Mate, and others. Initially the speaker surveyed which frameworks developers were using and not surprisingly, most were using Cairngorm (followed by PureMVC, then Mate). Then the speaker asked who wasn't using a framework at all, and I was again surprised to see that about half of the audience wasn't using any framework. You see I come from the thought that you need to have a framework in your box of tools to build most projects, they help coordinate group efforts, and they offer support. I had always just assumed that most Flex developers would be using some type of framework and that the flavor of framework was the only point of contention.

What made this particular session interesting was how the discussion turned into a debate, not about one framework versus another, but a debate about if you want to use a framework at all. The panel was mostly split. Chafic and Yakov were obviously not for using frameworks, while Todd and Joshua recommended using frameworks. The reason for using a framework varied. Some developers use them because it helps to coordinate the work when you have groups of developers, others use them because the client had stipulated that it was a "best" practice to have a framework. This make sense because you know that even though projects have a development life cycle, they will also have a maintenance life cycle. This means that the next group of developers coming in after you will need to go through your code and using a framework seems to facilitate this process.

This has my view since I started Flex. I enjoy using frameworks, even though some require extra work and setup, it just makes things easier to work in a group or hand off your work to others. It just feels comfortable to me, safe I would say. I would typically use Cairngorm for most application development, small and large because I am familiar with this framework and its widely used. If someone told me they were not using a framework, or I had to pick up code that was written without one from other developers, I would most likely cringe because that would require me to learn their way of doing things. This was also a big part of the debate, how to deal with handing projects off to others or working in groups if you don't have a framework handy.

I remained skeptical and listened to how Chafic and Yakov explained how they handled these issues without using a framework. What may seem obvious, but might be overlooked, is that Flex is already itself a framework and most of the micro-architectures build upon the Flex framework using patterns (Mediator, Proxy, Command, etc.) and the built-in event dispatch system. If you know what you are doing with patterns and can build loosely coupled components, you can get by with out using a framework in your Flex application. You would essentially be building black boxes (components, modules) that know nothing about other components of the application. Communication would still take place through event dispatchers and listeners. You can also use a pattern to build communication for server communication and data retrieval. This is so reminiscent of my early Flash development days, when we didn't really have a framework to build upon and we sort of invented our own communication system, mostly creating components with publicly exposed properties and methods.

Another argument for not using a framework, or perhaps a complaint about them, is that they require a lot of extra work and code setup time without really allowing any benefits for the developer. They are also traditionally hard to learn (some more than others). For example, Yakov said he didn't like Cairngorm that much until he learned PureMVC (which he liked much less). I had the same feeling about PureMVC, it really feels like a heavy burden to create proxy and mediators over and over again, making all those delegates/commands much easier to create in Cairngorm. This made me think a bit about why I use a framework and what it might be like to not use one. I have done this on smaller applications where you might communicate with compiled SWC file that wraps an API like Flickr or Yahoo Maps, but I often try to put them into proper place within PureMVC or Cairngorm because I didn't want them in my views.

I still get that feeling that when I don't use a framework, I am somehow not being a responsible developer. When I started doing Flex, I really wanted to use patterns and best practices, using Cairngorm makes me feel like I am following some agreed upon conventions for building Flex applications. Not using one really makes me feel that the next person that looks at my code will be like "WTF is this spaghetti code?". You know that developers often back bite the previous developers when they pick up a project. Cairngorm at least gives you some feeling that I am using standards that can be picked up by other developers. This is especially true when you want to train new developers or work with groups of people.

However, I think there is some value to building Flex applications without using a framework. I was persuaded by the methods Yakov and Chafik's mentioned for developing without a micro-architecture framework and the small gleam of freedom that shined in their eyes when they said they don't use one. Your development group can use an agreed upon convention for modular development and communication between components. Each person can build a smaller component that exposes public methods and broadcast events that other interested components can subscribe to. Also, rather than using a delegate/command to handle your business logic, you can create or wrapper API's that handles the data calls and broadcast the events, much like adding the Flickr SWC file to your project. Some value for not using a framework might also come when you have to build an application or prototype fast, such as done within Agile Software Development. Jesse Warden just published a three-part series about his experience doing agile development and mentions how frameworks fit into this style. For more info, check out his Agile Chronicles series.

Abandoning your framework probably works best within small groups of developers that know each other and are confident in Flex. If you are not working in such a group or you are concerned that your own methodologies for Flex might not easily support maintenance after you are gone, its probably best to use a framework. The session ended up being more a question of using a framework at all, rather than debating which one is the best or most popular. What I would like to see is some examples by Yakov and Chafic on best practices for developing Flex applications in a group when not using a framework. I think its may be the way I go for my next personal project, but a few pointers would be great.

So, do any of you have an opinion about using a framework or not? Best practices applied when not using a framework? Examples? I would love to hear them.

UPDATE:

I found another discussion about this topic from the FlexWizz blog article titled "Why I hate MVC".

Todd Anderson also posted some of his thoughts about the panel discussion at MAX.

InsideRIA posted a complete review of frameworks with examples. They also ask "why use a framework at all?"

- Mr

Reblog this post [with Zemanta]

Headed to Max!

Posted on the November 10th, 2008 under Flex News by Mister

Prepared to head off to Adobe MAX 2008. This will be my 4 or 5th time going, can't recall all of them. I signed up for lots of advanced Flex and AIR courses, should be pretty good learning experience. I especially enjoy seeing some of the problems others in the field are working on and the unique solutions they demonstrate at MAX. I am also hoping to win a free copy of the new Adobe Creative Suite.

See you all there!

-Mr

Xdrive closes it’s doors

Posted on the November 6th, 2008 under Flex News by Mister

My recent employer just released a service announcement that they are closing their doors December 31st 2008. What this means now is that all the applications I helped development for the past 2 years will vanish into the ether, poof! This is very sad indeed as I spent a good amount of time this year working on some software updates that will never see the light of day and all the exiting lines of code will gather dust.

Xdrive Desktop Lite was just presented last year at Adobe MAX 2007 and was selected this year as a semi-finalist in the Adobe MAX 2008 awards. I also released an ActionScript 3 library wrapper for the Open Xdrive JSON API, which will also be defunct after the end of the year. I feel a little loss from this news, but I am also looking for what comes ahead.

Good bye Xdrive my old friend... hello new Flex opportunities!

-Mister

T-Mobile G1 Arrives (Android)

Posted on the October 20th, 2008 under Android by Mister

Just received my new T-Mobile G1. I think it arrived a little bit ahead of the estimated arrival date. Just took a couple of photos and now trying to figure out all the goodies of the phone.

Size of G1 compared to my T-Mobile Dash:

T-Mobile G1 compared to Dash

Thinks I like about Android:

1. Copy and Paste text, finally (take that iPhone)
2. Crazy amount of cool location aware applications being built
3. Great support for Google gmail, browser, and maps

Things not so keen on:

1. Hard to answer phone when phone locked
2. No on screen keyboard, pain to slide out keyboard all the time
3. Signal strength of 3G network is not as good in my areal
4. No native Google application to handle Google Docs
5. Phone is a bit bulky in the pocket
6. No good case for the phone, unlike iPhone

- Mr

New things to come

Posted on the October 17th, 2008 under Flex News by Mister

Yesterday was my last day of work at a full-time gig. I now find myself looking for new opportunities for the first time in almost two years. I moved to Los Angeles back in November of 2006 with high hopes to create great Flex applications, expand my knowledge and become more connected to the Flex community. Well, I did create some pretty cool applications and gained a ton of application experience with both Flex and AIR. I event had opportunities to connect to the Flex community by speaking at FITC Hollywood and Adobe MAX. I even had the opportunity to be part of the prerelease programs for Adobe Flex and AIR, and connected with some great people along the way. Is there more to do, yes. Is there more to learn, yes.

Though I didn't know it at the time, moving to Los Angeles also changed my personal life and many of the goals I had initially laid out. Was it an overall positive move, maybe. I didn't get as far as I truly wanted with the community connections. I had hoped our corporation would sponsor 360Flex and other community events. Things change at big companies in ways that are not always what you want, and you just sort of have to suck it up. Not unlike the changes in your personal life.

I am looking forward now to new opportunities. I learned that working for the "man" in a large corporations on a permanent basis is definitely not what I want. I want to experience a variety of development opportunities with Flex and AIR. I want to do more consulting and test the contracting waters for a while. I now have direction and new hope for controlling more of my own future. I love to create, Flex and AIR are both my canvas and my paint for creating. I am looking forward to making some great things in the year to come and looking forward to changes to come.

I am fortunate of one thing, working with Flex and AIR have given me choices and opportunities that other development areas may not have. Things might be tight with the economy, but our field is still rolling strong as more companies turn to this technology to deliver compelling applications. I hope our technology area is spared from the economic troubles ahead and development opportunities abound next year.

Here's to new beginnings and to always discovering more about yourself in everything you do.

-Mister

Secure login using the EncryptedLocalStore in Adobe AIR

Posted on the August 18th, 2008 under AIR, Flex by Mister

Adobe AIR has a quick and safe way to store encrypted user data when building applications. Data such as login and password can be persisted in the application using the EncryptedLocalStore available for AIR applications.

To demonstrate this, I wrote a quick demo application that will store username and password after users login. When the application is launched again, the same username and password will be retrieved from the EncryptedLocalStore and propagate the login and password text boxes. User's also have the option to reset the data and store a new username and password, removing the stored data from the EcryptedLocalStore.

This can be handy when you want your application to do auto-login, using the existing stored information from the user's previous session, and of course, the stored data is encrypted.

Example:

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
    width="410" height="260" creationComplete="initComponent()">
    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;
           
            private function initComponent():void
            {
                var password:ByteArray = EncryptedLocalStore.getItem("password");
                var username:ByteArray = EncryptedLocalStore.getItem("username");
               
                try{
                    if(password.length && username.length){
                        passwordInput.textpassword.readUTFBytes(password.length);
                        nameInput.text = username.readUTFBytes(username.length);
                    }
                } catch (e:Error){Alert.show(e.message);}
            }
           
            private function onLogin(event:Event):void
            {
                if(nameInput.text == "" || passwordInput.text == ""){
                Alert.show("Please enter username and password");
                    return;
                }
               
                try {
                    EncryptedLocalStore.reset();
                   
                    var bytes:ByteArray = new ByteArray();
                        bytes.writeUTFBytes(nameInput.text);
                       
                    EncryptedLocalStore.setItem("username", bytes);
                   
                        bytes = new ByteArray();
                        bytes.writeUTFBytes(passwordInput.text);
                       
                    EncryptedLocalStore.setItem("password", bytes);
                   
                    Alert.show("Writing username and password to local store.");
                   
                } catch(e:Error){Alert.show("Error writing store: " + e.message)}
            }
           
            private function onReset(event:Event):void
            {
                passwordInput.text = "";
                nameInput.text = "";
                nameInput.setFocus();
                EncryptedLocalStore.reset();
            }
           
            private function onKeyDown(event:KeyboardEvent):void
            {
                if ( event.charCode == Keyboard.ENTER) {
                    onLogin(null);
                }   
            }
        ]]>
    </mx:Script>
    <mx:Canvas width="380" height="240" horizontalCenter="0" verticalCenter="0">
        <mx:VBox verticalAlign="middle" horizontalAlign="left" verticalGap="0" horizontalCenter="0" bottom="142">
            <mx:Label id="userText" text="username"  creationComplete="nameInput.setFocus()"/>
            <mx:TextInput id="nameInput" creationComplete="{nameInput.setFocus()}" keyDown="onKeyDown(event)"/>
        </mx:VBox>
       
        <mx:VBox verticalAlign="middle" horizontalAlign="left" verticalGap="0" horizontalCenter="0" bottom="95">
            <mx:Label text="password"  />
            <mx:TextInput id="passwordInput" displayAsPassword="true" keyDown="onKeyDown(event)"/>
        </mx:VBox>
       
        <mx:ControlBar  bottom="16" width="161" height="35" horizontalCenter="0">
            <mx:Button id="submitButton" label="submit" click="onLogin(event)"  textAlign="center" />
            <mx:Button id="resetButton" label="reset" click="onReset(event)" textAlign="center"/>   
        </mx:ControlBar>
    </mx:Canvas>
</mx:WindowedApplication>

To use the example code, just create a new AIR application in Flex Builder and paste the code into your main MXML file.

-Mister

Detecting Local Drives with Adobe AIR

Posted on the August 6th, 2008 under AIR by Mister

Detecting a listing for local drives using Adobe AIR is fairly straight forward using the Adobe AIR File function getDirectoryListing for Mac or getRootDirectories for PC. The following code will get you a listing of the local drives for Mac or PC:

import flash.filesystem.File;
import flash.system.Capabilities;
 
private function getDrives():void
{
     var os:String = Capabilities.os.substr(0, 3).toLowerCase();
     var currentDrives:Array = (os=="mac") ? new File('/Volumes/').getDirectoryListing() : File.getRootDirectories() ;
     for each(var file:File in currentDrives){
         trace ("Drive: " + file.name + " Size: " + file.size);
     }
}

However, what I wanted to do was automatically refresh the the drive listing on a set time interval so I could detect newly added or removed drives. Here is a sample for that:

import flash.events.TimerEvent;
import flash.filesystem.File;
import flash.system.Capabilities;
import flash.utils.Timer;

private function setDriveWatcher():void
{
     var timer:Timer = new Timer( 2000 );
     timer.addEventListener( TimerEvent.TIMER, timerHandler );
     timer.start();
}

private function timerHandler(event : TimerEvent):void
{
     var os:String = Capabilities.os.substr(0, 3).toLowerCase();
     var currentDrives:Array = (os=="mac") ? new File('/Volumes/').getDirectoryListing() : File.getRootDirectories() ;
      for each(var file:File in currentDrives){
         trace ("Drive: " + file.name + " Size: " + file.size);
     }
}

Everything seems to work great on my Mac, but when I tested the application on my PC I heard a strange constant grinding noise coming from the A: drive, you know, that dinosaur floppy drive you probably forgot your PC had. It seems that when AIR gets a listing of all the local drives on the user machine, it pings the A: drive which causes it to make the noise. Remember when you try to access a PC floppy drive when it was empty it makes a lovely grinding noise that sounds like the drive is eating itself.

I suspect this issue arises because I am doing something with the directory detection feature of AIR that was not intended by Adobe, that is to repeatedly get listings of all local drives. However, I am trying to make a hack for a feature that Adobe probably should have included with AIR, automatically detecting drives being added and removed from the users machine. This is the issue that probably needs to be addressed by Adobe. I could not find any way to just skip certain drives, like the A: drive to avoid this issue either.

This issue does not happen on all PC's with floppy drives, just a handful that I have tested. It seems to be less of a problem when users have an actual floppy in the drive, but its not a total solution. It's slightly annoying to auto-detect the adding or removing of drives, so I recommend making a manual drive refresh option for users, something they can click one whenever they add or remove an external drive. Now, if I can only get AIR to recognize the type of drives automatically, like the difference between a hard drive, usb drive, and my camera, that would be nice.

-Mr

-->

View Michael Ritchie's profile on LinkedIn