Chapter 8. Advanced context features

8.1. Knowing your parents and your children

There two ways of linking contexts. Both dictate how information is shared between these contexts.

The following sections describe the differences and the ways to set these scenario's up.

8.1.1. Context parents

In the first case a context is assigned a parent. In this case the child knows about the parent, yet the parent knows nothing about the child context. By assigning another IApplicationContext instance to this parent property the getObject() method will first see if the current context can create the requested object instance, if no appropriate ObjectDefinition Describes an object that can be created by an <code>ObjectFactory</code>. can be found it will request it from its parent factory.

When a context gets assigned a parent it will automatically add its eventbus as a listener to its parent's eventbus. That way all regular events dispatched by the parent will also be received by the child.

8.1.1.1. A simple example of a child/parent hierarchy

Imagine a scenario with two application contexts. One is created by the main application and the other is created inside a module that is loaded at a later time.

We will refer to the first as  application context  and the latter as  child context.

Now imagine the configuration of the application context to look like this:

<objects>

 <object class="com.myclasses.MyObject" id="myObject" scope="singleton"/>
 
 <object class="com.myclasses.MyOtherObject" id="myOtherObject" scope="prototype"/>

</objects>

And the child context looking like this:

<objects>

 <object class="com.myclasses.moduleimplementations.MyOtherObject" id="myOtherObject" scope="prototype"/>

</objects>

When the child context is created, we will set the application context as its parent:

var childContext:DefaultApplicationContext = new DefaultApplicationContext("module-context.xml");
childContext.parent = applicationContext;

The result of this is that, when an object with id myOtherObject is requested from the application context, you will receive an instance of type com.myclasses.MyOtherObject. However, when you request the same object id from the child context, you will receive an instance of type com.myclasses.moduleimplementations.MyOtherObject.

Next, we change both configurations slightly, add some dependencies and show how to override those dependencies in the child configuration.

Here's how the application context's configuration looks:

<objects>

 <object class="com.myclasses.MyObject" id="myObject" scope="singleton"/>
 
 <object class="com.myclasses.MyOtherObject" id="myOtherObject" scope="prototype">
  <property name="dependency" ref="myDependency"/>
 </object>
 
 <object class="com.dependencies.MyDependency" id="myDependency"/>

</objects>

Now requesting an object with id  myOtherObject  from the application context will yield you an instance of type  com.myclasses.MyOtherObject  with a  dependency  property value set to an instance of type  com.dependencies.MyDependency.

After that we change the child context configuration to look like this:

<objects>

 <object class="com.moduledependencies.MyDependency" id="myDependency"/>

</objects>

When we subsequently request an object with id myOtherObject from the child context the result will be an instance of type  com.myclasses.MyOtherObject  with a  dependency  property value set to an instance of type com.moduledependencies.MyDependency.

Note

Overriding references like this will only work on objects that are scoped as  prototype , this is because its very probable that the object has already been created and cached by the parent context when requested, and injecting singletons created by the parent with  dependencies  created by the  child  context will suddenly put a dependency from the application context on the child context, which is undesirable.

8.1.2. Context children

The second case describes a scenario where the parent knows about the child, yet the child has no knowledge of its parent. For this the applicationContext.addChildContext() method may be used. The method expects two arguments:

function addChildContext(childContext:IApplicationContext, settings:ContextShareSettings=null):IApplicationContext;

The first is, naturally, the IApplicationContext instance that will be added as the child to the current IApplicationContext . The second argument is more important, the ContextShareSettings instance determines which aspects of the parent will be shared with the child context. A ContextShareSettings instance has the following Boolean properties to specify these aspects:

  • shareDefinitions - If true all of the object definitions of the parent, that have their childContextAccess property set to ChildContextObjectDefinitionAccess.DEFINITION or ChildContextObjectDefinitionAccess.FULL, will be cloned and added to the child context. The default childContextAccess value for an ObjectDefinition Describes an object that can be created by an <code>ObjectFactory</code>. is ChildContextObjectDefinitionAccess.FULL.

  • shareSingletons - If true all of the singletons in the parent's cache will be added to the child's cache, provided that an object with the same name doesn't already exist in the child context.

  • shareProperties - If true the properties registered in the parent's IPropertiesProvider will be copied to the child context. Properties with the same name that are already present in the child context will not be overriden.

Lastly, there is the eventBusShareSettings property, this property is of type EventBusShareSettings Describes in what way two eventbuses will be shared. and determines how the eventbuses of the parent and child contexts will be connected. First there is the shareKind property, this is of type EventBusShareKind Determines the way two eventbuses share their events. . This type defines the following ways of eventbus sharing:

  • NONE - The eventbuses will not be connected.

  • BOTH_WAYS - Events dispatched by the parent will be routed to the child's eventbus, and vice versa, events dispatched by the child will be routed to the parent.

  • CHILD_LISTENS_TO_PARENT - Events dispatched by the parent will be routed to the child's eventbus.

  • PARENT_LISTENS_TO_CHILD - Events dispatched by the child will be routed to the parent's eventbus.

  • ASSIGN_PARENT_EVENTBUS - The parent's eventbus will be assigned to the child context, so that the contexts effectively share one eventbus instance.

