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:

Metadata Inheritance

Judging from observations these are the rules the mxmlc compiler uses for deciding on metadata inheritance:

Per default Parsley does nothing on top of these inheritance rules. In particular it only processes the class that gets configured and not the entire inheritance tree. That would be impractical due to performance reasons, as reflection in current Flash Players is quite slow. This means that any metadata on class level for example would be lost in subclasses. Since this might be undesirable in some cases where the class has a lot of verbose [ManagedEvents] declarations for example, the framework offers the option to explicitly request to process the superclass or the implemented interfaces of a particular class:

[ProcessSuperclass][ProcessInterfaces]
public class SomeClass {

When using [ProcessSuperclass] only the immediate superclass will be processed, again for performance reasons. The superclass itself could also use this tag if you want the framework to move even higher in the inheritance tree. When the superclass gets processed its tags will be added to those available on the subclass. This means that when using this feature you cannot override a metadata tag from the superclass in the subclass, as both would be used in this case. If you want to override tags, you cannot use [ProcessSuperclass].

When using [ProcessInterfaces] all interfaces implemented by the class will be processed in addition to the class itself.

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="Publish" />
<keep-as3-metadata name="Subscribe" />
<keep-as3-metadata name="PublishSubscribe" />
<keep-as3-metadata name="Factory" />
<keep-as3-metadata name="Init" />
<keep-as3-metadata name="Destroy" />
<keep-as3-metadata name="Observe" />
<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="Command" />
<keep-as3-metadata name="CommandComplete" />
<keep-as3-metadata name="CommandResult" />
<keep-as3-metadata name="CommandError" />
<keep-as3-metadata name="CommandStatus" />
<keep-as3-metadata name="ResourceBinding" />
<keep-as3-metadata name="Selector" />
<keep-as3-metadata name="Target" />
<keep-as3-metadata name="Autoremove" />
<keep-as3-metadata name="Internal" />
<keep-as3-metadata name="ObjectDefinition" />
<keep-as3-metadata name="DynamicObject" />

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 6 Messaging for details on these features.

We now have to tell the container to manage these classes and create the an MXML configuration file.

<Objects 
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:services="com.bookstore.services.*"
    xmlns:actions="com.bookstore.actions.*"
    xmlns="http://www.spicefactory.org/parsley"
    >
        
    <fx:Declarations>
    
        <services:LoginServiceImpl timeout="3000"/>

        <actions:LoginAction/>
        
    </fx:Declarations>
    
</Objects> 

In addition to the metadata tags you can use these MXML tags for additional configuration, like the timeout value in the example above. The example uses a special root tag from the Parsley namespace provided by the framework. It allows the use of properties within the configuration class. Earlier versions simply used fx:Object as a root tag which is still supported, but does not allow the use of external properties.

Framework Initialization

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

<parsley:ContextBuilder config="{BookStoreConfig}"/>

In many applications the simple tag shown above could be the only direct dependency on the Parsley framework. To initialize the application you can use [Init] metadata tags on methods of classes that should execute logic on application startup. See 7.5 Object Lifecycle Methods 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.

Context Description for Log Output

If you want to have control over the description for a particular Context in log statements, you can simply set it in the ContextBuilder tag:

<parsley:ContextBuilder config="{MyConfig}" description="Main"/>

The toString output for the Context will then be:

[Context(Main)]

If you do not set the description explicitly it will be generated from the names of the configuration artifacts the Context was configured with, and thus could eventually be quite long:

[Context(FlexConfig{MainConfig,ServiceConfig},XmlConfig{logging.xml},RuntimeConfig{2 instance(s)})]

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:

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

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:

Dynamic Objects

Apart from the <Object> tag already introduced you could alternatively use the <DynamicObject> tag. It allows the same type of child tags as the <Object> tag:

<DynamicObject type="{LoginServiceImpl}">
    <Property name="timeout" value="3000"/>
</DynamicObject>

In contrast to the <Object> which just creates one instance and reuses it for subsequent injection requests, this tag creates a new instance for each request. So each object or view depending on this service would get its own instance. The lifecycle of such a dynamic object gets synchronized with the object it is injected into. So when the target object gets removed from the Context, the injected dynamic object will also get removed, since it was specifically created for that one target and is no longer needed.

In addition for serving as a source for injections, such a dynamic object can also be created programmatically based on the MXML configuration and then disposed by the application at any point in time. Details for programmatic access can be found in 7.7 Dynamic Objects.

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.7 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.3/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).

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

XmlContextBuilder.build("config.xml");

If you are using XML configuration in Flex you can alternatively use a tag for initialization:

<parsley:ContextBuilder>
    <parsley:XmlConfig file="config.xml"/>
</parsley:ContextBuilder>

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 Runtime Configuration

Added in version 2.2 this configuration mechanism allows to specify instances that should be part of the container at runtime:

<parsley:ContextBuilder>
    <parsley:FlexConfig type="{ServiceConfig}"/>
    <parsley:FlexConfig type="{ControllerConfig}"/>
    <parsley:XmlConfig file="logging.xml"/>
    <parsley:RuntimeConfig instances="{[instance1, instance2]}"/>
