You have a great application on your hands but you can’t load it up as a part of your brand-spanking-new application because they are not the same version.
Do you rewrite the old stuff? Or you downgrade the version of the app you are currently building? Both are very painful, and all you need to do to avoid the pain is to make the apps talk and coexist. This is a standard problem of any enterprise system, especially the ones with a long lifespan.
Flex framework addresses this problem with the Marshall Plan or at least it’s supposed to. Here at Pathfinder, when we were tasked with a complex multi-versioned enterprise system that had just such a problem. We gave Marshall Plan a try and in our experience we never got it to work entirely as intended. But we came up with a solution.
Background
To clue you in on the details, here we are, developing a Flex 4.1 SDK application so happy to use the new architecture that Adobe engineers came up with when we heard from our client that one (of many) of the modules needs to stay in version 3.5 because the framework it is using hasn’t been updated to Flex 4. ¡Ay, caramba!
Going from Modules to Sub Applications
We know that we can’t have Modules in a different version so we switched our logic to use Sub Applications instead. It is convinient to rely on ModuleManager to handle multiple instances of multiple Modules. We already had an Interface implemented for communication with Modules and the same one would be used for Sub Applications. These Modules also had a purpose of existing as independent apps so we scratched their wrappers, made them into apps and problem solved. We understood that sub apps are loaded into a different sandbox and that it will have consequences but we felt comfortable that we can work that out – priority was for the apps to “talk”.
Loading Sub Applications
We made sure that we went through document about loading sub applications before we began. This is a document that you can not do without when attempting to go multi-version.
First problem we encountered is that we were directed to do the following:
When compiling each of these types of applications, you should include the MarshallingSupport class into the main application and sub-applications. You do this with the includes compiler argument, as the following example shows:
-includes=mx.managers.systemClasses.MarshallingSupport
We discovered that inserting this compiler argument in an app prior to version 4 reliably returns the following error:
Unable to resolve a class for include: mx.managers.systemClasses:MarshallingSupport
That puts our sub application out of the game. We said, well let’s go ahead anyway, maybe they meant just the main app and not the sub too and we proceeded. Reason for such a bold decision is that we didn’t have any other option.
Even with that snag, loading a different version sub application turned out easy as pie thanks to SWFLoader in Flex 4 and its “loadForCompatibility” property. It worked on the first try.
Here is an example in AS3 (Flex 4.1 app):
private function loadSubApp():void
{
//swfLoader is declared outside
swfLoader = new SWFLoader();
swfLoader.name = "mySubApp";
//subAppContainer is a Canvas declared in MXML
subAppContainer.addChildAt(swfLoader,0);
swfLoader.trustContent = true;
swfLoader.loadForCompatibility = true;
//setting source triggers loading
swfLoader.source = "subApplication.swf";
swfLoader.addEventListener(Event.INIT, swfLoaded);
}Problem of accessing Sub Application
This is where all the trouble resides. We loaded the sub app into the main app and now we wanted to make a call to our interface method. We looked at the example from loading sub applications document on page 24 and found it misleading. Who the heck is “SubApp2″ and how will my main app know of that class or any dynamically loaded app anyway?
We also kept seeing this line of code around the net and in the examples:
(contentLoader.content as SystemManager).application
That’s how we’re supposed to access the sub app once it is CREATION_COMPLETED. We tried this with various combination of versions that gave different errors and we tried to cast it to SystemManager in various ways. We always got two possible results: null and an error of type “SystemManager can’t convert to SystemManager”. We understood that there might be a thousand reasons for this happening, starting with our MarshallingSupport include issue but we also understood that the darn thing loaded – we could see it in the display.
In the end we concluded that we are not Adobe engineers and we shouldn’t give that problem any more time. If it doesn’t work like it’s documented, we should not spend clients money figuring it out.
Access solution
We came up with our home brewed solution that is working very well. Solution is based on the fact that the sub application does load and exists in memory – therefore it must be accessible.
We decided to try out the good old vanilla approach which involves accessing properties of an typed object as if it was a plain Object. This is generally a bad practice and defeats the purpose of Object Oriented Programing but can sometimes come in quite handy. This is one of such rare instances.
To continue from the code example above, we listened to the Event.INIT just so we could add FlexEvent.APPLICATION_COMPLETE listener once the SWF is loaded:
private function swfLoaded(e:Event):void
{
swfLoader.removeEventListener(Event.INIT, swfLoaded);
swfLoader.content.addEventListener(FlexEvent.APPLICATION_COMPLETE, subAppCreationCompleteHandler );
}Once that happens we can acces our sub applications method using vanilla approach:
private function subAppCreationCompleteHandler(e:Event):void
{
swfLoader.content.removeEventListener(FlexEvent.APPLICATION_COMPLETE, subAppCreationCompleteHandler );
//subApplication is declared outside
subApplication = e.currentTarget as Object;
//Flex apps have an "application" object that represent the application instance
if( subApplication.hasOwnProperty("application") )
{
if (subApplication.application.hasOwnProperty("methodWeWantToCall") )
{
var f:Function = subApplication.application.methodWeWantToCall;
//Yes, we have to know upfront what are the parameters of the function
//but that is why we have the interface for
f( true );
}
else
{
Alert.show("Sub App doesn't have 'methodWeWantToCall'");
}
}
else
{
Alert.show("Loaded Sub App is not a Flex App");
}
}Method Parameter Gotcha
We have typed parameters that we were passing to the interface method into a custom value object back when we were working with Modules and packaged it in a SWC that everybody involved in the system was using.
After trying to pass the same custom VO to the sub app we started getting errors of the kind: “MyValueObject can’t convert to MyValueObject…”. We remembered that we read somewhere that we can only pass primitive objects to sub apps and we converted our VO to an XML that luckily is a primitive object in AS3. We also put the XML schema in the comments of our SWC to make sure there is little ambiguity. To add to that, you can find in documentation that any event dispatched by sub application can’t be casted but has to be retyped as well. Optionally you can access its parameters vanilla style too.
Home Brewed Cheat Sheet (main app: 4.1, sub app: 3.2+)
- You don’t need -includes=mx.managers.systemClasses.MarshallingSupport anywhere.
- Use loadForCompatibility and trustContent properties of SWFLoader.
- Make sure to listen to FlexEvent.CREATION_COMPLETE event on the sub app that you can only attach once the SWF has finished loading.
- Using hasOwnProperty method, check if application is available on your sub app and then check is your method available in the application.
- Create a new Function and pass it the reference to the sub apps method.
- Fire at will.
Conclusion
Creating a multi-versioned application was an exhausting experience. We were also very mad at Adobe at times for advertising multi-versioned apps while having a disarray in documentation. Body of knowledge for this topic is huge and variability of results is aggravating.
In the end the system works and we are satisfied with it’s stability. We are not crazy about vanilla access of objects or passing of primitives but we feel our assumptions are stable and we have enough error checks. Having said that and with bad feelings behind us, we are grateful to Adobe and Alex Harui for making multi-versioning even remotely possible. I can only imagine the multitude of considerations they had to make to make this an option. The philosophy behind their solution is a good study of the problem of managing evolving systems.

