Building a Flex Application with the Parsley Framework

After my recent explorations of “Swiz”, and “Spring ActionScript” (1,2,3), I decided to take the new version of the Parsley framework for a test drive, and build the Parsley version of inSync: the simple Contact Management application I often use to try out and demonstrate different features and techniques in Flex and Adobe AIR.

Parsley is primarily a Dependency Injection framework. It also offers a very interesting messaging infrastructure. I won’t get into the details of dependency injection here: My previous Swiz and Spring ActionScript articles provide some background information, and there are also plenty of detailed resources out there.

If you just want to run the application and dive into the code, here are the links:

  • Click here to run the application.
  • Click here to view the source code.

Object Configuration

Parsley allows you to configure the core objects of your application (the objects other components depend on) in MXML (like Swiz), in XML (like Spring ActionScript), in ActionScript, or using any combination of these approaches. You can also extend the framework and create your own configuration mechanism.

For the inSync application, I used a simple MXML configuration (Config.mxml) defined as follows:

<?xml version="1.0" encoding="utf-8"?>
<Object xmlns="*" xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:services="insync.parsley.services.*">

    <mx:RemoteObject
            id="contactRO"
            destination="contacts"
            endpoint="http://localhost:8400/samples/messagebroker/amf"
            showBusyCursor="true" />

    <services:ContactService />

</Object>

Note: In a real life application, you would not want to hardcode the endpoints of your services in your source code. You could use the XML configuration option to configure your endpoints in a more “externalized” fashion. More on this topic here.

Framework Initialization

You initialize the Parsley framework using the ContextBuilder class corresponding to the configuration approach you chose. Here is the main application file for the inSync application. Parsley is initialized in the preinitialize event of the application.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:views="insync.parsley.views.*"
	paddingTop="0" paddingLeft="0" paddingRight="0" paddingBottom="0"
	preinitialize="FlexContextBuilder.build(Config)">

	<mx:Script>
		<![CDATA[
			import org.spicefactory.parsley.flex.FlexContextBuilder;
		]]>
	</mx:Script>

	<mx:Style source="styles.css" />

	<views:MainView />

</mx:Application>

Dependency Injection

Parsley supports constructor injection, method injection, and property injection (by type or by id).

In the following example (ContactForm.mxml), the framework will inject a specific implementation of the IContactService interface. In this case, the ContactService instance created in Config.mxml will be injected. This is an example of injection by type. Coding to the interface allows us to keep the view decoupled from a specific implementation of IContactService.

Note: Parsley doesn’t force you to use any specific design pattern. For simplicity in this sample application, I inject a service directly into the view. The use of an interface provides some level of decoupling, but you can of course use other patterns (like the Presentation Model) to achieve a greater level of abstraction. The Dependency Injection and Messaging infrastructure of Parsley will make the implementation of these patterns easier.

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
	addedToStage="dispatchEvent(new Event('configureIOC', true))">

	<mx:Script>
		<![CDATA[

		import insync.parsley.model.Contact;
		import insync.parsley.services.IContactService;

		[Inject]
		public var service:IContactService;

		[Bindable]
		public var contact:Contact;

		private function save():void
		{
			contact.firstName = firstName.text;
			contact.lastName = lastName.text;
			contact.email = email.text;
			service.save(contact);
		}

		private function remove():void
		{
			service.remove(contact);
		}

		]]>
	</mx:Script>

	<mx:Form>
		<mx:FormItem label="Id">
			<mx:TextInput text="{contact.id}" enabled="false"/>
		</mx:FormItem>
		<mx:FormItem label="First Name">
			<mx:TextInput id="firstName" text="{contact.firstName}"/>
		</mx:FormItem>
		<mx:FormItem label="Last Name">
			<mx:TextInput id="lastName" text="{contact.lastName}"/>
		</mx:FormItem>
		<mx:FormItem label="Email">
			<mx:TextInput id="email" text="{contact.email}"/>
		</mx:FormItem>
	</mx:Form>

	<mx:HBox left="12" bottom="12">
		<mx:Button label="Save" click="save()"/>
		<mx:Button label="Delete" click="remove()"/>
	</mx:HBox>

</mx:Canvas>