</parsley:ContextBuilder>

If you need to specify id's then you could alternatively use nested child tags:

<parsley:ContextBuilder>
    <parsley:FlexConfig type="{ServiceConfig}"/>
    <parsley:FlexConfig type="{ControllerConfig}"/>
    <parsley:XmlConfig file="logging.xml"/>
    <parsley:RuntimeConfig>
        <parsley:Instance id="obj1" instance="{instance1}"/>    
        <parsley:Instance id="obj2" instance="{instance2}"/>    
        <parsley:Instance id="obj3" instance="{instance3}"/>    
    </parsley:RuntimeConfig>
</parsley:ContextBuilder>

The difference between objects added with the RuntimeConfig tag and DynamicObjects added at a later time is that the former are actually root object definitions which are injectable into other objects since they are specified at Context construction time.

You can even use the regular <Object> tags inline now:

<parsley:ContextBuilder>
    <parsley:FlexConfig type="{ServiceConfig}"/>
    <parsley:FlexConfig type="{ControllerConfig}"/>
    <parsley:XmlConfig file="logging.xml"/>
    <parsley:RuntimeConfig>
        <parsley:Instance id="obj1" instance="{instance1}"/>    
        <parsley:Instance id="obj2" instance="{instance2}"/>    
        <parsley:Object id="obj3" type="{LoginInterceptor}"/> 
            <parsley:MessageInterceptor method="intercept" type="{LoginEvent}"/>
        </parsley:Object>    
    </parsley:RuntimeConfig>
</parsley:ContextBuilder>

You can also specify existing instances with the configuration DSL:

ContextBuilder.newBuilder()
    .config(FlexConfig.forClass(ServiceConfig))
    .config(FlexConfig.forClass(ControllerConfig))
    .config(XmlConfig.forFile("logging.xml"))
    .object(instance1, "id1")
    .object(instance2, "id2")
    .build();

3.5 Configuration DSL

Added in version 2.3 this configuration option allows to specify most of the features you usually specify with tags (MXML, XML, Metadata) in code with a fluent syntax that allows to add logic to the configuration. The DSL spans multiple levels of configuration, it can be used to create an entire Context from scratch, but it can also be used to create object definitions in code and then combine those with the other configuration mechanisms. Since it is useful for many types of configuration tasks it is now also getting used by nearly all major extension points. Thus when building a custom metadata tag for example, you can use this convenient DSL for adding functionality to an object.

You can refer to 12 Extending the Framework for use of the DSL in extensions. This chapter is about basic configuration tasks for applications, so will list a few relatively simple examples.

Creating an empty Context

var context:Context = ContextBuilder.newBuilder().build();

May seem pointless, but you can still use this Context to dynamically add objects later.

Specifying configuration classes and files

ContextBuilder.newBuilder()
    .config(FlexConfig.forClass(BookStoreServices))
    .config(FlexConfig.forClass(BookStoreActions))
    .config(XmlConfig.forFile("logging.xml"))
    .build();

Adding existing instances to a Context

var instance1:Object = ...;
var instance2:Object = ...;

ContextBuilder.newBuilder()
    .config(FlexConfig.forClass(MainConfig))
    .object(instance1, "id1")
    .object(instance2, "id2")
    .build();

Specifying options for the ContextBuilder

var viewRoot:DisplayObject = ...;
var parent:Context = ...;

ContextBuilder.newSetup()
    .viewRoot(viewRoot)
    .parent(parent)
    .description("Root")
    .scope("window")
    .messageSettings()
        .unhandledError(ErrorPolicy.RETHROW)
    .viewSettings()
        .autoremoveComponents(false)
    .newBuilder()
        .config(FlexConfig.forClass(RootConfig))
        .config(XmlConfig.forFile("logging.xml"))
        .build();

Creating object definitions programmatically

var contextBuilder:ContextBuilder = ContextBuilder.newBuilder();

var objectBuilder:ObjectDefinitionBuilder 
        = contextBuilder.objectDefinition().forClass(SomeClass);

objectBuilder
    .property("dependency")
        .injectByType();

objectBuilder
    .property("dispatcher")
         .messageDispatcher();
         
objectBuilder
    .method("handleLogin")
        .messageHandler()
            .type(LoginMessage)
            .scope("local");
            
objectBuilder
    .asDynamicObject()
        .id("myObject")
        .register();
            
contextBuilder
    .config(FlexConfig.forClass(MainConfig))
    .build();

This is a bit more verbose, but still convenient. Note that calling register on the object builder adds the definition to the Context, so it will be available in addition to all objects defined in the MainConfig MXML configuration.

So the above is fully equivalent to adding the following MXML declaration to MainConfig:

<DynamicObject id="myObject" type="{SomeClass}">
    <Property name="dependency" typeRef="{SomeOtherClass}"/>
    <MessageDispatcher property="dispatcher"/>
    <MessageHandler method="handleLogin" type="{LoginMessage}" scope="local"/>
