Introducing Prana: IoC Container for AS3

ActionScript, Design Patterns, Flash, Flex, Prana Add comments

Note before starting: For a primer on Inversion of Control (IoC) and Dependency Injection, please read "Inversion of Control Containers and the Dependency Injection pattern" by Martin Fowler.

Prana's IoC container: an example

As an example, I took the Cairngorm Store modified by Renaun Erickson and used Prana to configure its service locator. You could imagine this application being deployed on several clients and they would all have their own AMFPHP gateway. It would be a pain if the application would have to be recompiled for each client just because the path to the remoting gateway changed. With Prana, we can specify the actual implementation of the remote services and the service locator in an external xml file called the application context (applicationContext.xml) and the IoC container will be responsible for setting things up for us. Let's see some code.

The service locator is now configured in the Services.mxml file. One of the services, the 'productService', is configured like this:

XML:
  1. <renaun:RemoteObjectAMF0
  2.   endpoint="http://localhost/amfphp/gateway.php"
  3.   id="productService"
  4.   source="com.adobe.cairngorm.samples.store.business.ProductDelegate"
  5.   showBusyCursor="true"
  6.   makeObjectsBindable="true">
  7. </renaun:RemoteObjectAMF0>

You can see that the endpoint property is pointing to a hard coded remoting gateway. As said earlier, in order to change this value for another deployed client, we would have to change the value and recomile the application. With Prana, we will just leave out the actual implementation like this:

XML:
  1. <renaun:RemoteObjectAMF0 id="productService"/>

So when the application is compiled, the service locator will know about a remote service called 'productService' but it will not know anything about its implementation details.

Defining the application context

We define the external configuration of the productService as follows. This configuration is stored in an xml file, called applicationContext.xml by convention (but you can call it whatever you like):

XML:
  1. <object id="productService" class="com.renaun.rpc.RemoteObjectAMF0">
  2.   <property name="id" value="productService"/>
  3.   <property name="endpoint" value="http://localhost/amfphp/gateway.php"/>
  4.   <property name="source" value="com.adobe.cairngorm.samples.store.business.ProductDelegate"/>
  5.   <property name="showBusyCursor" value="true"/>
  6.   <property name="makeObjectsBindable" value="true"/>
  7. </object>

Every object is defined in an 'object' node. We need to give each object and identifier (the 'id' attribute) and a class name (the 'class' attribute) so that the container knows which class to instantiate. The properties of the productService are defined in 'property' nodes which all have a 'name' and 'value' attribute. You can see for instance that the 'endpoint' property will be assigned the value 'http://localhost/amfphp/gateway.php'.

Note: Prana currently supports setter injection through implicit setters and not through explicit setters. (set myPropery vs. setMyProperty)

Besides the productService, we also have to configure the service locator so that it knows it is assigned a new instance of a remote service:

XML:
  1. <object id="serviceLocator" class="com.adobe.cairngorm.business.ServiceLocator" factory-method="getInstance">
  2.   <property name="productService">
  3.     <ref>productService</ref>
  4.   </property>
  5. </object>

Notice that we have specified a 'factory-method' attribute on the definition of the service locator. This is needed because Cairngorm's ServiceLocator is a singleton which you can access through the getInstance() method. When the container finds a factory method defined, it will not invoke the constructor of the class but instead will call the specified factory method to retrieve an/the instance of the class.

The productService is defined as a property of the serviceLocator, but notice here that the property node does not have an actual value assigned. Instead, is it has a 'ref' node which describes a reference to the id of another object defined in the application context.

Note: Currently reference properties only work when the refered to object is configured before the object that is refering to it. This will be solved in later versions of Prana.

The application context is ready. All we need to do now, is let the application know that it should load the context before starting up. In the Cairngorm Store example the application starts by getting the products for the store. This is defined in the onCreationComplete handler:

Actionscript:
  1. CairngormEventDispatcher.getInstance().dispatchEvent( new CairngormEvent( GetProductsEvent.EVENT_GET_PRODUCTS ) );

We will remove this here line and instead load the application context. Once the context is loaded, we can dispatch the event to get the products:

Actionscript:
  1. private var _objectDefinitionsLoader:IObjectDefinitionsLoader;
  2.  
  3. private function onCreationComplete():void {
  4.   _objectDefinitionsLoader = new XmlObjectDefinitionsLoader();
  5.   _objectDefinitionsLoader.addEventListener(ObjectDefinitionsLoaderEvent.COMPLETE, onObjectDefinitionsLoaderComplete);
  6.   _objectDefinitionsLoader.load("../applicationContext.xml");
  7. }
  8.  
  9. private function onObjectDefinitionsLoaderComplete(event:ObjectDefinitionsLoaderEvent):void {
  10.   CairngormEventDispatcher.getInstance().dispatchEvent( new CairngormEvent( GetProductsEvent.EVENT_GET_PRODUCTS ) );
  11. }

