views:

2234

answers:

4

I'm thinking of choosing Adobe AIR as the client-side implementation technology for an upcoming project. (The previous choice was C# and WPF, but I've been really impressed with Flash/Flex/AIR lately.)

But one of the most important features of my product will be its plugin architecture, allowing third party developers to extend the functionality and GUI in interesting ways.

I know how I'd design the architecture in C#: A plug-in loader would enumerate all of the assemblies in the local "app/plugins/" directory. For each assembly, it'd enumerate all of the classes, looking for implementations of the "IPluginFactory" interface. For each plugin created by the factory, I'd ask it for its MVC classes, and snap its GUI elements (menu items, panels, etc) into the appropriate slots in the existing GUI layout.

I'd like to accomplish the same thing within AIR (loading plugins from the local filesystem, not from the web). After reading this article, my understanding is that it's possible, and that the basic architecture (loading SWFs into sandboxed ApplicationDomains, etc) is very similar to the way you'd do it in .NET.

But I'm curious about the gotchas.

If any of you have done any dynamic classloading with the flash player (preferably in mixed flash/flex apps, and ESPECIALLY within the AIR host), I'd love to hear about your experiences building your plugin framework and where you ran into tricky situations with the flash player, and with the flash, flex, and AIR APIs.

For example, if someone asked me this same question, but with the Java platform in mind, I'd definitely mention that the JVM has no notion of "modules" or "assemblies". The highest level of aggregation is the "class", so it can be difficult to create organizational structures within a plugin system for managing large projects. I'd also talk about issues with multiple classloaders and how each maintains its own separate instance of a loaded class (with its own separate static vars).


Here are a few specific questions still unanswered for me:

1) The actionscript "Loader" class can load an SWF into an ApplicationDomain. But what exactly does that appdomain contain? Modules? Classes? How are MXML components represented? How do I find all of the classes that implement my plugin interface?

2) If you've loaded a plugin into a separate ApplicationDomain from the main application, is it substantially more complicated to call code from within that other appdomain? Are there any important limitations about the kinds of data that can pass through the inter-appdomain marshalling layer? Is marshalling prohibitively expensive?

3) Ideally, I'd like to develop the majority of my own main code as a plugin (with the main application being little more than a plugin-loading shell) and use the plugin architecture to hoist that functionality into the app. Does that strike fear in your heart?

+4  A: 
  1. The applicationDomain is more like a namespace, it groups class definitions and put them into a hierarchy: a domain can directly access the symbols in its own domain or in the parent domain, but not in child or sibling domains (or better: it can't do that directly - it must go through the applicationDomain object, asking the definition of a given class); when loading an external swf you can decide where to put the new symbols: a child domain (default), a new domain attached to the system (using null), the current domain, a domain attached somewhere else (explicitly passing the parent of the new domain). Note that new symbols will never overwrite symbols in the current domain, but the same name can exists in multiple domains.
    Unfortunately you cannot enumerate the classes in a given domain (well, at least I don't know any way to do it), but the common solution is to require (as in "The Plugin Interface") the presence of a well-known factory in each swf, which will return either the definition (Class) of the plugin or the plugin itself.
  2. You just have go get a reference to the object somehow (the factory), then it's just another object. There's no marshalling: the domain it's just a logical partitionning of the namespace (it's a tree branching of the system domain).
  3. No :) But be warned: it may easily turn into a hell for the GC, where unused domains cannot be unloaded due to references spread in other domain. I suggest taking a look at the multi-core PureMVC framework, possibly with pipes for ensuring a strict separation between the plugins.

Btw, Flash Player also a concept of security domain, but I actually never touched it, so I don't known what the possibilities are here.

Luca Tettamanti
+3  A: 

Luca Tettamanti gave good answers to your specific questions already, so I'll just offer some additional info on the general subject:

I've implemented a simple plugin API for a Flex app using the ModuleManager class (and the other stuff in the mx.modules package.) The gist of it is that you subclass plugins from ModuleBase and use ModuleManager in the host app to load them. Then you have the plugins implement a common interface (e.g. IMyAppPlugin) and use some sort of a facade to represent and implement the interface to the host application that the plugins can use (e.g. MyAppFacade implements IMyAppFacade.) Whenever plugins are loaded, inject this facade reference into them.

The topic "Modular applications overview" in the Flex 3 help has some good info (the subchapter "Module domains" discusses application domains in the context of modules.) Here's an excerpt:

"By default, a module is loaded into a child domain of the current application domain. You can specify a different application domain by using the applicationDomain property of the ModuleLoader class."

The topic "Using the ApplicationDomain class" goes into more depth on the subject of application domains, and you should definitely read it if you haven't already.

hasseg
Very nice. Is your plugin API open source?
benjismith
No, and even if it was, it's quite specific to the app it was written for. Everything that's "generic" about it is pretty much explained in the answer I wrote.
hasseg
Gotcha. I'll take a look at your links. (Only got started with flex last week, so I don't know much about flex Modules yet.) One more question, though... In a pluggable AIR app, I'd like users to be able to *install* plugins. Given AIR's standard installer, how would you recommend handling that?
benjismith
I was thinking about that myself... Unfortunately I'm not really an expert in AIR -- I've only dabbled in it. Sorry. :( Maybe you can implement the installation of plugins in the app UI yourself and use some path under File.applicationStorageDirectory as the location for installed plugins.
hasseg
Should check out the sub-application capability added in Flex SDK 3.2 - it is all about doing the things described in the question:http://livedocs.adobe.com/flex/3/loading_applications.pdfTo cut to the chase - use <mx:SWFLoader> for sub-application loading as it's enhanced for this functionality
RogerV
A: 

Responding to the statement regarding Java as a possible plug-in architecture:

It turns out Java has been used to devise plug-in architecture systems for many years. As to to client-side, the Equinox OSGi module management frameworks is probably the best well known. At one point the Eclipse IDE refactored their plug-in architecture on top of Equinox OSGi. Eclipse IDE is perhaps one of the most successful client-side plug-in architecture systems yet devised - from historical longevity point of view as well as breadth of user base and follow-on community of plug-in development. They also offer their plugin architecture as a foundational framework for devising arbitrary client-side applications - Eclipse RCP.

I just had to interject this because though Java was positioned as perhaps a very weak choice for this, it actually is far more successful than any other language/runtime environment to date in delivering working systems of this kind - especially vs. C# .NET, which, of course, has good innate facility for modules. Is kind of ironic, but there you have it.

As to Adobe AIR, I'm dev managing a project this is being devised on AIR. In our case our module extensibility is always going to be delivered from the web server - not a local directory. Flex has the

<mx:Module/>

tag for creating modules that can be loaded discreetly at runtime.

Alas, a frustration with AIR is its lack of any class APIs for launching other applications. You can load a URL to load something in the user's default browser, but you can't launch, say, Excel. Both Java and C# have APIs for launching other apps as external processes.

RogerV
A: 

Have you tried loading sub-applications ?
There is good documentation for doing this in AIR and I was successful with it in a few hours. However, the same implementation is a different story in Flex because of sandbox violation between sub-application and main application. I have spend weeks pounding my head into the wall.