</DynamicObject>

Which in turn is equivalent to using the [Inject], [MessageDispatcher] and [MessageHandler] metadata tags in the class definition.

3.6 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. The configuration classes are plain ActionScript, not talking to Parsely APIs, thus this mechanism is intended to be used in cases where you are able to configure the object solely with metadata tags. If you need to specify features like a message handler or an injection point programmatically, you should prefer the 3.5 Configuration DSL.

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);

Or (in Flex) with an MXML tag:

<parsley:ContextBuilder config="{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.7 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:

<parsley:ContextBuilder>
    <parsley:FlexConfig type="{BookStoreServices}"/>
    <parsley:FlexConfig type="{BookStoreActions}"/>
</parsley:ContextBuilder>
XmlContextBuilder.buildAll(["services.xml", "actions.xml"]);
ActionScriptContextBuilder.buildAll([BookStoreServices, BookStoreActions]);

But finally you can also mix them any way you want:

<parsley:ContextBuilder>
    <parsley:FlexConfig type="{BookStoreServices}"/>
    <parsley:FlexConfig type="{BookStoreActions}"/>
    <parsley:XmlConfig file="logging.xml"/>
</parsley:ContextBuilder>

or programmatically using the configuration DSL:

ContextBuilder.newBuilder()
    .config(FlexConfig.forClass(BookStoreServices))
    .config(FlexConfig.forClass(BookStoreActions))
    .config(XmlConfig.forFile("logging.xml"))
    .build();

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 9 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 ConfigurationProcessor interface. See 12 Extending the Framework for details.

3.8 Configuration Properties

Since version 2.3 Parsley supports the use of properties, either loaded from external files at runtime or declared inline.

Supported Syntax

The supported syntax allows for key/value pairs delimited with '=', multiline property values with '\' at the end of the line and comments with '#' at the beginning of the line:

prop1 = value1
prop2=value2

#This is a comment which will be ignored
prop2 = This is a property value that \
spans more than just one line

For the names of the properties there is a restriction though: Those have to be names which would also be valid AS3 property names. This means you cannot use '.' in property names like in Ant-style property files for example. Instead you could use '_' as delimiter in long property names.

Like shown in the sample above the use of spaces around the '=' delimiter does not make any difference as both property name and value will be trimmed.

Using Properties in MXML Configuration

Using properties in MXML configuration requires the use of the new <Objects> root tag, which was added in version 2.3:

<Objects 
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns="http://www.spicefactory.org/parsley"
    >
    
    <fx:Script>
        <![CDATA[
            import com.mycompany.bookstore.BookstoreService;
        ]]>
    </fx:Script>
    
    <fx:Declarations>
    
        <Object type="{BookstoreService}">
            <Property name="serviceUrl" value="{properties.serviceUrl}"/>
        </Object>
    
    </fx:Declarations>
    
</Objects>

Using Properties in XML Configuration

In XML files the Ant-style syntax ${someProperty} can be used:

<objects xmlns="http://www.spicefactory.org/parsley">
    
    <object type="com.mycompany.bookstore.BookstoreService">
        <property name="serviceUrl" value="${serviceUrl}"/>
    </object>
    
</Objects>

Here you don't need the properties. prefix like in MXML configuration.

External Property Files

If you want to load the properties at runtime you can use the PropertiesFile tag:

<parsley:ContextBuilder>
    <parsley:PropertiesFile file="bookstore.properties"/>
    <parsley:FlexConfig type="{BookStoreConfig}"/>
    <parsley:XmlConfig file="logging.xml"/>
</parsley:ContextBuilder>

Make sure you declare the property file before any configuration classes or files that use these properties, as the builder processes the child tags in the order they are specified.

Property Files compiled into the Application

Alternatively, if you want to maintain properties in a separate file, but prefer to compile them into the application rather than loading them at runtime, you can use the PropertiesString tag:

<fx:String id="props" source="bookstore.properties"/>

<parsley:ContextBuilder>
    <parsley:PropertiesString source="{props}"/>
    <parsley:FlexConfig type="{BookStoreConfig}"/>
    <parsley:XmlConfig file="logging.xml"/>
</parsley:ContextBuilder>

Inline Property Declarations

Finally you can also define properties directly within the builder tag (and of course can combine those with external properties).

<parsley:ContextBuilder>
    <parsley:PropertiesObject>
        <fx:Object 
            serviceUrl="http://www.company.com/services/" 
            mediaPath="images"
        />
    </parsley:PropertiesObject>
    <parsley:FlexConfig type="{BookStoreConfig}"/>
    <parsley:XmlConfig file="logging.xml"/>
</parsley:ContextBuilder>

Configuration DSL

If you don't use the MXML tags for building a Context, all the variants shown above are also available in the configuration DSL:

ContextBuilder
    .newBuilder()
        .config(Properties.forFile("bookstore.properties"))
        .config(FlexConfig.forClass(BookStoreConfig))
        .build()