That's it. By loading the application context, all objects will be wired together behind the scenes. If wanted, we could access the container and request the productService from it:

Actionscript:
  1. var container:ObjectContainer = _objectDefinitionsLoader.container;
  2. var productService:RemoteObjectAMF0 = container.getObject("productService");

Other Prana capabilities

The Dependency Injection method in the example above is Setter Injection. Prana however also supports Constructor Injection. An example object definition for a constructor defined as Person(name:String = "", age:int = 0, isMarried:Boolean = false) is:

XML:
  1. <object id="johnDoe" class="be.indiegroup.prana.ioc.testclasses.Person">
  2.   <constructor-arg value="John Doe"/>
  3.   <constructor-arg value="36"/>
  4.   <constructor-arg value="true"/>
  5. </object>

Another thing is that you can (recursively) define properties as arrays or objects like this:

XML:
  1. <object id="testObject" class="be.indiegroup.prana.ioc.testclasses.TestObject">
  2.   <property name="anArray">
  3.     <array>
  4.       <value>stringValue</value>
  5.       <value>13</value>
  6.       <value>true</value>
  7.       <array>
  8.         <value>12</value>
  9.         <value>test</value>
  10.       </array>
  11.     </array>
  12.   <property>
  13.   <property name="anObject">
  14.     <object>
  15.       <property name="key1" value="value1"/>
  16.       <property name="key2" value="35"/>
  17.       <property name="key3" value="false"/>
  18.       <property name="key4">
  19.         <array>
  20.           <value>12</value>
  21.           <value>test</value>
  22.         </array>
  23.       </property>
  24.     </object>
  25.   </property>
  26. </object>

Download Prana 0.1

I hope you enjoyed this primer on Prana. Below is the Prana Framework available for download. It has the Prana.swc file, sources and docs. Please note that documentation is far from complete at this moment. The other download is the Cairngorm Store, modified by Renaun Erickson to use AMFPHP and modified by myself to use Prana. You can download them here:

  • Prana Framework 0.1
  • Prana Framework 0.1.1
  • Prana Framework 0.1.1 with dependencies
  • Cairngorm Store Prana Example
  • Download Prana on SourceForge: Prana SourceForge page

Have fun!


Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
 

9 Responses to “Introducing Prana: IoC Container for AS3”

  1. Theo Says:

    Interesting. But I’m interested in how you deal with including the classes referenced in the applicationContext.xml into the SWF. Do you have to reference each class in the application to make sure that it is included?

  2. Christophe Says:

    @Theo: yes that is the approach I’m using right now. Note though that in the service locator example it is not needed since all the classes are already compiled in the swf because they are referenced in the services.mxml file. In my new post on the FrontController, the commands need to be referenced so they get compiled.

  3. shaun Says:

    Nice work. I might have to give it a whirl soon.

  4. Flapflap Says:

    Hi there,
    Interresting, do you know LowRA and PixIOC, inversion of control projetcts made by Francis Bourre ?
    They have a very interresting feature of plugin, you can create your application by extending a Pluxgin class that allow IOC but also a MVC+C for each plugin and a channel communication between plugins.
    Have you planned same features ?

  5. Christophe Says:

    Hi FlapFlap,

    I heard of LowRA but didn’t really check it out till you commented here. It seems that LowRA is much more than an IoC container. The core goal of Prana is to provide a solid IoC container, based on successful implementations like Java Spring, and offer additional configuration support for the different application frameworks out there.

    Furthermore, I also read your post on the LowRA list and wanted to make some things clear:
    - Prana is not based on Cairngorm, but offers support for developers using Cairngorm by providing configuration options using the IoC container. It is important to know this as I think it may quickly become a general misconception of what Prana actually is and what it is capable of.
    - The current version of Prana is not 0.03 but 0.3. I also think we can change the alpha to beta by now.

    I will be keeping an eye on LowRA and thanks for commenting.

  6. Matt Says:

    Loving the work! Really impressed :o )

  7. Varun Rathore Says:

    Love ur work .
    Keep the good work hope to see this thing on widescale, i loved the (recursively) defining properties .

    Thanks a lot

  8. TK Says:

    This is absolutely genius. I have been considering putting together an AS3 IoC container for a while now and I’m glad to see that someone beat me to the punch :)

    Seriously though, thank you so much for this excellent contribution to AS3. While some developers might overlook this, IoC is critical for large-scale RIA’s with external dependencies and properties that should be handled by injection. Much gratitude,

    – TK

    PS: Is Prana dependent on Cairngorm? I still haven’t given Prana a whirl yet, but I develop in strict AS3 w/o use of the Flex Framework so I want to know if I can use Prana.

  9. Ries van Twisk Says:

    What does Prana really trying to solve???

    Ries

Leave a Reply

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in