Jai’s Weblog – Tech, Security & Fun…

Tech, Security & Fun…

  • Jaibeer Malik

    Jaibeer Malik
  • View Jaibeer Malik's profile on LinkedIn
  • Subscribe

  • Feedburner

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 29 other followers

  • Archives

  • Categories

  • Stats

    • 379,210
  • Live Traffic

Flex: SpringActionscript (IOC) & SpringActionscript Cairngorm Extension Sample Code Examples

Posted by Jai on August 24, 2009

This post covers some sample code examples of SpringActionscript Cairngorm Extension which you can use to inject the different Cairngorm objects using SpringActionscript framework (Flex IOC).

As promised in my earlier posts Flex then, now & tomorrow – From a java developer’s perspective, Flex: Cairngorm (MVC), SpringActionscript (IOC) and other Cairngorm Extensions to share the sample code examples, few strategies and best practices for flex development using Cairngorm.  In this post we will cover the Flex IOC, SpringActionscript framework and the Cairngorm extension. We will cover how we can configure the different objects that we can inject and usually need in cairngorm implementation are:

  • Event name and command mapping in front controller
  • Command needs models
  • Command needs delegate
  • Delegate needs service
  • Services and Amf channel configurations

Lets have a look at the overall application context file and then we can take each object one by one in more details and covering the sample code for it.


<!-- External configuration file -->
<property file="config.properties" />

<!-- Application Model -->

<object id="applicationModelLocator" factory-method="getInstance" singleton="true" ></object>

<!-- Front Controller -->
<object id="frontController" class="com.test.control.TestAppController">		<constructor-arg>			<object><property name="checkLoginCredentials" type="class" value="com.test.command.TestCommand1"></property><property name="getUserDetails" type="class" value="com.test.command.TestCommand2"></property>			</object>
		</constructor-arg>
		<method-invocation name="addCommandFactories">
			<arg>
				<array>
					<ref>appAwareCmdFactoryForLoginDelegate</ref>
			    	     <ref>appAwareCmdFactoryForUserDelegate</ref>
				</array>
			</arg>
		</method-invocation>
</object>
<!-- Delegates -->
<object id="loginDelegateFactory"		class="org.springextensions.actionscript.cairngorm.business.BusinessDelegateFactory"><property name="service" ref="loginService"></property><property name="delegateClass" type="class" value="com.test.business.LoginDelegate"></property></object>

<object id="userDelegateFactory"		class="org.springextensions.actionscript.cairngorm.business.BusinessDelegateFactory"><property name="service" ref="userService"></property><property name="delegateClass" type="class" value="com.test.business.UserDelegate"></property></object>

<!-- Command Factory  -->
<object id="appAwareCmdFactoryForLoginDelegate"	class="com.test.command.TestApplicationModelAwareCommandFactory"><property name="applicationModel" ref="applicationModelLocator"></property>		<method-invocation name="addBusinessDelegateFactory">			<arg>				<ref>loginDelegateFactory</ref>			</arg>			<arg>				<array>					<value type="Class">com.test.command.TestCommand1 </value>				</array>			</arg>		</method-invocation></object>

<object id="appAwareCmdFactoryForUserDelegate" class="com.test.command.TestApplicationModelAwareCommandFactory"><property name="applicationModel" ref="applicationModelLocator"></property>		<method-invocation name="addBusinessDelegateFactory">			<arg>				<ref>manageUserDelegateFactory</ref>			</arg>			<arg>				<array>					<value type="Class">com.test.command.TestCommand2 />				</array>			</arg>		</method-invocation></object>

<!-- Channel Configurations -->

<object id="amfChannel" class="mx.messaging.channels.AMFChannel">		<constructor-arg value="my-amf"></constructor-arg>		<constructor-arg value="http://${host.name}:${host.port}/${context-name}/messagebroker/amf"></constructor-arg><property name="id" value="amfChannel"></property><property name="pollingEnabled" value="false"></property></object>

<object id="channelSet" class="mx.messaging.ChannelSet">		<method-invocation name="addChannel">			<arg>				<ref>amfChannel</ref>			</arg>		</method-invocation></object>

<template id="remoteObject">
		<object class="mx.rpc.remoting.mxml.RemoteObject"><property name="showBusyCursor" value="true"></property><property name="makeObjectsBindable" value="true"></property><property name="channelSet">				<ref>channelSet</ref>			</property>		</object>
</template>

<!-- Remote services -->
<object id="loginService" template="remoteObject" ><property name="destination" value="loginService" /></object>

<object id="userService" template="remoteObject"><property name="destination" value="userService" /></object>

