Spiking Greedy SWFs

A project we're working on requires third parties to be able to load SWFs of their own design into an overall "shell" that we're building. So far, so good - particularly with the new unloadAndStop method that's part of Flash Player 10. That means I can fully unload the SWFs no matter where they managed to sink their teeth/event listeners.

Then I started to think about a weird edge case... what if the creators of these SWFs accidentally does something spectacularly bad like get stuck in an infinite loop? I had a few ideas for a solution, and so I decided to spike them and see if any of them worked (The link explains what spiking is - but in a nutshell it's a quick-and-dirty end-to-end solution that tests out an idea).

To test my solutions I made two SWFs - one with a simple spinning animation (spinner.swf) and another that, with the push of a button, would lock up for 5 seconds (greedy.swf). My first idea was to put the SWFs on the same HTML page and have them talk via LocalConnection. The spinner would monitor the greedy SWF (when ever the greedy one started, it would tell the spinner) and if the greedy SWF went on too long the spinner would talk back out to Javascript and tell it to replace the Flash Player instance.

That didn't work in the slightest.

As soon as the greedy SWF started getting greedy, the spinner would lock up too. I even tried putting the SWFs in separate HTML files and loading in one via an iframe - same result.

The next solution was to have Javascript do the monitoring. So now the greedy SWF would call out to Javascript before it started getting greedy and the Javascript would then start a timer. If that timer wasn't reset by the greedy SWF finishing it would unload the Flash Player running the greedy SWF. Pretty decent idea, yeah? Nope.

It seems like (at least in the browsers I tested, Safari and Firefox), when Flash is locked up the rest of the browser, including JS is locked up too. The timer would only first AFTER the greedy SWF stopped on it's own accord.

So where does that bring us? Well, these solutions or something like that may work in IE, particularly since it's running on a whole different plugin architecture. It may also work in Chrome since it's whole architecture is based on isolating processes. That being said, a real cross-browser solution remains elusive. I guess I'll just have to hope the 3rd party SWFs don't suck and maybe do a bit of testing on them before I roll them out to the public.

LAFlashapaloozastock III

Branden will both be speaking at the free Flash conference LAFlashapaloozastock III in Venice Beach, CA on December 6, 2008.

To help keep the event free Branden will also be teaching a very cool course of his own titled "Creating Killer ActionScript Robots For Fun & Profit" on December 4th and 5th. It's going to be a two day romp through ActionScript 3 learning advanced programming techniques in order to make software robots with which the students will do battle! The course is $499 per student. If you're interested click the course title to find out more.

SOAP is Just XML

Recently, Branden and I were tasked to build a Flash UI on top of a web service.  Seems like pretty standard development...but, as you have to know by now, nothing is ever "standard" at Automata.  After some research, trial & error, and hand-wringing, we realized that the device we were attempting to connect to was using SOAP 1.2.  Well, unfortunately, Flex only supports up to SOAP 1.1, so we had a bit of a problem.

It didn't take us long to remember that SOAP was just XML, and that Flex's web service API was just a nice class that makes it easy to speak that language.  After deciding to nix the Flex solution (we were only using Flex for the WebService API), we moved to an all Flash solution.  We created a connector class to act as a web service API, and simply sent XML packets directly to the server using URLLoader.  One note about this solution is that it will only work if you have knowledge of the web service you are trying to use.  In our case, we had the entire schema at our disposal, so we knew the exact format of the service operations.

The connector class contains public methods to call the individual web service operations.  Additionally, we created individual request classes for each of the operations that extended a class called Abstract Request.  AbstractRequest provides a method send(uri:String, headers:Array) that uses URLLoader to send the request to the server.

The "uri" parameter of send() is the full path to the web service, with the "http://" attached.  The headers are the HTTP headers that you need to send to the web service for such things as authentication.  In our code, these are set in the Connector class, and passed to each request as it is needed.  The "_request" property holds the XML object that you will pass to the server.  This XML is formatted as an XML packet specific for this web service.  The value for this property is defined in the AbstractRequest sub-classes.

The _request property is an XML object that defines the format, and uses Flex-style binding to add the actual data from the constructor parameters.  This is a little-known XML trick you can do in AS3.  Branden found it in the Help section of the Flash CS3 IDE.  Pretty neat if you ask me.

Back to the AbstractRequest class, we simply set the data property of the URLRequest intstance to be the string representaton of the request XML, and call URLLoader.load(), passing in the URLRequest instance.  This sends the XML packet to the server.  The handler for Event.COMPLETE will receive the XML returned from the server.

Our connector class has methods like:

public function addGroup(groupId:String, groupName:String, flag:String):void {

var request:AddGroupRequest = new AddGroupRequest(groupId, groupName, flag);

request.addEventListener(ISYResultEvent.EVENT, onResult);

request.addEventListener(ISYFaultEvent.EVENT, onFault);

request.send(_uri, _headers);

}

This actually executes the web service call.

And just like that, you've build your own web service class.  While it's quite specific to the web service you are using, you could certainly expand it to consume a WSDL file so you can use it for any web service.