Note that in order to get its dependencies injected when it’s added to the stage, a view has to dispatch the “configureIOC” event.

Messaging

Parsley provides a generic Messaging infrastructure that allows you to exchange messages between objects in a decoupled, flexible, and easy-to-use manner:

  • The event dispatcher and the event handler don’t know about each other.
  • The event dispatcher and the event handler are decoupled from the framework: You dispatch events the Flex way.

Let’s look at the Search feature inSync as an example:

  • The Toolbar class includes a simple TextInput that allows the user to specify a search criterion.
  • The ContactList class displays the Search Results in a DataGrid.

The Toolbar class is defined as follows (non essential code removed for clarity):

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%"
	addedToStage="dispatchEvent(new Event('configureIOC', true))">

	<mx:Metadata>
		[ManagedEvents("search")]
	</mx:Metadata>

	<mx:Script>
		<![CDATA[
			import insync.parsley.events.SearchEvent;
		]]>
	</mx:Script>

	<mx:Label text="Search:" top="18" right="164"/>

	<mx:TextInput id="searchBox" right="0" top="16"
		change="dispatchEvent(new SearchEvent(SearchEvent.SEARCH, searchBox.text))"/>

</mx:Canvas>

Note that it dispatches a SearchEvent when the content of the search input field changes.

That event is defined as a managed event (using the ManagedEvents annotation), meaning that the framework will make sure that all the parties interested in that event will receive it.

How do you register as a listener for a managed event? You simply annotate a function with [MessageHandler], and it automatically becomes an event handler for that event, regardless of the display object hierarchy or whether the event bubbles or not.

Here is how it’s done in ContactList (non essential code removed for clarity):

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%"
	addedToStage="dispatchEvent(new Event('configureIOC', true))">

	<mx:Script>
		<![CDATA[

			import mx.controls.Alert;
			import mx.collections.ArrayCollection;
			import mx.rpc.events.FaultEvent;
			import mx.rpc.AsyncToken;
			import mx.rpc.AsyncResponder;
			import mx.rpc.events.ResultEvent;

			import insync.parsley.events.SearchEvent;
			import insync.parsley.services.IContactService;

			[Inject]
			[Bindable]
			public var service:IContactService;

			[Bindable]
			public var contacts:ArrayCollection;

			[MessageHandler]
			public function searchHanlder(event:SearchEvent):void
			{
				service.getContactsByName(searchStr).addResponder(new AsyncResponder(getContacts_result, faultHandler));
			}

			private function getContacts_result(event:ResultEvent, token:AsyncToken):void
			{
				contacts = event.result as ArrayCollection;
			}

			private function faultHandler(event:FaultEvent):void
			{
				Alert.show(event.fault.faultString);
			}

		]]>
	</mx:Script>

	<mx:DataGrid id="dg" dataProvider="{contacts}" width="100%" top="0" left="0" right="0" bottom="0"/>

</mx:Canvas>

With the simple [MessageHandler] annotation, the handler will be invoked every time an event of the function argument’s data type is dispatched in the application. If you need finer control, you can use the selector notation to specify the event type. For example in MainView.mxml, we register the contactDeleted function as a handler for the ContactEvent.DELETED event as follows.

[MessageHandler(selector="contactDeleted")]
public function contactDeletedHandler(event:ContactEvent):void
{
}

There is more to the Messaging capabilities of the Parsley framework. For example, you can use [MessageBinding] to bind a property of an object to the property of an event.

[MessageBinding(messageProperty="result",type=" mx.rpc.events.ResultEvent")]
public var contacts:ArrayCollection;

Installation Instructions

  1. Download the project here
  2. Import it in Flex Builder
  3. Run the application. The application is configured to use the MockService (ContactServiceMock) by default, so it will run without any back-end.