As you can see the context file is used to configure different cairngorm objects and to inject dependent object.  The channel configuration is obtained from the configuration file. It picks the key-value properties from the configuration file  “config.properties”. Common template is used to configure all the remote objects.

It shows the single mapping like each command will have single delegate and each delegate will have single service. The model locator is injected in each command so that you can directly have model access inside the command. If there is group of commands which use the same delegate, then pass the commands as array to the commandFactory. If you have complex mappings in your application, twist around the same things to make it work.

Lets have a look at sample code of each component to make it work.

ApplicationModelLocator


public class ApplicationModelLocator extends EventDispatcher implements IModelLocator, IApplicationModelLocator
 {
...
...

private static var modelLocator:IApplicationModelLocator;

public static function getInstance():IApplicationModelLocator
 {
 if (modelLocator == null)
 {
 modelLocator=new ApplicationModelLocator();
 }

 return modelLocator;
 }
}

The factory method used in getting the instance in the view component and while injecting into each command should be same. Here it is getInstance, which gives you the same instance at both the places.

The model locator will contain all you application models which will store the application data for you.

TestAppController

import org.springextensions.actionscript.cairngorm.control.CairngormFrontController;
public class TestAppController extends CairngormFrontController
 {
....
...

public function addCommandFactories(commandFactories:Array):void
 {
 if (commandFactories.length > 0)
 {
 for (var i:int=0; i < commandFactories.length; i++)
 {
 addCommandFactory(commandFactories&#91;i&#93;);
 }
 }
 }
}

&#91;/sourcecode&#93;

The front controller keeps information about the event-command mappings. You can use both the context configuration to define this mapping and you can also you addCommand method to define it.

This also contains a custom method  addCommandFactories (which internally calls the addCommandFactory method), used to inject the different command factories created in the context config file.

<strong>LoginDelegate</strong>


import org.springextensions.actionscript.cairngorm.business.AbstractBusinessDelegate;
public class LoginDelegate extends AbstractBusinessDelegate implements ILoginDelegate
 {
public function LoginDelegate( service :* = null, responder:IResponder = null )
 {
 super(service);
 }

public function checkLoginCredentials(userName:String,password:String) : void
 {
 var call : Object = service.checkUser(userName,password);
 call.addResponder( responder );
 }
....
...
}

The delegate class should extend  AbstractBusinessDelegate and the service will automatically get injected into it. And you can directly use the service instance here.

TestApplicationModelAwareCommandFactory


import org.as3commons.reflect.ClassUtils;
import org.springextensions.actionscript.cairngorm.commands.ResponderCommandFactory;
public class TestApplicationModelAwareCommandFactory extends ResponderCommandFactory implements ITestApplicationModelAware {

private var _applicationModel:IApplicationModelLocator;

 public function set applicationModel(value:IApplicationModelLocator):void {
 _applicationModel = value;
 }

 override public function canCreate(clazz:Class):Boolean {
 if (ClassUtils.isSubclassOf(clazz, CommandBase)) {
 return super.canCreate(clazz);
 }
 return false;
 }

 override public function createCommand(clazz:Class):ICommand {
 var result:CommandBase = super.createCommand(clazz) as CommandBase;
 result.applicationModel = _applicationModel;
 return result;
 }
....
....

}
<pre>

This is the custom command factory which should extend the  ResponderCommandFactory and used to set the application model inside all the commands created using this factory.

CommandBase


import org.springextensions.actionscript.cairngorm.commands.AbstractResponderCommand;
public class CommandBase extends AbstractResponderCommand implements ITestApplicationModelAware {
...
public function set applicationModel(value:IApplicationModelLocator):void {
 _applicationModel = value;
 }
}

This is the base command extending AbstractResponderCommand and which every command will extend and will contain the common functionality between all the commands. The application model is set in base command only so that all commands have access to this model. This is not mandatory but good practice so that if you need to make some changes in your command implementation, you do it in base and get reflected in all the commands.

TestCommand1/TestCommand2

public class TestCommand1 extends CommandBase
 {

override public function execute( event : CairngormEvent ): void
 {
...
IloginDelegate(this.businessDelegate).checkLoginCredentials(userName, password);
}
...
}

All the commands should extend CommandBase and to access the delegate you can directly use some delegate inteface like ILoginDelegate and use this.businessDelegate to get the instance. The use of interfaces and implementation classes is usually preferred in case you want to mock your delegate for the testing purpose etc.

In terms of loose coupling and configuration based injection, it can be really helpful for the testing purpose also. I can define separate mock objects to test the application.

Feel free to share your experinces of flex IOC and other available similar frameworks for flex.

-HTH

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: