3 Configuration and Initialization

Configuring and initializing the Parsley Framework usually consists of the following steps:

3.1 Configuration with AS3 Metadata

AS3 Metadata Tags can be used to configure services like Dependency Injection or Messaging. They can be placed on any class that is managed by Parsley. Features configured by metadata tags can be combined with configuration in XML or MXML. Almost every metadata tag has a corresponding MXML and XML configuration tag.

The individual metadata tags and their attributes along with examples are described in the corresponding sections:

Compiling custom metadata into SWFs

Unfortunately the mxmlc compiler has a pretty inconsistent behaviour when it comes to deciding whether custom metadata will be included in the SWF or not. If you use the Parsley and Spicelib SWCs to compile the main application you (or your tool) will likely specify the library with the -l option so that the library will be compiled into your SWF. In this case all the metadata tags used by Parsley and Spicelib will be included automatically. So for the main application SWF there is nothing you have to do unless you created custom configuration tags that you want to use as AS3 metadata.

For compiling modules or other SWFs where you (or you tool) choose to use the -el option to specify the Parsley SWC it is different though. The framework classes will not be compiled into your SWF then (this is intended behaviour) and unfortunately the metadata tags won't either. And this is rather erratic behaviour, since for your intention to use the framework and thus its metadata configuration tags it shouldn't make a difference if you compile the frameworks classes into the SWF or not. So when using the -el option you have to explicitly specify the Parsley and Spicelib metadata tags. Those are quite a few (extracted from the Parsley Ant builds):

<keep-as3-metadata name="Metadata" />
<keep-as3-metadata name="DefaultProperty" />
<keep-as3-metadata name="Required" />
<keep-as3-metadata name="Event" />
<keep-as3-metadata name="AssignableTo" />
<keep-as3-metadata name="Inject" />
<keep-as3-metadata name="InjectConstructor" />
<keep-as3-metadata name="Factory" />
<keep-as3-metadata name="Init" />
<keep-as3-metadata name="Destroy" />
<keep-as3-metadata name="AsyncInit" />
<keep-as3-metadata name="ManagedEvents" />
<keep-as3-metadata name="MessageDispatcher" />
<keep-as3-metadata name="MessageHandler" />
<keep-as3-metadata name="MessageBinding" />
<keep-as3-metadata name="MessageInterceptor" />
<keep-as3-metadata name="MessageError" />
<keep-as3-metadata name="ResourceBinding" />
<keep-as3-metadata name="Selector" />
<keep-as3-metadata name="Target" />
<keep-as3-metadata name="Internal" />
<keep-as3-metadata name="ObjectDefinition" />

Of course you can just pick the ones you are actually using. But then you have to remember to add new tags to the build whenever you introduce a new configuration tag into your application.

In case the metadata tags did not get compiled into your SWF the symptoms are usually that several operations silently fail. For example injections will not performed then if you specified them with the [Inject] tag. When things silently fail this is usually a clear indication that some or all of the metadata tags are missing in the SWF. Because if there was some other type of problem, like an injection type where the framework does not find a matching object for in the container, Parsley will always throw an error. It will not silently fail unless you specified the dependency as optional.

This section was added to this chapter as a few users already ran into this issue.

3.2 MXML Configuration

This is the only Parsley configuration mechanism that (obviously) can only be used in Flex Applications. Everything else is available for Flex and Flash Applications.

Let's assume you want to configure the following two classes:

package com.bookstore.service {

class LoginServiceImpl implements LoginService {

    public var timeout:int;
    
    public function login (username:String, password:String) : void {
        // execute service    
    }
    
}
}
package com.bookstore.actions {

class LoginAction {

    [Inject]
    public var service:LoginService
    
    [MessageHandler]
    public function handleLoginEvent (event:LoginEvent) : void {
           service.login(event.username, event.password); 
    } 
    
}
}

As you see several features are already configured with metadata tags. See 4 Dependency Injection and 5 Messaging for details on these features.

The MXML configuration file

We now have to tell the container to manage these classes and create the following MXML file:

<mx:Object 
    xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:services="com.bookstore.services.*"
    xmlns:actions="com.bookstore.actions.*">
    
    <services:LoginServiceImpl timeout="3000"/>
    
    <actions:LoginAction/>
    
</mx:Object> 

Note that there isn't even a single Parsley import. Only regular object tags like those that you place for any kind of component or object in MXML. In addition to the metadata tags you can use these MXML tags for additional configuration, like the timeout value in the example above.

Framework Initialization

Finally you have to initialize the container. Assuming you saved the configuration in BookstoreConfig.mxml, you can initialize it with:

FlexContextBuilder.build(BookStoreConfig, this);

In many applications the one liner shown above could be the only piece of code where you directly use the Parsley API. To initialize the application you can use [Init] metadata tags on methods of classes that should execute logic on application startup. See 6.3 Object Lifecycle Methods for details.

The second parameter in the code example above refers to the root view component you want to use for dynamically wiring Flex Components to the Context. See 7 Dynamic View Wiring for details.

In theory you could also directly interact with the Parsley Context:

var context:Context = FlexContextBuilder.build(BookStoreConfig, this);
var initializer:BookStoreInitializer 
    = context.getObjectByType(BookStoreInitializer) as BookStoreInitializer;
initializer.execute();

But this kind of usage is not recommended. In normal application code there is usually no need to use the Parsley API directly. The API is primarily for extending the framework or for building custom frameworks on top of Parsley.

Using Parsleys MXML Tags

There is a variant of the MXML configuration mode shown above where you use special Parsley tags instead of normal object tags:

<mx:Object 
    xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns="http://www.spicefactory.org/parsley">
    
    <mx:Script>
        <![CDATA[
            import com.bookstore.services.*;        
            import com.bookstore.actions.*;        
        ]]>
    </mx:Script>
    
    <Object type="{LoginServiceImpl}">
        <Property name="timeout" value="3000"/>
    </Object>
    
    <Object type="{LoginAction}"/>
    
</mx:Object> 

These special tags give you some additional features that are not available when using normal tags like in the first example. Both approaches have pros and cons:

Advantages of normal MXML tags:

Advantages of Parsley MXML tags:

3.3 XML Configuration Files

External XML files may be an adequate alternative to MXML if:

Of course you may also chose to only externalize parts of your configuration to XML files and stick with MXML for wiring your core services. See 3.5 Combining multiple Configuration mechanisms for details.

Using the same two example classes as shown in the MXML section above, this is how the XML configuration file would look like:

<objects 
    xmlns="http://www.spicefactory.org/parsley"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.spicefactory.org/parsley 
        http://www.spicefactory.org/parsley/schema/2.0/parsley-core.xsd"
    >
    <object type="com.bookstore.services.LoginServiceImpl">
        <property name="timeout" value="3000"/>
    </object>
    
    <object type="com.bookstore.services.LoginServiceImpl"/>
</objects>

In general XML configuration looks very similar like MXML configuration with Parsleys MXML tags. Under the hood XML tags and MXML tags map to the same framework classes. The main difference is that we follow XML naming conventions, so the tags are not capitalized and attribute names use dashes and not camel case (e.g. target-property instead of targetProperty).

Again initialization is just a one liner, assuming you saved the file as config.xml:

XmlContextBuilder.build("config.xml");

Compiling classes configured in XML

One thing you need to be aware of is that in contrast to MXML configuration the classes you use in the configuration file will not be compiled into your SWC or SWF if you don't use them explicitly in your code. This might happen quite often since it is good practice to program against interfaces and only declare the concrete implementation in the container configuration.

There are basically three choices to solve this:

3.4 ActionScript Configuration

This configuration mechanism may seem unfamiliar if you only knew Flex IOC containers so far. It is somehow similar to Spring JavaConfig. It allows you to create the objects that should be managed by Parsley in code. Let's again use the two classes from the MXML example and add them to the IOC Container:

package com.bookstore.config {

class BookStoreConfig {

    public const action:LoginAction = new LoginAction();
    
    public function get service () : LoginServiceImpl {
        var service:LoginServiceImpl = new LoginServiceImpl();
        service.timeout = 3000;
        return service;    
    }

}
}

Again we set the timeout property, this time with ActionScript. Note that it does not matter if you define the objects as a var, a const or an implicit getter function. The objects these properties hold will all be added to the IOC container.

Of course intialization is again just a one liner:

ActionScriptContextBuilder.build(BookStoreConfig);

This configuration mode allows you to add metadata:

[ObjectDefinition(singleton="false")]
public function get service () : LoginServiceImpl {
    var service:LoginServiceImpl = new LoginServiceImpl();
    service.timeout = 3000;
    return service;    
}

In the example above the container would call the getter function each time this object is requested. The default for the singleton property is true, so without any metadata tags Parsley would call this method only once and then cache the returned object internally and reuse the same instance for all subsequent injections.

3.5 Combining multiple Configuration mechanisms

Although you may prefer to stick with a single configuration mechanism for most simple applications, you are not forced to do so. You can use any combination of the configuration styles presented in this chapter, and even create your own.

First you may want to split configuration between multiple files/classes of the same configuration style. In this case you can just use the buildAll method of the entry points shown in previous sections:

FlexContextBuilder.buildAll([BookStoreServices, BookStoreActions], this);
XmlContextBuilder.buildAll(["services.xml", "actions.xml"]);
ActionScriptContextBuilder.buildAll([BookStoreServices, BookStoreActions]);

But finally you can also mix them any way you want using the CompositeContextBuilder class:

var builder:CompositeContextBuilder = new DefaultCompositeContextBuilder(this);
FlexContextBuilder.merge(BookStoreConfig, builder);
XmlContextBuilder.merge("logging.xml", builder);
builder.build();	

It's still simple: You just create an instance of the CompisiteContextBuilder class and pass it to the merge methods of the various context builder classes.

In all these examples the final result is a single Parsley Context. For all the IOC Container features like Dependency Injection or Messaging it does not matter at all how you split object configuration between files and classes, the result is always the same as if they were configured in a single file.

However for large and complex applications you may want to create modular Contexts, meaning that the multiple configuration artifacts are not merged into a single Context, so that they can be loaded and unloaded on demand. For modular applications you may want to read 8 Building Modular Applications.

Finally if you want to create your own configuration mechanism and seamlessly integrate it with existing configuration styles, you can create implementations of the ObjectDefinitionBuilder interface and pass those implementations to CompositeContextBuilder.addBuilder. See 11 Extending the Framework for details.