Archive for the 'flex' Category

Flex2 (and 3) RemoteObjects over SSL with ColdFusion

I just deployed a Flex app to an SSL secured host, and ran into some issues getting AMF over SSL working.  Googling turned up the answers, but in rather fragmented form.  So I'm coalescing them here.  In a nutshell, you have to create a new channel (my-secure-amf) that uses the secured versions of the AMF classes (both AS and Java), and then register it as a usable channel for the ColdFusion destination.  Here's a diff from my services-config.xml (in /WEB-INF/flex) with the four important bits bolded:

--- services-config.xml 2007-09-01 00:37:25.000000000 -0700
+++ services-config.xml 2007-09-01 00:59:41.000000000 -0700
@@ -13,6 +13,7 @@
             <destination id="ColdFusion">
                 <channels>
                     <channel ref="my-cfamf"/>
+                    <channel ref="my-secure-cfamf"/>
                 </channels>
                 <properties>
                     <source>*</source>
@@ -48,6 +49,15 @@
                 </serialization>
             </properties>
         </channel-definition>
+        <channel-definition id="my-secure-cfamf" class="mx.messaging.channels.SecureAMFChannel">
+            <endpoint uri="https://{server.name}:{server.port}{context.root}/flex2gateway/" class="flex.messaging.endpoints.SecureAMFEndpoint"/>
+            <properties>
+                <polling-enabled>false</polling-enabled>
+                <serialization>
+                    <instantiate-types>false</instantiate-types>
+                </serialization>
+            </properties>
+        </channel-definition>
     </channels>

     <logging>

In addition to this server-side config, you need to ensure your client connects to the proper channel and with the proper Channel (the AS class) implementation.  If you're using services-config.xml in your compilation process, it's a no brainer, but if you're manually configuring your ChannelSet in code (parameterized, of course), you have to watch out.  If you want to do the latter, here's how I do it:

private function configRemoteObject(gateway:String, cfc:String, useSsl:Boolean):RemoteObject {
  var cs:ChannelSet = new ChannelSet();
  if (useSsl) {
    cs.addChannel(new SecureAMFChannel("my-secure-cfamf", gateway));
  } else {
    cs.addChannel(new AMFChannel("my-cfamf", gateway));
  }
  var ro:RemoteObject = new RemoteObject();
  ro.destination = "ColdFusion";
  ro.channelSet = cs;
  ro.source = cfc;
  ro.addEventListener(ResultEvent.RESULT, function(event:ResultEvent):void {
    if (event.token.hasOwnProperty("resultHandler")) {
      event.token.resultHandler(event);
    } else {
      trace("result event with no resultHandler: " + event);
    }
  });
  ro.addEventListener(FaultEvent.FAULT, function(event:FaultEvent):void {
    if (event.token.hasOwnProperty("faultHandler")) {
      event.token.faultHandler(event);
    } else {
      trace("FaultEvent: " + event.fault.message);
    }
  });
  return ro;
}

The three arguments to the method are pulled in via a URLLoader to an XML file such as the one below that is part of the deployment configuration (i.e. not part of the codebase).

<?xml version="1.0" encoding="utf-8"?>
<settings>
  <gateway>/flex2gateway/</gateway>
  <useSsl>false</useSsl>
  <cfc>sorter.cfcs.count_facade</cfc>
</settings>

I don't claim that this is the best way, but it does let you easily change where your SWF connects to without recompilation, which therefore lets you build your Flex projects standalone (no compile-time server linkage).  Quite useful if you have a variety of environments you want a single project/SWF to work in.

Flex3 Apache Module glibc Gotcha

I went to install the Flex3 Apache compiler module on my server today, and it supports glibc 2.4 and higher only, which means no RedHat 4 (or derivatives).  So no Flex server compilation for me, since there doesn't seem to be source anywhere to compile against glibc 2.3.

Skinning Sliders Flex

I've been working with a custom Slider extension (which selects a range of elements from a dataProvider, rather than numerics, plus a couple other little things), and got to skinning it this afternoon.  One of the design specs required different images for the two sliders, both pointing towards each other (i.e. mirror images of each other).  Obviously you can't do that with the single 'thumbSkin' style on Slider, so more digging was needed.

A quick look at the API docs shows that SliderThumb extends Button, and therefore inherits it's 'skin' style.  Except that you can't use it; it gets silently ignored.  After some digging around inside the Slider source, I found that the style names get realiased to be their "proper" names, with a 'thumb' prefix, so you actually need to use 'thumbSkin', just like you do on the Slider control itself.  It seems that instead of replicating the style attribute from the Slider to the SliderThumbs (using appropriate names), the whole Slider style definition is copied into the SliderThumbs.  I'd expect this [strange] behaviour to be the same for other auto-created elements (headers in DataGrids, etc.) as well, so watch out, because there is no documentation except digging through the framework source.

Bicycle Dashboard Again

Another relatively minor change: the charts now use a DateTimeAxis instead of a category axis.  This way temporal spacing is preserved, rather than just ordering, and the axis isn't as cluttered, because it can drop labels without affecting the display semantics.