If you want to use the Remoting service instead of the MockService:

  1. Replace <services:ContactServiceMock/> with <services:ContactServiceRemote/> in Config.mxml
  2. Install the BlazeDS turnkey server.
  3. Download insync-parsley-java.zip, and unzip it on your local file system.
  4. Copy classes/insync to blazeds/tomcat/webapps/samples/WEB-INF/classes/insync.
  5. Add the following destination to blazeds/tomcat/webapps/samples/WEB-INF/flex/remoting-config.xml:
  6. <destination id="contacts">
            <properties>
                <source>insync.dao.ContactDAO</source>
                <scope>application</scope>
            </properties>
    </destination>
    

  7. Copy insync/sampledb/insync to blazeds/sampledb/insync
  8. Edit server.properties in blazeds/sampledb, and modify the file as follows to add the insync database to the startup procedure.

    server.database.0=file:flexdemodb/flexdemodb
    server.dbname.0=flexdemodb
    server.database.1=file:insync/insync
    server.dbname.1=insync
    server.port=9002
    server.silent=true
    server.trace=false
    

  9. Start the database (startdb.bat or startdb.sh)
  10. Start BlazeDS
  11. Run the application
  • sitron

    nice!
    any reason it doesn’t include a “summary” section?
    i got used to this little piece of subjective appreciation :)

  • supper flex examples mysql db

  • I like this function ver much

    “Parsley provides a generic Messaging infrastructure that allows you to exchange messages between objects in a decoupled, flexible, and easy-to-use manner”

  • Pingback: 20/07/2009 « Robertopriz’s Weblog()

  • Very easy to learn with your example!

    Thanks a lot :)

  • thanx very much

  • Jeffrey Mason

    Having a bit of trouble importing to Flash Builder 4. I’ve tried several import methods to no avail.

    Any suggestions, please.

  • I cant understand Parsley much, when will you use [inject],messageHandler and manageevents? im so confused..

  • Спасибо. было очень интересно.

  • Lee

    Nice icons in the app. Would you mind if I ask where you got the icons? I guess I already asked.

    I need a few good sources for free icons, as my design skills are not up to par.

    Thanks,

    Lee

  • Lee

    Sorry for the last message. Let me answer my own question:
    Those nice icons are available from:
    http://www.famfamfam.com/

    I realize now why the icons looked so familiar.

    Lee

  • Pingback: jexchen » Blog Archive » Flash、Flex资源收集之十全大补()

  • awesome example. really glad to finally read through it. Now I am looking forward to giving the framework a try. I really like the ManagedEvents and MangeHandler. This model is really close to a setup that I have used for a while on my own. I like the fact that it removes the need to write the addEventListener stuff in the class that needs to handle the event. Nice!

    Hope you plan on more examples in the near term.

    Rock On!
    -Matthew

  • Very interesting site. Hope it will always be alive!,

  • Very nice example – just one suggestion to bring it up to date: Pam Beesly is now Pam Halpert :)

  • Pingback: Borre Wessel – Flex in the enterprise » Presenting at the Adobe RIA user group London()

  • Thank you admin goood

  • [url=http://fyfk.ru/]анальное порно[/url]

  • Pingback: AS3常用类库 | RIA飞鹰工作室()

  • Priyank Namdeo

    This is excellent example to learn Parsley in seconds. Well done! Keep posting new (simple) threads!

  • Agish

    Thanks ..

  • Vardan

    Hi Christophe,

    Great tutorial.
    A question.
    What is the url/context to run it from the browser if I use ?

    Thanks again for your fantastic tutorial.

  • Pingback: Parsley Framework good examples | RIA Developer()

  • Rakesh Sivan

    Thanks for sharing your knowledge in Parsley framework and also the demo application. Its a pleasure to watch your lectures in Adobe Developer Connection, since there will be something quite innovative, kind of out-of-box-thinking stuff in your videos.. Keep up the good work.

  • Why didn’t you go the whole hog and integrate Pimento with Parsley? If you haven’t done that yet, I may have a go at adapting this example to use that rather than a straight JDBC style server-side.

  • Pingback: A first take on Flex SpiceFactory projects Pimento and Parsley « All things Grails and RIA()

  • Rinos

    Hi,

    I have configured and installed as instruct above but the application is running but when i register a new user it says sending failed msg and not saving data in to db. and i cant get any data to datgrid from database. can any body help me to get data from database. i am new to this environment.

  • Can these flex applications maybe work with wordpress? just a thought…

  • http://automobileinsurancetexas.net/

    The Savings You Want. Save with our competitive rates and extensive discount options. Compare multiple quotes from independent agents who represent many companies – not just one.

  • Thanks, I’ve been looking for something like this.
    Maybe it will help as a natural remedies for hemroids.

  • Pingback: Flash、Flex资源收集之十全大补 | Wang Jun's Blog()

  • Hi,

    I get the .zip and import it in flex this work correctly.

    When I run this with an ANT task, this build successfully but when I run the Application throught firefox I get two errors:

    1)
    ReferenceError: Error #1065: La variable org.spicefactory.parsley.flex::FlexContextBuilder n’est pas définie.
    at main/preinitHandler()[C:\env\myworkspace\glm-flex\src\main.mxml:22]
    at main/___main_Application1_preinitialize()[C:\env\myworkspace\glm-flex\src\main.mxml:4]
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at mx.core::UIComponent/dispatchEvent()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:9298]
    at mx.core::UIComponent/initialize()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:5367]
    at mx.core::Container/initialize()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2526]
    at mx.core::Application/initialize()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Application.as:846]
    at main/initialize()[C:\env\myworkspace\glm-flex\src\main.mxml:0]
    at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::childAdded()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:2009]
    at mx.managers::SystemManager/initializeTopLevelWindow()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:3234]
    at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::docFrameHandler()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:3064]
    at mx.managers::SystemManager/docFrameListener()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:2916]

    2)

    VerifyError: Error #1014: La classe flexlib.containers::SuperTabNavigator est introuvable.

    at global$init()
    at ()[C:\env\myworkspace\glm-flex\src\main.mxml:0]
    at Function/http://adobe.com/AS3/2006/builtin::call()
    at mx.core::ComponentDescriptor/get properties()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\ComponentDescriptor.as:241]
    at mx.core::Container/createComponentFromDescriptor()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:3557]
    at mx.core::Container/createComponentsFromDescriptors()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:3493]
    at mx.core::Container/createChildren()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2589]
    at mx.core::UIComponent/initialize()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:5370]
    at mx.core::Container/initialize()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2526]
    at mx.core::UIComponent/http://www.adobe.com/2006/flex/mx/internal::childAdded()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:5267]
    at mx.core::Container/http://www.adobe.com/2006/flex/mx/internal::childAdded()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:3305]
    at mx.core::Container/addChildAt()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2217]
    at mx.core::Container/addChild()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2140]
    at mx.core::Container/createComponentFromDescriptor()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:3681]
    at mx.core::Container/createComponentsFromDescriptors()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:3493]
    at mx.core::Container/createChildren()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2589]
    at mx.core::UIComponent/initialize()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:5370]
    at mx.core::Container/initialize()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2526]
    at mx.core::Application/initialize()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Application.as:846]
    at main/initialize()[C:\env\myworkspace\glm-flex\src\main.mxml:0]
    at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::childAdded()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:2009]
    at mx.managers::SystemManager/initializeTopLevelWindow()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:3234]
    at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::docFrameHandler()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:3064]
    at mx.managers::SystemManager/docFrameListener()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:2916]

    Here is my build.xml:

    Deleting some flex’s files from flex project

    Deleting some flex’s files from ${glm-deploy.home}

    <!–
    en_US
    locale/{locale}
    mainBundle
    anotherBundle
    bin-debug/Resources_en_US.swf
    –>

    Compiling the Flex code

    Creating the HTML template

    Thanks in advance for your help.

    Calavero

  • sai

    Helped!!

  • subba

    Thanks, for great example

  • Scott Schafer

    Thanks for this tutorial.

    It all looks good, except that this line bugs me: [ManagedEvents(“addContact,search”)]

    It seems wrong to me to define the event names as a constant and then hard code them in this file. I’d like to do something like the following instead, but I can’t seem to get it to work.

    Any ideas?

  • Manasa

    Nice Tutorial. Goes really well with the manual in Parsley’s documentation.

    I just started learning Parsley. Im having difficult getting Message Handlers. So in the given Contact Management application, ToolBar view dispatches the event “search” and ContactList view has a message handler for it. This part is clear.

    I defines a message handler for the same “Search” event in main.mxml. But this method did not get invoked :(
    are there any restrictions on which objects can have message handlers for events?

    thanks in advance ..

  • Ashish

    Thanks for such a nice example.
    But “Managed event” part of it kinda looks little vulnerable, especially when multiple objects of a class containing resultHandler are active in the same scope… In that case every object will respond to the event for which the handler is written and unnecessary updates will be made to the unintended object…. I hope I am making sense here…

  • a

    cxcsf

  • Hi,
    Thanks for the example. I have a small doubt.
    In the example, config.mxml you have added ContactServiceMock and in views you have
    [Inject]
    [Bindable]
    public var service:IContactService

    I guess it means service in views will be intialized to ContactServiceMock Object.

    In case I want to intialize service object with ContactServiceRemote, then i replace ContactServiceMock with ContactServiceRemote in Config.mxml.

    Now, If I have two different views where one needs ContactServiceRemote and one needs ContactServiceMock then how can we add both services in Config.mxml.

    Thanks a ton in advance for the reply.

  • Hi,

    I got the answer for my previous question. Looked into Parsley Docs.

    Thanks

  • eq

    How to load data on application startup, let say in your example above when the application starts/display, i want to display list of contacts without typing in anything in search field.

    I tried few things but no success yet.
    I tried putting code in creationComplete=”search(….
    but i noticed that the service is null.

    When i type % in search field it DOES display contacts, which means that during preinitialize, service was not initialized, right? or am i missing something

    A good coded example would be very helpfull or is this even possible with parsley?

    thanks

  • eq

    Never mind, i figured it out,
    1) dispatched an event in application complete
    2) added event listener in the constructor
    3) handle that event in the controller
    4) executeservicecall to call the server

  • Great Article, Christopher. I have also found this very interesting article about Silent errors in Parsley http://stageaction.wordpress.com/2011/11/17/flex-parsley-silent-failure/

  • Marksion

    Just start up learning Parsley, seems to be a good fw!

  • Wow that was strange. I just wrote an incredibly long comment
    but after I clicked submit my comment didn’t show
    up. Grrrr… well I’m not writing all that over again. Anyways,
    just wanted to say fantastic blog!

  • Wow, this paragraph is nice, my sister is analyzing such things, thus I am going to let know her.

  • 27

    Wow, amazing blog layout! How long have you been blogging
    for? you make blogging look easy.The overall look of your web site is excellent,
    let alone the content!

  • That is very attention-grabbing, You are a very professional blogger.
    I’ve joined yoyr rss feed and sit up for searching ffor
    extra of your fantastic post. Also, I have shared yourr website in my socfial networks

  • A pair of metallic gold or silver toned sandals would be glamorous, and go well with everything.
    We simply love HardX. Also sure to please romantic wives-to-be,
    Jewel gowns boast effortless youthful elegance, classic silhouettes paired with modern trendy
    embellishment and traditional laces, creating a sense of heightened romanticism.

    Hard X now, above all, have a positive go-getter outlook and make a real effort in pursuing your dream of a fashion modeling career with everything you’ve
    got.

  • The position of a sofa is critical in determining how the ‘qi’
    or energy will flow in the living room. The innovative design of each Home Reserve sectional sofa allows you to select just the pieces you need to create the perfect seating
    arrangement for any room. For unification it is important to consider framing and matting everything alike
    when hanging these together.

  • If this is you, try going to Concept CM2 the first night here.
    Most of the advices preach about basic body language but a woman notices you in great
    detail. Each country has different values and beliefs so you will want to
    make sure it is compatible with what it is that you believe in.

  • Howdy! I’m at work browsing your blog from my new iphone!
    Just wanted to say I love reading your blog and look forward to all your posts!
    Keep up the superb work!

  • Hi there! I’m at work browsing your blog from my new apple iphone!
    Just wanted to say I love reading through your blog and look forward
    to all your posts! Keep up the great work!

  • Cheap celine handbags
    I’ll immediately snatch your rss as I can not to find your e-mail subscription hyperlink or e-newsletter service.
    Do you’ve any? Please permit me recognize in order that I
    may just subscribe. Thanks.

  • I don’t know whether it’s just me or if everybody else experiencing problems with your blog.

    It appears as though some of the written text within your posts are running off the screen. Can someone else please
    provide feedback and let me know if this is happening to them as
    well? This could be a problem with my internet browser because I’ve had this happen previously.
    Kudos

css.php