Introduction
I have recently been playing around with Prana. This is a wonderful inversion of Control framework written by a very talented and supportive group (Christophe Herreman, Damir Murat, Erik Westra). Below are my learnings and observations.
What is Prana
Prana has a class called “XMLApplicationContext” that will create objects as defined by an XML file. The XML file actually specifies the class name and other necessary parameters required to create an object. Right off the bat I am sure you can think of projects where you have custom built a parser and a factory to do the same thing, but instead of linking the the class dynamically you used a case statement.
Why Use Prana
The driving forces behind Prana are much more than providing a reusable parsing and factory code. Actually Prana is a framework that implements to concept of IoC and Dependancy Injection. These are concepts most documented and implemented by the Java Based Spring Framework The general theory is that by inverting control logic from a centralized controller to external configuration files your application becomes flexible in the supporting and switching different types of control logic that might do the same thing, but do it in different ways (ie production environment might use data a server versus test environment that uses canned data). More specifically Prana allows you to use dependency injection in that we inject the implementation dependencies into build through the external configuration files instead of coding them into the application directly.
How to use Prana
Below are the simplest steps I found to actually seeing something working. The Prana team has a few great examples you should check out as well. 1) Check out Prana as a project into Flex Builder. New -> Project -> Checkout Projects from SVN -> Create a new repo location -> https://prana.svn.sourceforge.net/svnroot/prana -> click on “prana-main -> trunk -> src -> main” basically make it a project. 2) The project I made basically resuses a bunch of stuff that is in the prana-sample-movieApp project, so report step 1 for the movie project. New -> Project -> Checkout Projects from SVN -> Create a new repo location -> https://prana.svn.sourceforge.net/svnroot/prana -> click on “prana-sample-movieApp -> trunk -> src -> main” basically make it a project. 3) Now you have Prana, lets take it for a spin. Create a new Actionscript project, I called mine “iman_prana_simple_sample”. I set the Actionscript build Source path the following: a) Path to the “prana-main” we just checked out. make sure the path ends like this “\prana-main\src\main” b) Path to prana-sample-movieApp we just checked out. Make sure the path ends like this “\prana-sample-movieApp\trunk\src\main” c) Path to flex framework. Basically something like “C:\Programs\Adobe\Flex Builder 3\sdks\3.0.0\frameworks\src” Here is the code I replaced the main AS3 class with. This is the class that you will “set as the default application” and run. I was able to compile this code and get the expected output. Its basically a bunch of stuff I stole from the movieApp example. I wanted to see the project work in an AS3 only environment. So here it is:
package {
import flash.display.Sprite;
import flash.events.Event;
import org.pranaframework.context.support.XMLApplicationContext;
import org.pranaframework.samples.movieapp.MovieLister;
import org.pranaframework.samples.movieapp.CSVMovieSource;
import org.pranaframework.samples.movieapp.StaticMovieSource;
public class iman_prana_simple_sample extends Sprite
{
private var _applicationContext:XMLApplicationContext;
private var _applicationContextComplete: Boolean= false;
private var _movieLister:MovieLister;
public function iman_prana_simple_sample()
{
// The next 2 lines gets the dynamic classes compiled.
CSVMovieSource
StaticMovieSource
logMessage(“creation complete; setting up object factory to load applicationContext”);
// an instance of XmlObjectFactory is able to load an XML
// file with object definitions and parse it
_applicationContext = new XMLApplicationContext(“applicationContext.xml”);
// listen for the object definitions loading to complete
// (loaded and parsed xml object definitions)
_applicationContext.addEventListener(Event.COMPLETE, onApplicationContextComplete);
// start the loading
_applicationContext.load();
logMessage(“started loading applicationContext”);
} // constructor
private function onApplicationContextComplete(event:Event):void {
logMessage(“finished loading applicationContext”);
logMessage(“trying to load ‘movieLister’ object from object factory”);
// we can get objects from the application context with
// the getObject() method. As an argument, we pass in the id of
// the object definition in the applicationcontext xml file
// here we request the ‘movieLister’ and put it in a var
// (note: container.getObject(“staticMovieSource”) would give
// us the StaticMovieSource object defined in the application-
// context
// programmatically we would do something like:
// var movieSource:IMovieSource = new StaticMovieSource();
// var movieLister:MovieLister = new MovieLister();
// movieLister.movieSource = movieSource;
// … but the container does that for us
_movieLister = _applicationContext.getObject(“movieLister”);
logMessage(“successfully loaded ‘movieLister’ “);
// mark the object factory complete flag as true
// this will enable the UI controls to search for movies
// because their ‘enabled’ property is bound to this var
_applicationContextComplete = true;
onGetMoviesButtonClick();
}//onApplicationContextComplete function
private function onGetMoviesButtonClick():void {
// search movies from the given director
// if the director’s name is left blank, then all movies will
// be returned
var director:String = “Quentin Tarantino”;
var movies:Array = (director == “”) ? _movieLister.getAll() : _movieLister.getMoviesDirectedBy(director);
logMessage(“‘” + movies.length + “‘ movie(s) found”);
// show all movie matches
for (var i:int = 0; i<movies.length; i++) {
logMessage(“movie #” + (i+1) + “: ” + movies[i]);
}
}
private function logMessage(message:String):void {
var time:Date = new Date();
trace(time.hours + “:” + time.minutes + “:” + time.seconds + ” – ” + message);
} // logMessage function
} // class
} // package