More Bicycle Dashboard Updates

I just pushed a couple usability tweaks to the bicycle dashboard app.  First, the profile you're viewing is now persisted in a cookie, as well as session, when you return to the app, you'll still be viewing the same thing, even if your session expired.  Before you'd always revert back to me, and while I'm ridiculously good looking, there isn't a picture of me in the app, so all you get to see is my boring numbers.

Second, I resorted the ride listing so that by default the most recent ride is at the top.  That's what I'd intended from the beginning, but it didn't work, and I hadn't taken the time to figure out why until now.  Turns out that my reference maintenance code reorders stuff when new data is pulled in and it does the state substitution on existing entities.  It uses a couple Dictionary objects as lookups for the substitutions, and they don't maintain insertion ordering (and why should they?), and I didn't consider the ramifications.  But that's fixed now, and also means that the bike selector when adding a new ride will work "correctly" in that it'll automatically select the bike you've ridden most recently, rather than the one your rode first.

Flash 9.0.48 for Linux

Adobe has released Flash Player 9.0.48 for Linux, and my bicycle dashboard seems to work now, which is good news, since that app was undoubtedly not the only one affected.  If you're on Linux, go get it!

Bicycle Dashboard Update

I made some mods to my bicycle reporting dashboard last night and just pushed them live.  Highlights include being able to break down the charts by bike, route, or day of week, legends to support showing multiple series, control over the chart baseline (zero or autodetect), and formatting of the "elapsed time" axis labels.

Now that that's working right, multiuser is next on the list, and I'll probably throw a "route link" field in there as well so you can link to a map of your route if you have one.

Fun with Flash on Linux

So I got home this evening and wanted to record my commute with my new logger app, and guess what, it crashes Firefox. Roughly one-in-four loads of the app are successful, other attempts cause a segfault as the player tries to load the SWF. It seems to work better in SeaMonkey, but still not perfect. I know Linux is the "we don't really care" platform for Adobe (and Macromedia before), but I'd almost prefer no player at all to a crashy one. Anyone have any hints?

Bicycle Goodies (i.e. Info Porn)

While on my seemingly endless airplane rides, I finished up a first draft of my bicycle reporting app, and made it available at the seemingly random address of http://www.barneyb.com/bicycle/.  ; )  Yes, it's Flex, and yes, I chose that platform of my own volition.  It's still a little rough around the edges, but it's all functional, and I used it to record this morning's ride.  Much better than using the command line MySQL client.  Of primary interest is the graphs of the stats.  I haven't gotten very far into them yet (was having some issues - surprise - getting the charts to work right for the more complex cases), but they're there, and the average speed one has a positive slope (yah me!).

There's a couple "weird" characteristics to the UI, but they have sound backing.  First, the entire UI is modal-free excepting the login form.  I didn't want to be stuck editing something and realize that I hadn't created some related entity and have to cancel out to create it.  I also wanted to be able to view the listings while adding/editing entities, so all the forms show up in tabs along with the listings so you can easily switch back and forth.

Second, the whole UI is publicly available.  I didn't want to build a separate admin area, so the editing UI doubles as the detail view UI.  The "Save" buttons are disabled unless you're logged in, and that's backed up on the server-side, of course.

Last, while not easily apparent, is the security of the authentication without using SSL.  Part of the AS3 Core Lib is MD5 hashing capabilities, so when the password is entered client-side, it gets hashed before sending to the server.  This provided a nice solution to password transmission that didn't require an outward facing self-signed SSL certificate (which isn't very friendly) but also doesn't compromise passwords.

Once I get stuff a little cleaner, I'll post source.  I'm also thinking of making it multi-user, but there are some weird issues (like handling public browsing) that would need to be dealt with.  Time will tell what becomes of it.

I also added contextual ride history to the single-entry pages on my blog.  I'd added it to the listing pages a while ago, but realized that a large percentage of my audience reads my blog via the XML feeds, so they never see the listing pages.  So rides within 24 hours of a given entry will now show up on the single-entry pages.

Another Flex Weirdness/Gotcha

Another little gotcha to watch out for with Flex.  If you have an ArrayCollection of Objects that are backing a DataGrid, you can add/remove objects from the ArrayCollection and the DataGrid will update.  However, updating properties on the objects doesn't seem to update the DataGrid until you force a redraw via some other means (e.g. resorting the rows).  In my particular case, the Objects in question were non-dynamic instances of a custom class that are [Bindable] at the class level.

This was unexpected to me, but on further reflection seemed quite explicable (though not necessarily reasonable).  It seems that individual DataGrid cells ought to be bound to the property they're fronting, rather than only the rows being bound to the Objects.  But with the way the internals of DataGrid work, the property selection is dynamic (using [] notation), which is unbindable directly.  You can avoid it with a bindable function, of course, but it seems DataGrid (at least in Flex 2.0.1) doesn't do that.

I'll probably dig into this some more (since I really don't want to have a zillion executeBindings() calls all over the app).  If anyone has any insight into this behaviour, I'd be quite interested to hear it.