Using Spring ActionScript With ActionScript Foundry

What is Spring ActionScript ?

According to the official site:

Spring ActionScript is an Inversion of Control (IoC) Container for ActionScript 3.0, and more specifically the Flex framework. It enables you to configure objects and components in a non-intrusive way by describing them in an external xml document and having them loaded at runtime. ”

Requirements

All useful information about Spring ActionScript are accessible here : http://www.pranaframework.org

We have built a new version of ActionScript foundry in order to makes the initialization process of Flex Application with Spring ActionScript framework. Please use at least the 2.1.0 version of the ActionScript Foundry

Maven Dependencies

We provide Spring ActionScript at http://maven.servebox.org/repository

dependencies declaration:

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-actionscript</artifactId>
			<version>0.7.1</version>
			<type>swc</type>
		</dependency>

spring-actionscript has a dependency on as3reflect project, http://code.google.com/p/as3reflect/

Why should i need IOC and dependency injection in Flex Application.

There are multiple reasons, you can use Spring ActionScript for specific test environment, multiple server environments, conditional user’s execution and generally each time an application runs in specific contexts. IOC increase adaptability, maintainability, and lisibility.

Here is an article about dependency injection and IOC:

How Spring ActionScript works ?

Spring is based on a xml file usually named applicationContext.xml this file will be loaded at runtime. It contains XML description of actionscript classes, constructor description, property definition or function calls. The applicationContext.xml file only assumes the description role.

From ActionScript point of view this file will be parsed and stored in a XMLApplicationContext object. At runtime your application will refer to the XMLApplicationContext object for the class instantiation that required IOC.

e.g. : BusinessDelegate is the ActionScript Foundry class which assumes RemoteService abstraction. Typically you could have more than one BusinessDelegate depending on your execution context.

Your applicationContext-remote.xml could be:

<?xml version="1.0"?>
<objects xmlns="http://www.pranaframework.org/objects"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.pranaframework.org/objects
    	http://www.pranaframework.org/schema/objects/prana-objects-0.6.xsd">
 
	<object id="businessDelegate" class="org.servebox.sample.business.RemoteBusinessDelegate">
		<method-invocation name='service'>
			<arg>
				<ref>remoteObject</ref>
			</arg>
		</method-invocation>
	</object>
 
	<object id="remoteObject" class="mx.rpc.remoting.RemoteObject">
		<property name="destination" value="remote-service" />
		<property name="source" value="remote-service"/>
	</object>
 
</objects>

and your applicationContext-local.xml could be:

<?xml version="1.0"?>
<objects xmlns="http://www.pranaframework.org/objects"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.pranaframework.org/objects
    	http://www.pranaframework.org/schema/objects/prana-objects-0.6.xsd">
 
	<object id="businessDelegate" class="org.servebox.sample.business.LocalBusinessDelegate">
		<method-invocation name='service'>
			<arg>
				<ref>remoteObject</ref>
			</arg>
		</method-invocation>
	</object>
 
	<object id="remoteObject" class="mx.rpc.remoting.RemoteObject">
		<property name="destination" value="local-service" />
		<property name="source" value="local-service"/>
	</object>
 
</objects>

Loading the ApplicationContext

Loading applicationContext is quite simple. applicationContext.xml has to be considerate as an external resource, accessible at runtime. I choose to place this file in:

/src/main/resources/spring/applicationContext-mycontext.xml

So the file will be copied by eclipse or maven to:

http://localhost/myApplicationName/spring/applicationContext-mycontext.xml.

Due to Flex Application initialize process, IOC mechanism implementation might be difficult. In fact, you have to ensure that the applicationContext.xml file is loaded before instancing a specific class or application will raise an exception. With the ActionScript foundry, some classes are automatically instantiate at startup. the following methods are automatically triggered during the application initialization process:

  • initializeModels() (run by  initializeFoundryObjects()  )
  • initializeDelegates() ( run by  initializeFoundryObjects()  )
  • initializeSubController() ( run by  initializeFoundryObjects() )