Are there any luck when the main app is in 3.5 and the sub app is in 4.5?
When I tried it, it gave the following error. trymodule is main app in 3.5, and mobileModule.swf is the sub app in 4.5. And also, I cannot set trustContent in the SWFLoader in main app, otherwise it crashes.
[SWF] C:\Users\m.yu\Adobe Flash Builder 4\trymodule\bin-debug\trymodule.swf – 660,038 bytes after decompression
[SWF] C:\Users\m.yu\Adobe Flash Builder 4\trymodule\bin-debug\modules\bin-release\mobileModule.swf – 143,727 bytes after decompression
init done
[SWF] C:\Users\m.yu\Adobe Flash Builder 4\trymodule\bin-debug\modules\bin-release\mobileModule.swf\[[DYNAMIC]]\1 – 671,219 bytes after decompression
[SWF] C:\Users\m.yu\Adobe Flash Builder 4\trymodule\bin-debug\modules\bin-release\mobileModule.swf\[[DYNAMIC]]\2 – 381,334 bytes after decompression
Warning: Ignoring ‘secure’ attribute in policy file from http://fpdownload.adobe.com/pub/swz/crossdomain.xml. The ‘secure’ attribute is only permitted in HTTPS and socket policy files. See http://www.adobe.com/go/strict_policy_files for details.
[SWF] C:\Users\m.yu\Adobe Flash Builder 4\trymodule\bin-debug\modules\bin-release\mobileModule.swf\[[DYNAMIC]]\3 – 1,113,279 bytes after decompression
rocksoccer,
I have never tried to have a lower version as the parent app but I have not seen anything that says that it is imposible.
Looking at your stack, the crossdomain.xml looks most fishy. I see that’s in the old format and that might be giving you trouble with trustContent.
Do read the article in the link from the error: http://www.adobe.com/go/strict_policy_files
In a nutshell, this is the standing crossdomain.xml format (ex. allows full access):
I do remember that trustContent is critical for success.