Going back to the original topic of this thread...
They have folded in the PureMVC codebase and made numerous changes/ommissions to meet their ends.
They are of course, free to do so under the creative commons license. I cannot speak to the extent to which PureMVC is used or to its role within Prana. So while I can't 'endorse it' per se, I certainly can't say anything bad about it. I understand the focus is to bring about a configuration-driven 'IOC' framework.
I would be interested to hear the results of any thoughts you may have if you do work with it.
-=Cliff>
I'm pretty active with the Prana community, and although I wasn't the developer who did the bulk of the PureMVC integration to it, I have done my part to help improve it to make it easier to use and more inline with the PureMVC way of doing things.
Prana's aim is to be a top-notch IoC container for Actionscript (the primary focus originally was flex, but with recent code changes it has no flex dependencies). Most of its architecture cues come from the Spring framework - in particular the xml driven configuration file has almost identical syntax to the Spring xml files, so developers familiar with Spring will be able to easily pick up Prana.
I wont try to sell anyone on IoC - like any pattern it has benefits and drawbacks and it is not the right solution for every case.
The pieces of Prana that are probably of most interest to the PureMVC community is the initial groundwork that has been put in place to attempt to make it easy use IoC and PureMVC together.
To clarify some of what Cliff said - there are pieces of code in the Prana that are folded-in from PureMVC, but most pieces modify by extension rather than at the source level. To make it clear when you are using classes and interfaces of the Prana versions of the PureMVC classes and interfaces, they are prefixed with IoC in the case of a class, or IIoC in the case of an interface. (I.e. IFacade is IIocFacade, Facade is IoCFacade).
The biggest development difference between coding to an IoC container and coding in PureMVC by itself is that dependencies are injected by the container, rather than retrieved from the facade. For instance, in an application I am developing now I have a mediator that collaborates with a certain Proxy. Rather than retrieve the proxy from the Facade - which I still COULD do if I wanted to - I am simply injecting the proxy into the mediator at creation time.
Here is a simple example of configuring a mediator in Prana.
<object id="specialistSelectionScreenMediatorInstance" class="com.xyz.view.mediator.SpecialistSelectionScreenMediator" lazy-init="true">
<property name="specialistCategoryProxy" ref="specialistCategoryProxyInstance" />
</object>
(One notable dependency - the actual UI component - isn't being injected here. I have a viewPrep command that I run at startup that does that work for me. View component injection is kind of a pain since you have to do a lot more legwork to handle the creation lifecycle... It's possible, if you need to do it, but for now I just did it this way.)
Earlier in the same file, the specialistCategoryProxyInstance is created and configured to have a concrete delegate class injected into it:
<object id="specialistCategoryProxyInstance" class="com.xyz.model.proxy.SpecialistCategoryProxy" >
<property name="categoryLoadingDelegate" ref="specialistCategoryDelegateInstance"/>
</object>
The delegate instance that is injected into it for now is one that I have merely generating and returning test data:
<object id="loginDelegateInstance" class="com.xyz.model.business.impl.TestDataProvidingLoginCredentialsDelegate" />
(edit: adding in this last sample piece of code)
As I mentioned above, the mediator example isn't complete until it is registered. I have my viewPrep command do this at startup. It looks like this in the context file:
<object id="MainViewPrepCommand" class="com.xyz.controller.MainViewPrepCommand" >
...
<property name="specialistSelectionScreenMediator" ref="specialistSelectionScreenMediatorInstance" />
...
</object?
And the relevant pieces of the MainViewPrepCommand look like this in the code:
public class MainViewPrepCommand extends IocSimpleCommand
{
...
// the mediator gets injected and stored here. This can be an interface or a concrete class. If Flex Builder had a decent "extract interface"
// refactoring tool, I'd definitely say "always code to an interface instead of the concrete class..." but what you do in private is your business :)
private var _specialistSelectionScreenMediator:ISpecialistSelectionScreenMediator;
...
// This is the method that the Prana container calls when it sets this property when creating the mediator
public function set specialistSelectionScreenMediator(v:SpecialistSelectionScreenMediator):void {
this._specialistSelectionScreenMediator = v;
}
...
override public function execute( note:INotification ) :void
{
var app:MyApp = note.getBody() as MyApp;
...
_specialistSelectionScreenMediator.setViewComponent(app.mainView.specialistSelector);
iocFacade.registerMediatorByConfigName(_specialistSelectionScreenMediator.getConfigName(), _specialistSelectionScreenMediator);
...
}
As you can see above - it's a fairly straightforward command. Perhaps in the future one of us will create a utility object that will be easily configurable in the context file so you can simply leverage that to help do this all by simply writing a few lines in the configuration file. Even this isn't very painful, however.
The benefits of using an IoC container in this case listed above involve the ease of swapping out delagates. When I am ready to change my implementation to go "live" with a real delegate that will actually communicate with the server, I don't have to touch any of the code - I merely have to change the loginDelegateInstance to be of a different class - and inject any configuration details into that class that may be necessary (such as remote service information). I can even have several delegates in my code that are all compiled and available - so I can perform some kind of performance testing against different remote access methods (i.e. have one delegate hitting a web service and marshalling the objects into strongly-typed return objects, while another delegate would use object remoting and pass off the strongly-typed objects that are returned from that process without doing much additional work) - and in that case, it would be literally simply swapping one line of configuration between executions of the file and the entire behavior of that piece would be changed.
In that vein - one of my favorite things about Prana is the ease in which I can handle remote objects and their configurations. Flex by default practically forces you hardwire the remoting configuration at compile-time, which has always rubbed me the wrong way. With Prana, configuring my remote destinations at runtime is extremely easy. It looks like this:
<property file="remotingprops.xml" />
<object id="remotingChannel" class="String">
<constructor-arg value="${remoting.channel}" />
</object>
<!-- ================================================== -->
<!-- Template: Remote Object -->
<!-- Usage: This template is used to make it easy -->
<!-- to configure our remote objects. -->
<!-- Parameters: -->
<!-- destination - The RemoteDestination on the server -->
<!-- source - A name to describe the source -->
<!-- ================================================== -->
<template id="remoteObject">
<object class="mx.rpc.remoting.mxml.RemoteObject">
<property name="destination" value="${destination}"/>
<property name="endpoint" ref="remotingChannel" />
<property name="showBusyCursor" value="true"/>
<property name="source" value="${serviceClass}"/>
</object>
</template>
In my remotingprops.xml file I have a simple properties file that I specify the hostname and the context root of my server. You will notice that even the remote service itself is abstracted out... so I can change between different endpoints on the server without having to touch my flex code or recompile it to match a new configuration.
The main difference between Prana's PureMVC classes the pure PureMVC classes is that Prana classes all use the configName rather than the name defined by the concrete instance. This is to provide functionality for the name-based retrieval, but to allow the names to be set in the context and not in the classes (the id attribute of the object is the "configName"). This is the primary change that has been made to the PureMVC classes.
The only other change that I am aware of is that a new IoCManagedMacro command was created because the existing MacroCommand has a final method that dictates that it create an instance of the command itself - and the Prana one relies upon concrete commands being passed into it. (The reason for this is that the commands - although stateless - can still have dependencies upon other collaborators such as proxies... etc. that are set in the context file.) For a similar reason, the IoCMediator provides default null values for both the name and the viewComponent of the constructor to allow for it to be created at run-time.
Aside from those few changes, I don't believe that much else has been changed. The ConfigName mappings are still passed to the standard Facade - and you could create a PureMVC application that used Prana to only manage the dependencies of a small portion of it - the IoC classes and the normal PureMVC classes can coexist in the same application. A command could use the Facade to retrieve an instance of a Proxy that was set up by the IoC Container - for instance - and it would be unaware of Prana entirely.
I think that the number of changes is minimal, and no omissions come to mind. The current SVN trunk of Prana (0.6) has some changes in it to try to bring it even closer to a normal PureMVC way of doing things.
Since PureMVC is architected very well with loose coupling in mind, it is not hard to make it play well with an IoC container. If anyone is interested in helping, check out the code and play around with it a bit.