This is part 8.
In Part 3, I showed how to set up Parsley and showed a basic injection example.
In Part 4, I showed how to send messages using Parsley that do not extend the Event class.
In Part 5, I showed how to send messages using Flex Events.
In Part 6, I showed nested contexts and object lifecycle methods.
In Part 7, I showed Decoupled Bindings
This article builds upon what was covered in the previous examples, so if you haven't seen them, I encourage you to start with at the beginning of this series. This article focuses on Parsley's Dynamic Commands and Dynamic Objects.
Parsley’s Dynamic Command & Dynamic Object
Parsley offers two very useful short lived objects: the <DynamicCommand> and the <DynamicObject>. Short lived objects are those who aren’t persistent during the life of the context. They are created, used, and destroyed, once or multiple times during the life of their context. You could also call them non-singleton. Let’s take a closer look to each one.Dynamic Command
Parsley’s Dynamic Command is a built in implementation of the MVC’s Command.
For those not familiar with MVC (Model View Controller), here is a very short summary of what the purpose of Command. The main goal of MVC is to create decoupling, in which you break the application into three main sections. The View which holds your User Interface elements, the Model which holds your data, and the Controller which gets and puts data into the model. The Command is part of the Controller.
The key concept is that the View (the the UI components) really should not care where the data comes from, that being a local database, an ASP page, php, Remote Object, WebService, local object, etc… It should worry only about interacting with the User. This is useful since it keeps your view components cleaner, easier to debug, and it certainly makes it easier to: Reuse the View component, Reuse the data acquiring/saving code, swap the view component, and swap the data acquiring/saving code. So under the MVC concept, the view simply dispatches a message in which it requests the acquiring of data or saving of data, how that is performed is not it’s problem.
Getting and saving data is the Controller’s job. Most MVC implementations have a concept of a Front Controller. The front controller’s job is to receive the messages dispatched (most likely from the View) and to invoke specific Commands to execute the request, that being either: acquiring data from where it should, or saving the data.
When you use Parsley’s <DynamicCommand>, you do not need to create your own Front Controller, since Parsley and its Context take the job of the Front Controller. Whenever you dispatch a message of a specific type, Parsley will create an instance of the specified Command Class type, and it will call it’s execute method. When done, it destroys that instance automatically, hence it is short-lived.
In Parsley, Command Classes do not need to implement any interface, nor they need to extend any class. They simply have to have at bare minimum a method called execute() that receives one parameter of the associated message type.
At a bare minimum a Command class in Parsley would look like:
package commands { public class MyCommand { public function execute (message:MyMessage) : void { // Do something } } }
In your context config file you must declare the Dynamic Command with the <DynamicCommand> tag:
<spicefactory:DynamicCommand type="{MyCommand}" selector="A Specific Request" />
If you pay close attention, there is nothing in the context config file that associates the specific command with the message type. That is because Parsley figures this out automatically. Parsley reads that you wish to create a DynamicCommand of the class type “MyCommand”. It looks into that class for a public method named execute. It then looks at the parameter type that is expected by the execute method and then it associates that parameter type as a message, with that command. So whenever a Parsley managed message is dispatched with that parameter type, Parsley automatically creates an instance of the DynamicCommand type, calls it’s execute method and passes the message as the parameter.
So what is this “selector”. Parsley’s DynamicCommand was designed to be used with or without standard Events. All events have an event type property. What selectors allow you to do, is to have the same message type (class) and invoke different commands depending on the selector.
For example you could have a UserSettingsMessage class that has some properties that would be the same, regardless if you save the user settings or retrieve the user settings. So you could have a “SAVE User Settings” selector, and a “GET User Settings” selector that invoke different commands with the same Message type.
In Parsley the selector does not have to be a string type, nor it actually has to be called type. That’s just the default. As long as it returns a value that can be compared by value and not by reference it can be called anything. So selectors can be Number, String and Integers, but I would stick to Strings and Integers. In your message class, you just use the [Selector] tag in front of the property you wish to be the selector and Parsley does the rest.
Since Parsley’s DyanmicCommand is a managed object, it can participate in all of Parsley’s features, including Messaging and Injection, which takes us to Dynamic Objects
Dynamic Object
Parsley’s Dynamic Object aren’t associated in any way with Dynamic Commands, they simply work well together. Dynamic Objects can be any non-view classes that you wish to have Parsley manage, but you do not want them to be persistant. A standard managed object of Parsley is instantiated when you inject its class type into any other Parsley managed object or view, but that instance remains persistent, if you inject the same class within the same context the same instance is injected in each injection, basically being shared. This is also called singleton, as it’s a single instance.
Dynamic Objects are not persistent. Each injection of that class type creates a whole new instance, something akin of using new() on each injection.
You might be wondering, why in the world would you just not simply use new() then? Well, couple of reasons. First; since it is a Parsley Managed object, that class can participate in any of Parsley features, so it can itself have injections and do Messaging, receive and send. Second; when using Interfaces, it is easy to swap out the Real class in all places where you Inject that Interface. You just change it in the context config file once.
Ok, enough background info, let’s look at how this actually works.
The Examples
I want to set some things straight:
First: This is NOT a complete MVC implementation. It is focused primarily on the Controller side. The Model and View are extremely simple to keep the focus on the Controller and the Command. I will later show a complete MVC example with Presentation Model.
Second: There is no one single way to implement Controllers and Commands the "right way". The right way depends on many things. Don’t forget that the goal is to make things simpler by decoupling, but don’t forget to keep things simple.
Generally speaking, Commands usually invoke services, as the command itself is not the service. The Service will be either a Remote Object call, a WebService, or a HTTPService for example. You can instantiate new services within the command or Inject Services to the Command. I particularly like Injecting services into the command as it makes it simpler to swap out the service, with little or no change to the Command. In Cairngorm, for example, Commands usually invoke “Delegates” which have the services in them, it’s a little extra step that you might consider.
Another decision to make is who should handle the result from the request of the service. The Service itself or the Command? Both have their pros and cons. If you wish to have the Service handle the result, then you must extend the service and create your own class that has the result handler in it, or use the Delegate concept. If the Command handles the result, then the Command gets tied to that service implementation.
There is no one perfect answer. You should consider your implementation on the following: How likely are you to use this application with a different server technology, or update your communication protocol with the server. If you think that there is a fair chance of you implementing a different server technology or move from XML to JSON or AMF, or something of your own, I would suggest having the Service handle the result.
Well, just to keep everyone happy, I’ve implemented both here. Two examples of the same thing, one with the Service handling the result, and the other with the Command handling the result.
Ok, this is a very simple RSS reader, and I really mean simple, the view and the model are as simple as they can get, and it was only tested with the RSS feed from this blog, but it should work with any other blogspot RSS feed. For those unfamiliar with what an RSS feed is, it’s a feed used to publish frequently updated work. More info on Wikipedia (http://en.wikipedia.org/wiki/RSS). RSS feeds are returned in XML, and I did almost no parsing of the XML, just the bare minimum, as the focus here is not to create a full RSS reader, but look on how to implement a <DynamicCommand>. In the real world, I would very rarely store XML data in my model. One of the great things about Flex is that it lets you prototype so easily.
The Service handling the result example:
Here is the running version of the Service handling the result. View Source is enabled.NOTE: I had to make a quick change to the examples. After I posted the example I realized that blogger's crossdomain.xml file doesn't allow for swf's hosted on other domains to read the RSS feed. I resolved the issue by reading the RSS feed through "Feed burner" (http://www.feedburner.com).
Now let take a look at the structure of the project.
This project has the basic structure of an MVC project, where you have models, views, and the controller all independent from each other.
We have one Command which is the GetRssFeedCommand class.
We have one Message which is the GetRSSFeedMessage class. When we dispatch this message, the GetRssFeedCommand should be instantiated, and have its execute method called.
Our Model is very simple, it’s the RssFeedModel. The model will store the result from the service invoked by the command. The view will be bound to a property of our model, so whenever the model gets data, so will our view.
In regards to the service, there are two classes. One is an Interface, called IRssService. Interfaces are not requiered, it simply makes it much easier to swap out the real service class if we wish to. For example we could have a mockup Service class that fakes getting data and we could quickly swap it latter. The real service class is the RssXMLHttpService class. That is the class that connects and gets the data.
The view, well, I stuck the List component in the main component called DynamicCommandExample, so the main file is the view. I have simply one item renderer for the List which is called RssFeedItemRenderer.
Of course we also have our Context configuration object, which is called DynamicCommandContextConfig.
Now let’s go into the details.
Let's start of with the Context config file which actually makes this work. Here is DynamicCommandContextConfig.mxml:
<?xml version="1.0" encoding="utf-8"?> <!--- This is the file that declares which objects you wish to manage through Parsley. Any object declared within the Object Tag will be allowed to participate in any of Parsley's features. This is a Simple MXML implementation, but this can also be declared in and XML file. --> <mx:Object xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:spicefactory="http://www.spicefactory.org/parsley" xmlns:models="models.*" xmlns:services="services.*" xmlns:local="*"> <!--- Our simple Rss Model that holds the results --> <models:RssFeedModel /> <!--- Here is the Service that we ask Parsley to use. Since this service implements IRssService, Parsley figures out that it should inject this service whenever an Injection request for IRssService is made. Notice that I've declared the Service as a DynamicObject. This means that a new instance will be created every time it is injected, and when the reference to this instace is finished, the old instance is removed. Type is the name of the class you wish to have created. Alternatively I could have declared it as a "Singleton" in the sense that once created it remains during the life of this context. When using Soap WebServices I always use the singleton aproach so that the wsdl only downloads once. Using the singleton aproach the declaration should be: <services:RssXMLHttpService /> --> <spicefactory:DynamicObject type="{RssXMLHttpService}" /> <!--- This is the declaration for the Dynamic Command. DynamicCommands are created automatically when a message of the type of the parameter received by the execute method is dispatched. type is the name of the class that you wish to have invoked. Selector is the specific identifier so that you can have more than one message of the same message class dispatched and the selector let's you select wich dynamic command is associated with it. I use public static const so that it is obvious wich message class is associated, although it is obtained by Parsley from the parameter of the execute method. You can also specify the name of the execute method, if it's not execute, but I would discourage you to do so. Execute is standard across all MVC frameworks. --> <spicefactory:DynamicCommand type="{GetRssFeedCommand}" selector="{GetRSSFeedMessage.REQUEST_FEED}" /> <mx:Script> <![CDATA[ /* The imports are necesary for the { } class usage */ import messages.GetRSSFeedMessage; import commands.GetRssFeedCommand; import services.RssXMLHttpService; ]]> </mx:Script> </mx:Object>
Although not obvious in the declaration (it is in the comment), when the GetRSSFeedMessage is dispatched that’s when GetRssFeedCommand is instatiated. This is one thing I don’t like about Parsley’s implementation of the DynamicCommand. I feel that it is really cool that it figures it out automatically from the parameter type expected in the execute method, but I have to go dig for it if I don’t remember it. That’s why I try to make it obvious in the selector attribute, but keep in mind that they don’t actually have to be related, to Parsley the specified selector in the <DynamicCommand> declaration is just a value to look for.
Now let’s take a look at the message that will be dispatched. Here is GetRSSFeedMessage.as:
package messages { /******************************************************** * This is the message that is instatiated and dispatched. * It is meant to request an RSS Feed. * Parsley uses primarely the class type to select what Command * to execute, but it recognizes that you could also have the same * class and wish to invoke different Commands depending on some * values of this class. So it also uses a selector property of this class. * Somewhat similar to the Event type selector, but without the same limitations. * * For more Parsley Examples visit artinflex.blogspot.com */ public class GetRSSFeedMessage { /************************* * This will be the selector type. Notice that it doesn't have * to be a String, but use types that are compared by value by default. */ public static const REQUEST_FEED:int = 1; /***** * Internal type holder */ private var _type:int; /*********************** * Constructor that receives the type * @param requestedType the type selector for this message */ public function GetRSSFeedMessage(requestedType:int) { _type = requestedType; } /*********************** * In parsley the Selector can be any property name. You must use * types that are easily compared by value and not by reference. * You simply tag the property with the Selector tag to indicate to * Parsley that this is the property you wish to use as selector. */ [Selector] public function get type():int { return _type; } } }
In this example I used the property name type as the selector, which is fairly standard, but you can name it whatever you want. Just make sure you use the [Selector] tag to let Parsley know which property you want to use. Also here is the public static const to help me identify the message class in the context config file mentioned earlier.
Now, let’s look at the simple model, this is where the data will be stored. Here is RssFeedModel.as:
package models { /***************************************** * This is a very simple model that holds an XMLList to hold the * result from the RSS Feed service request. It will be bound by a * mx::List to get the values. * * For more Flex and Parsley examples visit: artinflex.blogspot.com */ public class RssFeedModel { /************************************ * The list that holds the rss feed. It is bindable */ [Bindable] public var feedXML:XMLList; } }
Nothing special in our model. It simply has a property called feedXML that will hold the data. I would usually not hold data as an XMLList but I wanted to keep this simple.
Let’s move on to the Command. Here is GetRssFeedCommand.as:
package commands { import messages.GetRSSFeedMessage; import mx.rpc.AsyncToken; import services.IRssService; /********************************************************* * This is a short lived dynamic command class. In parsley Commands are * normaly created when a message is dispatched of it's expecting type. * Once created the execute method is called and passed the argument. * This command injects a service interface and proceeds to call * the service methods. * Once the command completes it is automatically destroyed unless specifically * told not to. * * For more Parsley and Flex Examples visit artinflex.blogspot.com */ public class GetRssFeedCommand { /********************************* * The service is injected through an Interface. This makes it easy * to swap out the service with a different class. Parsley figures * automatically out through reflection wich of it's manage object * should it inject by determining which classes implement this * interface. */ [Inject] public var service:IRssService; /********************************* * Once Parsley creates this command object and performs it's injections, * it proceeds to call the execute method. You can tell Parsley to call * a different method, but this is discouraged. The execute method * can return an AsyncObject. * Parsley determines which command to execute by the object * type of the parameter of this execute method. * * @param message is the message sent. It's type is used to determine * which command to execute. */ public function execute (message:GetRSSFeedMessage) : void { service.readRssXMLFeed("http://feeds.feedburner.com/ArtsFlexNotes"); } } }
This command class is actually pretty simple, and most of them will usually be simple. In this version of the command, handling the result is taken care of by the service. Commands may have more complex logic. For example, they might check if the model already has this data, and not go to a service to get it again (if you know it won’t change), they might also decide where they will go get the data, etc… Also Commands are not just about getting data, they also save data, process data, etc… For example you might have complex and dynamic Validators implemented as commands.
Now this command is relying on a service. Since the command is managed by Parsley it can Inject, as show and it Injects the IRssService, which Parsley fills in with RssXMLHttpService because it knows that RssXMLHttpService implements IRssService through its inspection/reflection process.
First Let’s take a look at the Interface IRssService.as:
package services { import mx.rpc.AsyncToken; /********************************************* * This interface is used to read RSS Web Services * Using Interfaces makes it easy to switch the actual * Service classes. */ public interface IRssService { /********************************************************** * This function will send a request to read an rss xml feed and * store the result in the feedModel * @param rssURL the url of where the RSS feed can be found. * @return The call's AsyncToken in case the command wants * to add it's own handlers */ function readRssXMLFeed(rssURL:String):AsyncToken; } }
The interface just defines the methods that the Command will need to access. In this case it has a method named readRssXMLFeed() that expects the URL of the feed. Notice that the definition specifies that the service returns an AsyncToken. In this implementation of the Command, the AsyncToken returned is being ignored, but on the following example it will be used.
So let’s look at the real service itself. Here is RssXMLHttpService.as:
package services { import models.RssFeedModel; import mx.controls.Alert; import mx.rpc.AsyncToken; import mx.rpc.IResponder; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.rpc.http.mxml.HTTPService; /*********************************************************** * This is a simple RSS consumer service class that will read an * RSS Feed. I used the MXML version simply because it has * the showBusyCursor property that I like. It displays a hour * glass while it submiting the request. * @author Arturo Alvarado * For more Flex and Parsley examples visit artinflex.blogspot.com */ public class RssXMLHttpService extends HTTPService implements IRssService,IResponder { /*********************************** * This is the model that we will place the feed that we will receive. * The view will get the data from the model */ [Inject] public var modelRssFeed:RssFeedModel; /********************************************* * Constructor */ public function RssXMLHttpService(rootURL:String=null, destination:String=null) { super(rootURL, destination); showBusyCursor = true; } /**************************************** * This function will send a request to read an rss xml feed and * store the result in the feedModel * @param rssURL the url of where the RSS feed can be found. * @return The call's AsyncToken in case the command wants * to add it's own handlers */ public function readRssXMLFeed( rssURL:String):AsyncToken { this.url = rssURL; this.resultFormat ="e4x" var call:AsyncToken = this.send(); call.addResponder( this); return call; } /************************************* * This is the result handler it takes the result from the http * request and stores and XMLList of all the nodes taged with <item></item> * into the model * @param data is the result object that we will make sure it's a Result Event */ public function result(data:Object):void { if (data is ResultEvent) { var event:ResultEvent = data as ResultEvent; modelRssFeed.feedXML = XML( event.result )..item } } /****************************************** * Fault handler in case the request failed. * @param info object that contains the Fault data. */ public function fault(info:Object): void { var event:FaultEvent = info as FaultEvent; Alert.show(event.fault.message,event.fault.faultDetail); } } }
This service is a Parsley managed object. Recall from the Context configuration file that we specified it to be a Dynamic Object, which means that a new instance will be created, used and destroyed each time a Command Injects it. This has the benefit of using fewer resources while the service isn’t being used. When using Soap Web Services you might wish to reconsider this approach, and leave either the service or something from it, persistent, that way you don’t have the service request a wsdl file every time you wish to make a request.
This service handles the result and fault. Since it does implement IResponder, it can assign itself as a Responder to the AsyncToken returned. I like this approach better than the addEventListener() / removeEventListener() approach for handling results and faults.
In this case, being managed by Parsley means that it can Inject the model, which it does, and store the result in the model, which it does.
Normally, I would have a defined a ValueObject (in case you are not familiar with the term ValueObject check out: http://blog.tsclausing.com/post/10) with the fields I’m interested in. I would create an instance of that value object, assign the values obtained from the Feed’s XML to that instance and push that instance to an Array, ArrayList, or ArrayCollection in the Model..
So that’s the backend of our app. Let’s look at the View. The view is made up by two components, the Main app, called DynamicCommandExample, and by an Item Renderer named RssFeedItemRenderer.
Let’s take a look at DynamicCommandExample.mxml:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:parsley="http://www.spicefactory.org/parsley" viewSourceURL="srcview/index.html"> <!--- ContextBuilder is how you tell parsley to manage objects that are not Views. In this case I'm instructing Parsley to load the DynamicCommandContextConfig file which has the "list" of objects you wish to have managed, including the definition of the dynamic command. --> <parsley:ContextBuilder config="{DynamicCommandContextConfig}" /> <!--- I want Parsley to manage this view, as it will hold the mx:List that will display the feed and I wish to pass the models data provider, though Injection. Normaly I would not do this in the main app, but the focus of this example is the Dynamic Command and really wanted to keep the view part very simple. --> <parsley:Configure /> <!--- The button that requests the feed. --> <mx:Button x="10" y="10" label="Retrieve RSS Feed" click="requestFeedButtonClickHandler()"/> <!--- The list that displays the feed result. This does not have to be on the same view as the requesting part. It binds to a property of the model. --> <mx:List x="20" y="40" width="389" height="321" dataProvider="{modelRssFeed.feedXML}" itemRenderer="views.RssFeedItemRenderer"></mx:List> <mx:Script> <![CDATA[ import models.RssFeedModel; import commands.GetRssFeedCommand; import messages.GetRSSFeedMessage; /********************************************************* * The dispatcher function injected so that we can request the * feed and Invoke the command by dispatching a Message. */ [MessageDispatcher] public var dispatcher:Function; /******************************************************* * The model that we will use to set the data provider of the list. * The model receives the data from the service invoke by the command. */ [Inject] [Bindable] public var modelRssFeed:RssFeedModel; /******************************************************* * This function get's executed when the button is clicked to * request the feed. Notice that there is no reference to the command * nor the model. This view has no reason to know who or how will get the * data. Is it from a local database, is it from a feed, is it an XML local * file. That is all irrelevant to this view, all it does is say it wants * the data and dispatches a message to request it. Parsley takes over from * there. */ public function requestFeedButtonClickHandler():void { dispatcher(new GetRSSFeedMessage(GetRSSFeedMessage.REQUEST_FEED)); } ]]> </mx:Script> </mx:Application>
This view is doing more than usual for being the Main file, but it is fine for this example. This view holds the Context, it is also configured for this context so that it can participate, so it has a <ContextBuilder> tag and a <Configure> tag.
The view has a button that when pressed it simply dispatches a new GetRSSFeedMessage of the REQUEST_FEED type. As you can see, it doesn’t know anything about the Command or the Service. It just wants data and it dispatches a messages asking for it, no matter where It comes from.
As this is a very simple view, I have a list that displays the results that is bound directly to the shared model’s feedXML property. It is notified of data being received through standard Flex binding. While this is ok in small projects or prototypes, I would suggest using Parsley Messaging to notify the view of the results. One inherit problem of using this approach is that the view will only get notified if data was changed, but if the request brought an empty result, the view would not know about it and the user could think that the application hung. At a later time I’ll show a “better” way of doing this.
Finally, this list uses a custom item renderer to display the data. Here is RssFeedItemRenderer.mxml:
<?xml version="1.0" encoding="utf-8"?> <!--- This is the Item Renderer for the List. It isn't designed to look good. It is designed to be simple to view the code. Normally, I would assign this to a VO and bind the properties to the VO so I can have proper compiler checking, but for this example it bound to the xml. When run under debug mode you will get warnings that proper binding was not achieved since you can’t bind to XML objects. For more Flex & Parsley examples visit artinflex.blogspot.com --> <mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" verticalGap="0" horizontalScrollPolicy="off" verticalScrollPolicy="off" > <mx:Script> <![CDATA[ /*************************************************** * Using namespace makes it a bit easier to parse xml * The updated field of the xml uses the atom namespace */ namespace atom = "http://www.w3.org/2005/Atom"; use namespace atom; /*************************************************** * This function should really be used to set a VO * so that you can bind to known properties. Here * I simply used it to help me view the contents of * the xml rss feed to find out the properties. * Data tipically receives an Object that you should * assing it to a local var of a know Value Object * @param value The data passed by the dataprovider * it is one record of the list. */ override public function set data(value:Object):void { super.data = value; } ]]> </mx:Script> <mx:Label width="100%" fontWeight="bold" text="{data.title }" selectable="false" /> <mx:Label width="100%" text="Publish Date: {data.pubDate}" selectable="false" /> <mx:Label width="100%" text="Author: {data.author}" selectable="false" /> <mx:Label width="100%" text="Last Updated: {data.updated}" selectable="false" /> <mx:Label width="100%" text="Link: {data.link}" selectable="true" /> </mx:VBox>
When it comes to the item renderer, there isn’t anything really special other than the namespace declaration. As mentioned earlier, normally I would not be passing XML, much less raw XML to an item renderer, just keeping it simple.
Well that’s it, now let’s look at the other version.
The Command handling the result example:
Here is the running version of the Command handling the result. View Source is enabled.Here is the Structure of this version of the example:
As you can see, there isn’t any apparent difference between these two. In fact, there really isn’t a whole lot. The overall structure is basically the same, although using the interface for the service is a bit less useful. This is because swapping the service might have an effect on the content of the result, which means that your result handler in the Command must be able to handle the new result format. You could write code in the command that could check the result, figure out the format and process it accordingly, but I would honestly only consider that in the case that you really were planning on swapping the Service in a regular fashion or at runtime.
The only two classes that changed are RssXMLHttpService and GetRssFeedCommand, everything else is exactly the same.
I’ll start off with the service. Here is RssXMLHttpService.as:
package services { import mx.rpc.AsyncToken; import mx.rpc.http.mxml.HTTPService; /*********************************************************** * This is a simple RSS consumer service class that will read an * RSS Feed. I used the MXML version simply because it has * the showBusyCursor property that I like. It displays a hour * glass while it submiting the request. * @author Arturo Alvarado * For more Flex and Parsley examples visit artinflex.blogspot.com */ public class RssXMLHttpService extends HTTPService implements IRssService { /********************************************* * Constructor */ public function RssXMLHttpService(rootURL:String=null, destination:String=null) { super(rootURL, destination); showBusyCursor = true; } /**************************************** * This function will send a request to read an rss xml feed and * store the result in the feedModel * @param rssURL the url of where the RSS feed can be found. * @return The call's AsyncToken in case the command wants * to add it's own handlers */ public function readRssXMLFeed( rssURL:String):AsyncToken { this.url = rssURL; this.resultFormat ="e4x" var call:AsyncToken = this.send(); return call; } } }
The difference between this one and the previous one is that this one doesn’t handle the result or fault. It simply returns the AsyncToken to the caller. It also no longer needs to Inject the Model into it. Since Injection is no longer needed, there is also no need to have this class to be managed by Parsley. In this example it still is, but there really isn’t a need for it anymore. The only benefit as it stands, it’s the ease of swapping it, but don’t forget that it could affect your Command.
Now let’s look at the Command, here is: GetRssFeedCommand.as:
package commands { import messages.GetRSSFeedMessage; import models.RssFeedModel; import mx.controls.Alert; import mx.rpc.AsyncToken; import mx.rpc.events.FaultEvent; import services.IRssService; /********************************************************* * This is a short lived dynamic command class. In parsley Commands are * normaly created when a message is dispatched of it's expecting type. * Once created the execute method is called and passed the argument. * This command injects a service interface and proceeds to call * the service methods. * Once the command completes it is automatically destroyed unless specifically * told not to. * * For more Parsley and Flex Examples visit artinflex.blogspot.com */ public class GetRssFeedCommand { /********************************* * The service is injected through an Interface. This makes it easy * to swap out the service with a different class. Parsley figures * automatically out through reflection wich of it's manage object * should it inject by determining which classes implement this * interface. */ [Inject] public var service:IRssService; /*********************************** * This is the model that we will place the feed that we will receive. * The view will get the data from the model */ [Inject] public var modelRssFeed:RssFeedModel; /********************************* * Once Parsley creates this command object and performs it's injections, * it proceeds to call the execute method. You can tell Parsley to call * a different method, but this is discouraged. The execute method * can return an AsyncObject. * Parsley determines which command to execute by the object * type of the parameter of this execute method. * * @param message is the message sent. It's type is used to determine * which command to execute. */ public function execute (message:GetRSSFeedMessage) : AsyncToken { return service.readRssXMLFeed("http://feeds.feedburner.com/ArtsFlexNotes"); } /************************************* * This is the result handler it takes the result from the http * request and stores and XMLList of all the nodes taged with <item></item> * into the model * @param data is the result object that we will make sure it's a Result Event */ public function result(data:Object):void { if (data is XML) { modelRssFeed.feedXML = XML( data )..item } } /****************************************** * Fault handler in case the request failed. * @param info object that contains the Fault data. */ public function error (info:Object): void { var event:FaultEvent = info as FaultEvent; Alert.show(event.fault.message,event.fault.faultDetail); } } }
Well, the obvious change is that it must handle the result and fault from the service as it is no longer handled by the service and of course you must inject the Model. But look closely, there are a few more differences.
First off, the execute method no longer returns a null, it is actually returning an AsyncToken, the same AsyncToken returned from the Service. Why in the world would I want to do that? If we didn’t invoke the execute() method directly, what is actually receiving the returned AsyncToken? Well, that’s a nice little trick up Parsley’s sleeve. Notice that I didn’t add any responders, nor I added any event listeners? How does the result() method get called?
Well, Parsley itself is invoking the execute() method of the command and when it receives an AsynToken it goes ahead and looks in your Command to see if you have a method called result() that is expecting an Object, and it also checks to see if you have a method named error() that is also expecting an Object, and calls them accodingly. Don’t ask me why Jens (creator of Parsley) decided not to go with the standard fault(), and used error(), no clue. But if you really want to use anything else and not error(), you can tell Parsley in the Context Config file to use a different name.
Now, also notice that the result handler isn’t exactly the same as the result handler in Service from the previous version of this example. Parsley actually does some cleaning up for you, and it doesn’t actually send a ResultEvent. It actually sends the ResultEvent’s result property, something like: "ResultEvent(event).result". This way you don’t actually have to typecast to ResultEvent since that’s actually not what you get as the parameter to your handler, you get the result of the ResultEvent. Hope I didn’t make something that is simple, confusing.
The error() handler is basically the same as a standard fault handler, with the exception of the name change.
Now I mentioned that you can change the name of the methods invoked automatically in the DynamicCommand by Parsley. It’s actually fairly simple. In your Context config file, where you declare your DynamicCommand you just specify it. Here is an example:
<DynamicCommand
type="{SaveUserCommand}"
selector="save"
execute="executeSaveUser"
result="handleSaveUserResult"
error="handleFault"
/>
Parsley also offers a more unique (not very standard) way of doing Commands. It is called the "Asynchronous Command Methods". It is based on using tags in front of methods to act as Commands. The cool factor is that you don’t have to create a Command class. You can place these tags in any Parsley managed object. I particularly like the Short-lived Dynamic Command approach better, simply because it is much more organized. Having Command handlers anywhere, can lead towards massive confusion and a complete pain to follow the code.
You can read more about the Parsley’s Commands in section 6.9 Asynchronous Command Methods and in section 6.10 Short-lived Command Objects in the docs.
I’m sure some might wonder which approach is better, the first or second demonstrated here. “Better” is such a subjective word. What is better for me is not necessarily better for you.
I like the first approach over the second one. As neat as the automatic call to the result handler in the Command might be, it can be confusing to someone familiar with Flex and not familiar with Parsley’s DynamicCommand. The boilerplate code saving is truly minimal.
I really like the ability to change my server side technology with little to almost no impact on the client side. Over the years, we have improved our communication between the client and server side, and I really like having things organized in a way that it makes it really simple to do so.
Well, I certainly hope that this was useful. It’s a great feature available in Parsley.
Next -> Parsley's Automatic Component Wiring examples.
Nice example. Helped a lot understanding Dynamic Commands. Without the basic explanation followed by a simplified example you tend to be lost as the Parsley developer manual does (explains without a concrete example). I eagerly anticipate studying yourother examples
ReplyDeleteThanks. Glad to be of help. Yeah, I struggled with them at the beginning also, as that part of the manual is pretty vague compared with the rest. Having experience with Commands before helps, but also confuses, as Commands usually return null in the execute method and the association between the Message and the Command is more obvious that it is in Parsley.
ReplyDeleteGood explanation of Commands, with some logic in either the command or the service. I personally have tried a third way. This uses the serializationFilter of HTTPService. The class that you define as your serializationFilter is called as the result is returned from the service, but before the ResultEvent is fired. In my case I get XML data returned and in the filter I convert the XML to an array. Then in the result in the command I add the returned data which is now an array to my model. My application works with ArrayCollections in the model, so if the service returns other data then the serializationFilter can convert that data into an array, and all that logic is separate but attached to the service and not the command. Similarly if using Remote Objects you can use convertResultHandler.
ReplyDeleteThank you. I recently discovered through a post on Parsley's Forum about the serlializationFilter. It's pretty cool. I plan to write an update using that one.
ReplyDeleteThe only thing I don't like about the serializationFilter is that it's Synchronous. On small result sets, it's a non-issue, but on large ones it is an issue, because you can't process the result in chuncks, like you could if you process it in your Command or in your Service Asynchronously. During the time that it is processing inside the serializationFilter, the UI will be frozen. Currently they Flash/Flex team is considering multithreading, which would totally resolve the Freeze issue, and you would no longer have to break the process in chunks give the UI a chance to react, but that's the future.
If you want the controller to handle the model updating, how would you do it? By nature the DynamicCommand and DynamicObject are not persistent. Sending a message from them for the Controller to pickup dies.
ReplyDeleteHmmmmm... would have to see how you are sending the message from the DynamicCommand, because it should not just die. Just because Parsley isn't holding a direct reference to the Command, it doesn't mean that it has been garbage collected. That's why they can still receive a response from a Service. Also Parsley Messaging is synchronous, so that is something to take into account when daisy chaining commands. Are you using the EventDispatcher or [MessageDispatcher]?
ReplyDeleteWhy don't you update the Model from a Command itself? Or are you wanting to invoke a Command from another Command? I guess I'm missing part of the picture to better answer your question. Do you have an example I can look at?
Sorry been away from this. I have an example which I have not problem providing if u are interested.
ReplyDeleteI placed the FXP here: http://alhsites.com/temp/
ReplyDeleteThe result method in MembershipServiceRemote received the data and fires the MembershipGetAllMembersEvent.
The MembershipController membershipGetAllMembersEventHandler never sees the event.
This is all kicked off in the AllMembersGrid.mxml firing the MembershipGetAllMembersMessage leading to the GetMemberDataCommand dynamic command which seems to work fine and is the basic change from the same example without a DynamicCommand.
Got the code to work by changing the DynamicCommand execute method to AsyncToken from void.
ReplyDeleteI left the result and fault for the RemoteObject in the service class (MembershipServiceRemote implements IMembershipService, IResponder).
My goal was to make this one DynamicCommand change from the Zend AMF prior example I posted to my blog using this article so my needs were different in that working Parsley code existed.
I suspect handling the result and fault in the Command might be a better approach. If I do I have no further need for the service class (MembershipServiceRemote implements IMembershipService, IResponder).
I guess the overall question is the advantage. The DynamicCommand seems bound to the service if execute returns AsyncToken or will this be the case for every type of service should I swap it out say for http service from the current AMF remote object.
OK. Got to look at the code and here is what is happening.
ReplyDeleteYou are dispatching a message from the Service itself. The service is set up as a dynamic object. The message is being dispatched from the Responder of service. By that time, Parsley has removed all references to that dynamic object, which has not been GCed because of the responder. Now Parsley asigns a new address for each dispatcher (don't know why), and to it that dispatcher is no longer valid so the handlers must be nulled out by that time. I'm going to have to dig into Parsley code to look a bit deeper into that one.
Solutions:
1) Setting the return type to AsyncToken in the execute method of the DyanmicCommand is keeping the service longer in Parsley's reference, but I would not bet on it in the future.
or
2) Setting MembershipServiceRemote as a Standard Parsley object, rather than a dynamic object.
or
3) Update the model directly from the service or the command. This is more "traditional". Although your setup is interesting as the service and the command are unaware of the model. Is it worth that extra layer of separation? Recall that the Command and Service are part of the controller. You really don't have to have a separate controller.
or
4) If you wish to keep the current setup, and use a dynamic object for your service, you could add signals. (https://github.com/robertpenner/as3-signals/wiki)
Signals behave similar to the Message Dispatcher of Parsley in the sense that they are synchronous. But a signal is an object, and if you declare a signal in your context as a Parsley managed object, it will be there as long as the context exist, and it's dispatcher doesn't change address, so it would work just fine.
I like Parsley's MessageDispatcher, it's great, never really thought of a reason to use Signals with Parsley until now. But honestly, I don't recommend this route, there really isn't a reason for this if the other 3 options are viable.
If you do go for option 1. You really should then handle the result in the Command and not in the Service. That way you will have a guarantee that the result handler will still be in Parsley's reference. Since you are using AMF, it will fit just right. But do consider if you really need that extra layer, and not just have the command update the model.
Hope that helped.
Ah, managed to make it work in the end (first method).
ReplyDeleteI used a RemoteObject connecting to Java/Spring backend instead of HTTPService, and that didn't worked right from the beginning.
Anyway, implementing IResponder for the command did not work for me... the result and fault methods were just never called, so I had to get back to:
ro.addEventListener(ResultEvent.RESULT, result);
ro.addEventListener(FaultEvent.FAULT, fault);
Back to the topic of Dynamic commands and object: so if I understand well, the interest is to have short-lived objects instead of "singleton" instanciated once for all at context initialization. Doing this is less memory consuming because these objects are only in memory when we actually need them, but in the other hand, we'll need to reinstanciate them every time we need it, so this is less good in terms of performance, right ?
So it's maybe not the best option "in case object creation and initialization is too expensive to be repeated all the time" (quoted from Parsley's doc).
Seems in the case of Soap Webservice, from what is written in your code comments, this would be a bad idea to use DynamicObject. For RemoteObject, I've no idea how "expensive" the instanciation is.
Thanks for the article !
(seems my last post was lost)
ReplyDeleteSo... managed to make it work finally (first approach), had issues with my RemoteObject instead of your HTTPService.
Also, I had to go back to:
ro.addEventListener(ResultEvent.RESULT, result); ro.addEventListener(FaultEvent.FAULT, fault);
because by implementing IResponder, I just didn't had any callbacks on result and fault methods.
Now back on Dynamic commands and objects: if I understand well, the advantages of using these over standart "singleton" is that they'll be less memory consuming as destroyed as soon as we don't need them. On the other hand, if we need them quite often, then we'll add the overhead of instanciation cost each time.
For example, by reading your code comments, it seems with a soap Webservice it would be too costly to instanciate the service each time, because of the wsdl download stuff.
As for me, I'm using RemoteObject to connect to Java/Spring backend (using AMF), but I've no idea how costly the instanciation of such objects is.
Thanks for the article!
Your last post ended up in the spam bucket and I missed.
ReplyDeleteYes, Flash player is slow at creating objects. But slow doesn't mean it takes 10 minutes to create an object. For normal stuff it's ok. If you really need to create/destroy objects every 10/20 milliseconds, then you must start caching them somehow. Item renderers of long lists are the perfect example.
Where it comes to commands and services, itt depends on how often are you going be calling your service or executing your command. Are you calling it on each keystroke, or faster?
Soap webservices do require that a request for a wsdl file be performed first. It's a matter of caching the request more than instantiating the class. The remote service will not be called until after the wsdl request is received. This can easily add 100 mseconds to 1 second of delay, for no good reason, just waiting on answer to proceed.
Hi Can u let me know how this dynamic commands concept is advantageous over implementing Idisposal interface for the respective component.
ReplyDeleteDynamic commands do not "compete" against implementing IDisposable. That is like trying to make a comparison between Oranges and Ground Beef; sure you can eat them both, but they are not even both fruit.
ReplyDeleteThe concept behind IDisposable is to have a component that cleans up after itself and cleans up it's children. But it is usually referring to view components.
Commands are not view components. Commands are classes created to perform a specific task and keep that task outside of the view component. The whole concept is to decouple the view from the business logic. The advantages of this are mentioned throughout the series of articles but here are a few: It is easier to extend the functionality, it is easier to run unit tests, it is easier to reuse your classes.
Dynamic Commands clean up after themselves, but they were not meant to be used to clean up the views and the view children or any view components. Actually, the whole idea is to decouple the view from the command, not the opposite.
You can use IDisposable in conjunction with Dynamic Commands just fine.
Hissam,
ReplyDeleteSorry for the late response. I'm a bit overwhelmed with work now, so it's a bit unlikely that I can get it done in a short period of time. But the Flex 4 and Flex 3 versions are pretty much the same. Make sure that you are using the Flex 4 Parsley swc's, and that you have your context declared.
Does injection work? Does any messaging work, or just your command doesn't fire? The context is declared a tiny little bit different in Flex 4. You must use the Declarations. There is an example of this in the Basic Injection example.
http://artinflex.blogspot.com/2010/09/quick-dive-into-parsley-basic-injection.html
Thank you for this great article! In order to understand how it works more easily I created a simple drawing which illustrates relationships among the different classes of the first example:
ReplyDeletehttps://docs.google.com/drawings/edit?id=1bSpqGS0nPgXtjYuguG6G0H30XL78K4iX_B-LMcPgvqE&hl=en_GB
Great article. Have you any looked into . have any thoughts on using the Task framework in Parsley in addition / instead of the DynamicCommand?..On first glance it seems like it would be better for sequencing multiple tasks/commands together (e.g. authenticate, authorize, retrieve profile at app start).
ReplyDelete@Anonymous.
ReplyDeleteThank you.
Yes, I have used it and I like it alot. The Task framework can be used with or without Parsley. I've used it even combined with Robotlegs.
I don't see the Task framework as a replacement for DynamicCommand, it most certainly can be used to chain commands together, or chain anything else.
I think that the idea of chaining the commands with the task framework would be that at some point in time you might want to run the commands independently, and not necessarily chained.
The neat thing is that in Parsley your execute method can return a Task.
Check out this thread.
http://www.spicefactory.org/forum/viewtopic.php?p=2510&sid=dc5e09ae3e861eebface7a1ec75ccca2
Your blog is becoming the de-facto industry standard documentation on using Parsley with Flex. I commend your efforts and the clarity of your work!
ReplyDeleteThanks!
ReplyDeleteHello,
ReplyDeletefirst of all i must say - this web is amazing ;)
One question:
How is the right architectural way to fill data after display a screen?
Example: In a tab i have a dropdownlist and after user click on this tab i will fill them up. The tab has his own model.
My ideas:
1, in createComplete call a [MessageDispatcher] for DynamicCommand
2, Use [init] in model
3, .... ?
tHx very much
p.
And one more question.
ReplyDeleteHow to do that, when i need call XY Services for a single screen? Should i make XY Commands? ...so much work :(
This comment has been removed by the author.
ReplyDelete@Horyna,
ReplyDeleteHi, there is no simple answer to your question. It depends on many things.
1) How complex your application is.
2) Do you benefit from an MVC architecture or not, or some other architecture.
3) Should that data be accessible from other views or commands.
If I'm using a framework that let's me decouple, I tend to make the most out of it. In Parsley terms, I rather use the [Init] rather than the View's Creation Complete.
Now this might not be the best thing always. For example, if your view is Animated into the scene, you probably want to wait to request the data until the view has finished it's animation so that the animation does not get interrupted.
The amount of services does not necessarily need to match the amount commands.
Commands relate somewhat to real life commands. You can have a simple commands such as: "Get Paper" "Get glue" "Get tape", or you can have a command that is "Get Supplies" which calls 3 services.
You can also have commands that do internal stuff and never even call a service. You can also have remote and local services. There is no RULE in that sense.
Building a decoupled application can be a chore. It is certainly more initial work than a coupled application. Does it pay off? Well, that depends on the complexity of the application.
Decoupled applications dissociate the data (and it's manipulation) from the views. This pays off mostly in the following scenarios.
1) There is a reasonable chance that your views will change in the future. Be it because you write a desktop/mobile/tablet app, or because it is an app that will grow and mature and it will get updated.
2) Multiple views will have access to the same data.
3) Interested in updating data even while the view is not active.
4) Caching data. If you got the data already, keep it persistent, there is no need to go get it again.
Under those scenarios that "extra" work does pay off.
This is nice blog. The way it is explained is great. If you want to read more about this topic, visit here.. Dynamic Object – Object Oriented Programming (OOP)
ReplyDeletegoruntulu show
ReplyDeleteücretli
LESR