Jul 4, 2008

Depedency Injection Container for Flex - part 2 Metadata Injection

As someone knows, there is a way to preserve custom metadata in Flex for runtime. The easiest way is to put for example:
-keep-as3-metadata+=Inject
in addidtional compiler arguments.

I found a way to use it for easy injection. Here's a proof of concept. I think the source is worth more than words.
This part :


//Injection by id
[Inject(id="component1")]
public var a:Object ;

//injection by id simpler
[Inject("component2")]
public var b:Object;

//injection by type
[Inject(type="poc.SimpleComponent2")]
public var c:SimpleComponent2;

//Injection by type guess
[Inject]
public var d:ExplicitCommandImpl;


//Injection by type works with interfaces, basic classess too
[Inject]
public var e:IExplicitCommand;


private var _f:Object;

//Works with getters and setters too
//Inject with given context
[Inject(type="poc.SimpleComponent2", context="someContextName")]
public function get f():Object
{
return _f;
}

public function set f(val:Object):void
{
_f = val;
}

does the trick.

The final trace is :

a [object ExplicitCommandImpl]
b [object SimpleComponent]
c [object SimpleComponent2]
d [object ExplicitCommandImpl]
e [object ExplicitCommandImpl]
f [object SimpleComponent2]

I think It's an easy way to join application components. The injected components are get by methods mentioned in part2 : getComponentById and getComponentByInterface so it's just a shortcut.

Just the -keep-as3-metadata part is tricky during release build. There's a bug on Adobe bugtracker.

Jul 3, 2008

Depedency Injection Container for Flex - part 1

It's an implementation of the pattern as described by Martin Fowler in “Inversion of Control Containers and the Dependency Injection pattern”. It contains setter injection and constructor injection implementations. Main ideas are to :

  • connect simple components in depedency injection container,
  • make use of Flex features e.g. use MXML files (with code completition etc.) rather than external XML files for depedency injection configuration,

This container can be used also as a service locator.





Simple example of configuration:


<?xml version="1.0" encoding="utf-8"?>
<InjectionContainer xmlns="edu.ics.framework.injection.
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:actions="edu.ics.framework.actions.>

<DIComponent id="component1" scope="application" componentClass="{ExplicitCommandImpl}"
>
<constructorParams>
<mx:Array>
<mx:String>string parameter</mx:String>
<mx:Number>2</mx:Number>
<mx:Object>{component2}</mx:Object>
</mx:Array>
</constructorParams>
</DIComponent>

<DIComponent id="component2" scope="application" componentClass="{SimpleComponent}" />

<actions:AbstractAction id="action1" name="addAction" />
<actions:AbstractAction id="action2" name="copyAction"/>

</InjectionContainer>

Every child object is registered as a component with it's id as a key.
Actually as InjectionContainer uses reflection, every public and bindable
property is registered.


Using DIComponent

DIComponent is basig object for creating components. Basic attributes are:

  1. id - must be specified to identify component; used as a key;

  2. scope - scope of component; three values are allowed:


    • application : only one component instance exists for whole application,

    • context : there is one component instance for every context,

    • instance : new instance is created every time component is requested.


    Default value is application

  3. componentClass - a class of component. Remember to use Class object, not just class name.
    As in the example componentClass="{SimpleComponent}" .

  4. setterTemplate - object that contains params to inject in created component instance

  5. constructorParams - array of construcotor parameters


Any other attribute of DIComponent tag will be used for setter injection.
These parameters overrides setterTemplate object properties.

Example:


<DIComponent id="component2" scope="application" componentClass="{SimpleComponent}" />
<DIComponent id="component3" scope="application" componentClass="{SimpleComponent2}" param1="param1Val" param2="99" />

setterTemplate is used to pass object, that contains params to inject in created component instance.

Example of usage:

<mx:Script>
<![CDATA[
private var setterTemplate3:Object =
{
param1:"param1Value",
param2:99
}
]]>
</mx:Script>

<DIComponent id="component3" scope="application" componentClass="{SimpleComponent2}" setterTemplate="{setterTemplate3}" />

The example above makes the same, that declaration in previous example:


<DIComponent id="component3" scope="application" componentClass="{SimpleComponent2}" param1="param1Val" param2="99" />


which is simpler and preferred method.
In these examples SimpleComponent2 can be:


package poc
{
public class SimpleComponent2
{
public var param1:String;

private var _param2:Number;

public function set param2(val:Number):void
{
this._param2 = val;
}

public function get param2():Number
{
return this.param2;
}

}
}



Constructor injection

You can use constructorParams property to pass array of parameters to constructor.
You can pass up to 15 parameters. Example of usage :


<DIComponent id="component1" scope="application" componentClass="{ExplicitCommandImpl}"
>
<constructorParams>
<mx:Array>
<mx:String>string parameter</mx:String>
<mx:Number>2</mx:Number>
<mx:Object>{component2}</mx:Object>
</mx:Array>
</constructorParams>
</DIComponent>

Simple objects
Example:

<actions:AbstractAction id="action1" name="addAction" />

Objects like this are registered with WrapperComponent . The scope of the component is always
application.



Injection and binding
To perform injection use Flex binding. You can put binded component into dynamic parameters, setter template or construcor parameters.
Injected object will be resolved during creaton of requested component according to its scope attribute.
In case of context scope, the scope name is propagated from parent component request.

Tasks and Actions Management for Flex

I'd like to show some concepts of creating simple, lightweight application framework based on some design patterns used in J2EE and Java Swing Application Framework. Main concept is to extend well known command pattern to make tasks and actions.

This "framework" is now a bunch of ideas and some proof of concept. I'd be happy to hear some comments from you.


Lets start with an example and see the source.


Actions framework solves some common tasks and problems that exist during rich application development:

  • multiple access methods to functionalities (by button, menu item, context menu etc.),
  • building multilingual interfaces,
  • building sequences of tasks (for example to show dialog and save document before closing it ),
  • organizing business components.

Basically it's an implementation of command pattern. Task is a part of code encapsulation single functionality. You can build sequences of both synchronous and asynchronous tasks. An Action is a task too, but has some more information such as name, label, description (tooltip text) and graphical icon. Action can be also saved after execution to build actions history to undo/redo them or even reuse as a macro.




Actions are designed to support multilingual interfaces. Action name is a key, and only property which is defined in the code. Label, icon and tooltip are automatically loaded from resources file. For example (ActionsFramework.properties file):


addAction.label=Add
addAction.tooltipText=Add task
addAction.icon=Embed('../../icons/add.png')

Those properties are then used in UI elements such as buttons, menus and context menus.




You can use UI elements from actionui package or use ActionsUIBinder to bind to existing UI elements. Example of ActionButton:


<actionui:actionbutton id="button1" action="{someAction}">
</actionui:actionbutton>

A button will display label, icon and toolTip from someAction and execute it on click. Building a toolbar from array of actions is also very easy. You can use ActionsUIBinder to build context menu as in the example :


for(var i:uint = 0; i < this.allActions.length; i++)
{
var item:ContextMenuItem = ActionsUIBinder.createBindedContextMenuItem(
AbstractAction(this.allActions[i]));
this.contextMenu.customItems.push(item);
}

Using tasks and actions makes user interface development much faster and actions are easy to manage. Even if you use every action in toolbar, drop down menu and context menu, you always have the same labels and icons with no effort – you only change properties file.
Generic support for cancel and undo actions is now in plans, but it's easy to implement in specific project because actions before execution are copied and saved in TaskManager history.