The shareRegularEvents property determines if events that are dispatched without a specific topic will be shared between the eventbuses. And lastly, the sharedTopics property determines which topics will be shared. So, for instance, if it is required that the parent listens to the child context for events of topic "SHARED", this EventBusShareSettings Describes in what way two eventbuses will be shared. instance will suffice:

var settings:EventBusShareSettings = new EventBusShareSettings(false, EventBusShareKind.PARENT_LISTENS_TO_CHILD, new <Object>["SHARED"]);

When the settings instance that is passed to the addChildContext() method is null, a default settings object will be created. The default property values for a ContextShareSettings are:

  • shareDefinitions - true.

  • shareSingletons - true.

  • shareProperties - true.

  • eventBusShareSettings - shareRegularEvents:true, shareKind:EventBusShareKind.ASSIGN_PARENT_EVENTBUS, topics:null.

Note

Only add a child context BEFORE the child context has been loaded and initialized!

8.1.3. Contexts and modules

When using modules in a Flex application Spring Actionscript allows a context that is assigned to a Module to autowire its stage components, should this be required.

Note

It is important to set the MXMLApplicationContextBase.modulePolicy property to ModulePolicy.IGNORE on the parent context. When failing to set this property the parent context will automatically try to autowire any modules added to the stage. This property defaults to ModulePolicy.AUTOWIRE.

In a Flex application that uses the MXML based contexts it is possible to let a parent context detect the creation of child contexts (usually in a module) and add them automatically to its child list.

The way this works is as follows. When an MXML based context is created it automatically adds its parent component as a root view. This component's SystemManager is queried to see if its isTopLevelRoot property is set to true. In this case the context will assume it will act as the parent and will listen to the static MXMLApplicationContextBase.sharedContextDispatcher for MXMLContextEvent.CREATED events. If the isTopLevelRoot property is false the specified context will dispatch a MXMLContextEvent.CREATED event through the same shared event dispatcher.

This behaviour is determined by the autoAddChildren property on the MXMLApplicationContextBase . Default this property is set to true.

To determine the default ContextShareSettings to be used while adding children, set the MXMLApplicationContextBase.defaultShareSettings to the desired instance. When different settings are needed for different child contexts listen for the ChildContextEvent.BEFORE_CHILD_CONTEXT_ADD event on the parent context and assign the desired ContextShareSettings instance on the given ChildContextEvent.shareSettings property.

The ChildContextEvent Dispatched by an <code>IApplicationContext</code> that acts like a parent context before and after it adds child contexts. is cancelable, so if the event handler calls ChildContextEvent.preventDefault() the child context will NOT be added.

The same holds true for the ChildContextEvent.BEFORE_CHILD_CONTEXT_REMOVE event, when ChildContextEvent.preventDefault() is called on it the child context will NOT be removed.

If the way that children are added needs very heavy customization it is possible to override the standard functionality completely by assigning a custom function to the ContextEvent.customAddChildFunction property. This function needs to have this signature:

function(parentContext:IApplicationContext, childContext:IApplicationContext, settings:ContextShareSettings):void;

Note

The only thing that will be done by the parent context when using a custom child add function is to actually add the child context to its list of children. Any other logic is deferred to the custom function.

A more elaborate way of overriding the child logic is by creating an implementation of the IChildContextManager Describes an object responsible for executing the logic that is involved with adding an <code>IApplicationContext</code> as a child to a parent context. interface and adding it to the configuration. If an application context spots an IChildContextManager Describes an object responsible for executing the logic that is involved with adding an <code>IApplicationContext</code> as a child to a parent context. it will use that instead of its default implementation.

Check out the for a reference application that demonstrates the multi-module support that Spring Actionscript offers.

8.1.4. ApplicationPropertiesObjectFactoryPostProcessor

This processor enables the MXMLApplicationContext to inject a number of Application properties into its managed objects. The following properties are available:

  • application.frameRate

  • application.historyManagementEnabled

  • application.pageTitle

  • application.resetHistory

  • application.scriptRecursionLimit

  • application.scriptTimeLimit

  • application.url

  • application.url.protocol

  • application.url.host

  • application.url.port

  • application.usePreloader

  • application.viewSourceURL

And besides those, any application parameters will be added by name as well. So if the a parameter called  myAppVar  is passed into the application it will be available as an external property by the name of  application.myAppVar . To inject these values into an object add them into the configuration like this:

<sas:Object id="myClass" clazz="{MyClass}">
	<sas:Property name="frameRate" value="$(application.frameRate)"/>
</sas:Object>

To enable the factory postprocessor, you also need to add a definition for it to the configuration:

<sas:Object id="applicationPropertiesObjectFactoryPostProcessor" clazz="{ApplicationPropertiesObjectFactoryPostProcessor}"/>