Due to this limitation, we have decided to change the AbstractApplication initialization process; this refactoring is available in release up to 2.1.0-SNAPSHOT. It implies that initialization process is bypassed until all external resources are loaded. External resources are declared in the externalResources array.  Just override it in your application. Note that you can specify other IExternalRessource in the externalRessources array such localization file.

private var xmlSpringResource : XMLSpringResource = new XMLSpringResource("spring/applicationContext.xml" , onContextLoaded );
 
override public function get externalRessources():Array
{
	return [ xmlSpringResource ];
}

Once all externalRessources will be loaded, the default initialization  process of the application will be executed.

Declaring the applicationContext in your application

protected var applicationContext:XMLApplicationContext = XMLApplicationContext( xmlSpringResource.getXMLApplicationContext() );

Using Spring ActionScript at runtime

That the point ! IOC design pattern is designed to work at run time. Let’s see a sample of BusinessDelegate instanciation.

In our controller:

override public function initializeDelegates():void
{
	var delegate : IBusinessDelegate = SpringApplication( Application.application ).getApplicationContextObject("businessDelegate") as IBusinessDelegate;
	registerBusinessDelegate( delegate , getQualifiedClassName( delegate  ));
}

In the SpringApplication:

public function getApplicationContextObject( key : String ) : *
{
    return applicationContext.getObject( key );
}

Explanations:

The applicationContext property of SpringApplication contains all objects defined in applicationContext.xml as a graph of object. When the getApplicationContextObject(“theObjectINeed”) is called, Dependency injection mechanism is processed. In other word if the requested object depends on other objects, those objects will also be instantiate by Spring ActionScript.

In the following sample, requested the businessDelegate object will also instantiate the remoteObject object, remoteObject will also instantiate channelSet and so on. <ref> is the XML keyword for linking objects.

<object id="businessDelegate" class="org.servebox.sample.business.LocalBusinessDelegate">
	<method-invocation name='setService'>
		<arg>
			<ref>remoteObject</ref>
		</arg>
	</method-invocation>
</object>
 
<object id="remoteObject" class="mx.rpc.remoting.RemoteObject">
	<property name="destination" value="local-service" />
	<property name="source" value="local-service"/>
	<property name="channelSet">
		<ref>channelSet</ref>
	</property>
</object>
 
<object id="channelSet" class="mx.messaging.ChannelSet">
	<method-invocation name="addChannel">
		<arg>
			<ref>amfChannel</ref>
		</arg>
	</method-invocation>
</object>
 
<object id="amfChannel" class="mx.messaging.channels.AMFChannel">
	<constructor-arg value="my-amf"/>
	<constructor-arg value="http://localhost/sampleApplication/amfbroker"/>
</object>

Why FlashPlayer limitation makes Spring ActionScript implementation painful ?

As you know, the flex compiler does not include non-referenced classes in the bytecode. This makes IOC difficult to use.

e.g : If you got a reference to theLocalBusinessDelegate class in your applicationContext and this class is never used in your project, you will get the following Error:

Error: A class with the name ‘org.servebox.sample.business.LocalBusinessDelegate’ could not be found.

There is actually four (ugly) solutions for solving this problem:

  • You should import at least one time all the classes you use in your applicationContext.xml

Just put a reference to each class in your Application constructor:

                public function SpringApplication()
		{
			bypassInitialization = true;
			ContactModel;
			HeaderRemote;
			HeaderLocal;
			RemoteBusinessDelegate;
			LocalBusinessDelegate;
			RemoteObject;
			super();
		}
  • You can use [Frame] metadata:
package org.servebox.sample
{
    [Frame(extraClass="org.servebox.sample.business.RemoteBusinessDelegate")]
    [Frame(extraClass="org.servebox.sample.business.LocalBusinessDelegate")]
    public class SpringApplication extends Application
    {
    }
}
  • You can use -include-libraries directive that force all code included in a library to be linked in your application
  • You can put all your code in an external RSL, so all classes will be linked in your swf.

None of these solutions seems to be really handy and we are actually investigating for a better solution.


Tags: , , ,

Print This Post Print This Post Thursday, April 9th, 2009 Tutorials by Jeff Mathiot

No comments yet.

Leave a comment

You must be logged in to post a comment.