Filed under: actionScript, cairngorm, development, flex, frameworks | Tags: actionScript, cairngorm, development, flex, Maté, PureMVC, tips
So I am on the quest to create a hybrid MVC mini-framework that combines some of the best elements of Cairngorm, PureMVC and Maté. The idea is to use the Command pattern from Cairngorm (because I like all my service/UX logic to be placed there and the EventMap’s dependencies on binding and MXML seem limiting), the Mediator pattern from PureMVC (which unclutters and decouples the views) and the EventMap and Injection logic from Maté (which will help to further decouple some of the command=>model logic).
Keep in mind I have only really been working with Maté for a couple of months and have only dived into actually understanding it in the last week or so. So if you know of a better way of doing what I am trying to accomplish, please let me know and I can update the article.
This will mostly address how to decouple some of that command => model logic. This means we are striving to get the command classes as model-agnostic as possible. It also means there needs to be a slight modification to the current CairngormCommand structure. We will keep the CairngormEvent in use because its data payload is useful in sending data back and forth from the event dispatchers/listeners. In order for a command to send info back to a listener, it will need to extend EventDispatcher. Then depending on the result or fault logic, it can dispatch an appropriate event with a data payload. Here is some stub code:
public class SampleMateFriendlyCommand extends EventDispatcher implements IResponder
{
public function execute (evt:Event):void
{
//the function signature could be anything including execute (... args)
//notice I am not implementing the ICommand interface as I want to have more flexibility
}
public function result (data:Object):void
{
//parse data object if needed.
var evt:CairngormEvent = new CairngormEvent("success");
evt.data = parsedResultDataObject;
dispatchEvent(evt);
}
public function fault (info:Object):void
{
//parse info object if needed.
var evt:CairngormEvent = new CairngormEvent("fault");
evt.data = parsedFaultInfoObject;
dispatchEvent(evt);
}
}
I like the Command pattern because I think of it in a military sense. You issue a command to a soldier and that soldier executes the command, then generally reports back. So this is akin to that analogy. Next we need to see how to get the data back to the EventMap in order to wire the result/fault data into the appropriate places. I tinkered with this for quite some time before stumbling upon this solution. The Maté API docs are decent but fail to cover much beyond explaining the self explanatory. I really hope they work on their API docs and really flesh out the information.
<mate:EventHandlers id="applicationCompleteHandler" type="{AppEvent.SAMPLE_MATE_COMMAND}" debug="true">
<mate:AsyncCommandInvoker generator="{SampleMateFriendlyCommand}" successType="result">
<mate:successHandlers>
<mate:PropertySetter generator="{SomeModelObject}" targetKey="data" source="{scope.currentEvent.data}"/>
</mate:successHandlers>
</mate:AsyncCommandInvoker>
</mate:EventHandlers>
The AsyncCommandInvoker allows you to specify the event type that will trigger the successHandlers or the faultHandlers. Accessing the data payload for the result or success event is done using scope.currentEvent.data. Again I must reiterate that I stumbled upon this find because there was no documentation that I could find to support what I was trying to do.
The cool thing about this is that you have now freed up your commands so that they needn’t know about any specific model objects. That is unless you really want to strongly type your result data objects. This freedom allows for better testing as you can simply wire up a testing event map if you want to unit test.
Next up will be trying to wire mediators and their respective views into the event map.
Filed under: actionScript, appCoreLib, cairngorm, client side, development, flex, projects, server side, tutorial, xml
The potential of Flex for rapid prototyping and general application development is amazingly fast. With some mock data and a basic user-experience (UX) scenario, a developer can create a functioning sample application in a matter of minutes.
If you are developing either a full blown RIA or a prototype application then you have probably at least heard of Cairngorm. If not, familiarize yourself with the basics here – link. I use a stripped down version of it for almost every project I have worked on. It works beautifully
I plan to show you an example of using AppCoreLib’s XMLDataBroker to fill in some mock XML data for your commands. This is helpful when you have a basic idea of an API/services but they are not returning anything or not ready to be tapped or you wanna test out a service’s result format before the server developers implement it.
Before I continue, let’s set one or two rules about this tutorial.
- the expected format for the returned data is XML
- the mock XML data format will reflect the same format of the actual service’s result
Firstly let’s take a look at a basic Cairngorm command. This is a stripped down version so you won’t see any delegate-type references in here.
package com.foo.controller.commands
{
import com.adobe.cairngorm.commands.ICommand;
import com.adobe.cairngorm.control.CairngormEvent;
import com.foo.business.Services;
import mx.rpc.AsyncToken;
import mx.rpc.IResponder;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
public class SampleCairngormCommand implements ICommand, IResponder
{
private var _vo:Object = {};
public function execute (event:CairngormEvent):void
{
var call:HTTPService = Services.getInstance().httpService;
call.url = "http://www.foo.com/someService";
var param:Object = {};
var token:AsyncToken = call.send(param);
token.addResponder(this);
}
public function result (data:Object):void
{
var xmlResult:XML = ResultEvent(data).result as XML;
}
public function fault (info:Object):void
{
}
}
}
So now with about 5 lines of code, I will show you how to inject mock XML data for creating a response that fits within the Cairngorm command structure:
package com.foo.controller.commands
{
import appCoreLib.business.XMLDataBroker;
import appCoreLib.events.XMLLoadEvent;
import com.adobe.cairngorm.commands.ICommand;
import com.adobe.cairngorm.control.CairngormEvent;
import mx.rpc.IResponder;
public class SampleCairngormCommand implements ICommand, IResponder
{
public function execute (event:CairngormEvent):void
{
var x:XMLDataBroker = new XMLDataBroker();
x.addEventListener(XMLLoadEvent.XML_LOAD_SUCCESS, result);
x.addEventListener(XMLLoadEvent.XML_LOAD_FAILURE, fault);
x.loadXML("assets/xml/someMockXMLData.xml");
/* var call:HTTPService = Services.getInstance().httpService;
call.url = "http://www.foo.com/someService";
var param:Object = {};
var token:AsyncToken = call.send(param);
token.addResponder(this); */
}
public function result (data:Object):void
{
var xmlResult:XML = XMLLoadEvent(data).xml;
//var xmlResult:XML = ResultEvent(data).result as XML;
}
public function fault (info:Object):void
{
}
}
}
That’s it! Simple, effective and most importantly, easy to remove once an actual service response is available.
Filed under: actionScript, cairngorm, client side, development, flex, server side, tutorial, validation
recap
Last time we discussed two methods for handling service validation errors in a Cairngorm application. The first method was to borrow from some AS2/ARP techniques by passing a reference. The second method was to leverage the event nature of Flex and use a central event dispatcher type approach. Both of these have their advantages and certainly have their disadvantages. This last approach will try to take the best from both worlds and combine them to alleviate some of the problems we encountered.
ServiceValidationErrorManager method
Again you will have to pardon the names here but this gets the point across. There is no doubt what this puppy does. For the sake of simplicity I will continue to call it “the manager”. Ok so the manager is a) a Singleton-type class and b) has at its root a property called currentClient. Here’s a peek:
pacakge com.foo.managers
{
public class ServiceValidationErrorManager
{
public var currentClient:IServiceValidationClient;
static private var _instance:ServiceValidationErrorManager;
static public function getInstance (){}//you get the idea....
}
}
The idea is pretty much the same as the first method in that our views serve as the IServiceValidationClient. When dispatching a Cairngorm event we register the client with the manager class (if applicable). Basically that is achieved by:
ServiceValidationErrorManager.getInstance().currentClient = this; //the view/implementor
So this fixes issues from the other two methods. Firstly it eliminates the need to pass the view to the command. Secondly it doesn’t get us tangled up in all these IEventDispatcher methods.
Now upon a response that has some validation errors, we can simply say:
ServiceValidationErrorManager.getInstance().currentClient.handleValidationErrors();
The other nice thing is that we needn’t really worry about garbage collection because we’re only dealing with one property on one class. It gets overwritten when needed. Now you may be asking why use a separate manager type class. Well you may want to have some logic in there for various things including queuing the views, and other crap I can’t think of right now.
summary
This could easily be adapted to a preexisting singleton model so you can reduce the need for the additional class. You just gotta remember its there. Also, even though you needn’t clear out the property on the manager, it does make good practice. Having a manager class allows you to do just that: manage validation errors appropriately. Of course this might be a grotesque oversimplification of a very serious need, you get the gist of the idea.
pros:
- OOP
- negates the use of IEventDispatcher logic in both view and command
- provides a centralized place to handle more robust registration for error handling
cons:
- adds another class
- still doesn’t address timing issue, unless you implement some queuing mechanism in the manager when setting the current client
- not as elegantly simple as method one
That’s it folks. 3 very ugly solutions to an ugly problem. Chime in and let me know how you do it. Thanks.
Filed under: actionScript, cairngorm, development, flex, tutorial, validation
client-side validation
In general validation takes place in two places within a RIA: the client and the services. Generally when creating a services-enabled flex application, you try to validate some of that data on the client. For instance, you want to check for necessary data (e.g. required form fields) and properly formed data (e.g. making sure an email address has the @ sign and a domain). This is what I call client-side validation. So what do I mean by “service validation errors”?
service validation
Let’s use the example of sending some registration data to a service. We the flex client have already validated the data and send it off. So let us assume we are sending a user name, password and email address. Obviously we want our user name to be unique and the flex client hasn’t a way to determine this. Instead it relies on some registration service to check for the uniqueness of the data being sent. Ok, let’s assume now that we have sent something that is already being used by another user. This is service validation (it may be called something entirely different which I am ignorant of, but this is what I call it for now). Now if you have a good system in place, you will want to get some data associated with the registration error that just occurred. So now that we are on the same page about the high level validation stuff let’s get a closer view in handling it in an application that uses Cairngorm
user experience ground rules
Firstly I am going to set some ground rules for an application. We are going to assume that any view whose data requires a service and validation response will prompt further user input within itself. So no popups/Alerts on top of some registration popup/view. Why not? Well these solutions came about from my client’s user experience design that doesn’t allow for such simple solutions. Plus it would negate the whole purpose of my posting
under-the-hood-process
- user enters data requiring validation
- client-side validation occurs (assume it passes)
- Cairngorm event dispatches with data
- command (I am scrapping delegates for the sake of simplicity) process sends out and awaits reponse
- service validation errors come back with response necessitating changes to data
- command needs to notify someone that data needs to be corrected
method one: referencing
For the OOP purist out there, this might not settle well. It certainly did not settle well with me. But it’s a pragmatic approach with very few pitfalls attached. For those familiar with AS2 and ARP this will be very familiar.
Firstly we need to establish some sort of protocol for handling the service validation errors coming back. A very simple and forceful solution would be to use an interface. Let’s call it IServiceValidationClient. Yeah that sucks but it gets the point across. Here is a glimpse of that interface:
package com.foo.validation
{
public interface IServiceValidationClient
{
function handleValidationErrors (errors:Array):void;
}
}
Our view will implement this interface. Now to make use of it. We need pass a reference of this implementor along with the call. Depending how hairy your application is, you may have tons of custom CairngormEvent subclasses. For simplicity, I will just use a basic subclass called FooEvent. It looks like this:
package com.foo.events
{
import com.adobe.cairngorm.control.CairngormEvent;
import com.adobe.cairngorm.vo.IValueObject;
import com.foo.ui.IServiceValidationClient;
import flash.events.Event;
public class FooEvent extends CairngormEvent
{
public var vo:IValueObject;
public var serviceValidationClient:IServiceValidationClient;
public function FooEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false)
{
super(type, bubbles, cancelable);
}
override public function clone ():Event
{
var evt:FooEvent = new FooEvent(type, bubbles, cancelable);
evt.vo = vo;
evt.serviceValidationClient = serviceValidationClient;
return evt;
}
}
}
So before we dispatch the FooEvent, we just say:
var evt:FooEvent = new FooEvent("doRegistrationDude");
evt.vo /* = the value object you should have assembled from the view's inputs */
evt.serviceValidationClient = this;
Ok, so at this point we are now dealing with the command. Upon execution, you need to store an instance level reference to the event.serviceValidationClient. This way you can grab it upon the response. If there happens to be an issue with the response, assuming you have standardized the errors somehow, you just grab that reference again and say:
serviceValidationClient.handleValidationErrors(errors);
Now there is one thing left to do. And this is very important. You need to do some clean up after you have utilized the response data. In this call you to make the command’s ref to the view null again or it will not get garbage collected.
serviceValidationClient = null;
Summary
pros:
- simple implementation
- provides an interface for standardization of error handling
- requires very little in additional coding/classes
- not highly coupled
cons:
- not very OOP
- requires that you remember to implement the interface
- requires garbage collection clean up
Ok so that is method one. I will post the other two methods in separate posts so as to make a short read of them.
Filed under: actionScript, amf, amfphp, cairngorm, development, flash, flex, mysql, orm, php, pog, remoting, tutorial, xml
Preface
If you are no stranger to the concept of a Rich Internet Application (aka. RIA) and the different constituents that make up a RIA, you can skip this introduction. This tutorial will help developers to setup a Flex application to a database using PHP while minimizing manual database queries. Let’s familiarize ourselves with a few basic RIA concepts. Generally a RIA is comprised of 3 main components:
- the client – no, not your client that sends the checks, but rather the Graphical (User) Interface that a user of a RIA interacts with. In our case, this the flex client that is deployed to a particular URL.
- the service layer -this component is the hidden part of the application that interprets client events, requests information stored on a database, and then sends the requested data back to the client. In our case AMFPHP, PHP and POG will be in this category. I will explain what these mean in a bit.
- the database – this is where our data is stored. In my case this is MySQL. Depending on your local setup, you may be using a different database.
For most of this tutorial we will be dealing with the client and the service layer. The service layer will be comprised of AMFPHP which is a very small framework which facilitates remoting between Flex and PHP. Remoting is simply a means to send and receive native ActionScript objects to a service layer. POG is another small framework for taking PHP objects and allowing CRUD methods for their database counterparts. CRUD stands for Create, Read, Update and Delete and POG simply stands for PHP Object Generator. In our case, we are setting up a RIA so that the objects sent to and from Flex will easily be able to be manipulated via CRUD methods. To sum this up we are establishing a seamless means of having Flex and a database to communicate with a minimum amount of manual data manipulation. If that confused the hell out of you, I apologize as I am kinda new to making tutorials.
Resources
POGTestApp client & server – link
AMFPHP v1.9 20070513 – link
POG – link
The Quest
Anyone who frequents this blog know that I have been on a mission for some time to get some sort of ORM setup for my pet-project. I didn’t want to be encumbered by a heavy framework with a complex API or inheritance structure. I’d looked at CakePHP, Doctrine, Propel, Junction and a few others. As a non-PHP guy, I found all of those to be overwhelming. I’d rather spend my time coding than having to read config documentation or learn a new API. That is not to say that I don’t want to learn something new, I do. I just felt enough of my time had been spent trying to find the right solution. The right solution had to be ultra-simple and intuitive.
Enter POG
POG stands for PHP Object Generator. I’ll spare you my praises of it for now (you can read up on their site if you like). Suffice it to say it is an ORM framework that is simple, intuitive and light weight. And it works for me. This looks like a long read, and it is, but it will go rather quickly. Lot’s of pictures too!!!
Your first Flex + AMFPHP + POG RIA
Server setup
I have my project setup in two places. One location is where my deployable flex content, AMFPHP and POG code goes. The other is simply where I house my Flex project source. Here is a pic of the deploy location:
I use MAMP (Mac + Apache + MySQL + PHP) which is a turnkey PHP server. It works well for me because I really didn’t like doing all the Terminal setup to get my Mac’s built in PHP setup for this. If my project makes it to the big time, then all this server side setup will be delegated to a more knowledgeable person who can set it up better than I have.
AMFPHP
Firstly I want to tackle the AMFPHP part since its probably the most straight forward part of the process. Go and download AMFPHP 1.9. I am using the 20070513 release. Once downloaded, unzip it and place it in the aforementioned deploy location. The only things you need to do for AMFPHP is:
- make note of you services folder (I put a symlink to the whole AMF folder in my flex project so I could have direct access to it from within Eclipse without having to use the bin folder).
- adjust the following information on the globals.php
- $servicesPath – in my case “services/”
- $voPath – this will point to your POG objects folder once we get it setup, in my case “../pog/objects/”
That is all on the AMFPHP aside from constructing your services.
[EDIT 2008.03.21]
Since initially this tutorial only happened to touch upon the setup of these technologies there hadn’t been any issues encountered. Obviously this tutorial didn’t reflect a real implementation of such a setup beyond the simple Get method. Further development has turned up an interesting find about sending AS3 objects out from Flex to be mapped to a POG object. As it is now, it can’t. That is because the naming convention chosen by the POG framework doesn’t get picked up by the AMFPHP deserializer. My gunslinger buddy Renaun Erickson has found a simple solution for this that doesn’t break the POG naming convention. You can read more about it on his blog – link.
You need to open the AMFBaseDeserializer.php and insert the following code at line 384:
elseif(file_exists($GLOBALS['amfphp']['customMappingsPath'] . 'class.' . strtolower($mappedClass) . '.php'))
{
$include = $GLOBALS['amfphp']['customMappingsPath'] . 'class.' . strtolower($mappedClass) . '.php';
}
POG
POG is unique in that you don’t just go and download a framework (at least not yet). If you visit POG, you are greeted with a little RIA that takes some information about the object you want to create. I decided to use the name TestObject and give it two properties: userName and password both being varchar(255). Just to reiterate, I am using the PHP5.1+ along with the POG database wrapper:
Notice that I am NOT using the PDO mysql wrapper. Reason being that AMFPHP has issues finding the mysql PDO driver and not everyone’s php environment contains those. So let’s stick to the POG database wrapper.
Since this is the first interaction with POG, we want to download the full framework in addition to you new object:
Then unzip the file, rename it simple as “pog” and place it in your deployment location. Next locate the {yourMainDeploymentFolder}/pog/configuration.php and update the needed information so that POG can access your database. Here is a snap of mine:
Notice that I have my mysql port set to 8889 rather than the default 3306? Also the plugin settings url is an absolute path. In your browser navigate to the following location: http://localhost{:yourPort}/{yourMainDeploymentFolder}/pog/setup/index.php. Go through the initial welcome/setup screen. POG will do some quick unit test, and if everything goes well, you are then presented with a portal to do basic CRUD methods on your new POG object. This is useful because we can setup a few test objects to use in setting up and testing the Flex application.
Now it would appear that POG is ready to go. And you’d be correct if you just want to use the local POG portal to play with it. In order to get it working with Flex and AMFPHP, you need to fix a few things with a few classes in POG. We will come back to that after we get the Flex project setup.
Flex
I am providing my POGTestApp source for you to download, but I also want you to see the steps necessary to do it yourself. First let’s create a new Flex project. I called mine POGTestApp. Now I also have mine located in a different place than the deployment location so I used some advanced options:
In the provided flex project, I have the Cairngorm.swc in the libs folder. Make sure to add the libs folder to the library path. Also point it to the services-config.xml:
Open the services-config.xml and make sure to modify the endpoint uri to point to your amfphp gateway.php:
Now at this point you should be able to modify your Services.mxml (ServiceLocator subclass) and add your php services there. If you downloaded the files I have provided, I suggest taking a look at Services.mxml. Since this is a testing application, I have a genericFaultHandler and a genericResultHandler in this file that you can add breakpoints to for debugging purposes. So even though I am making the calls from the application file without any responders, I am still listening for them in Services.mxml. Now if you decide to make some calls of you own, without using my files, you will notice that you get some errors or it just doesn’t seem to work. That is because POG needs some adjustments to work properly.
POG adjustments
Even though POG works inside the provided POG setup.php, it won’t want to play with Flex or AMFPHP unless you give it some help. Here are a few things to modify:
- open the class.database.php and hardcode your configuration.php settings in there. For some reason the global vars are not making through to the Database class. Since I suck at php, I was advised to put it here until a better solution is found.
- open the class.testobject.php (or whatever your POG object is named) and add the remoting string: var $_explicitType = YourRemotingClassNameHere.
- also add include_once(‘class.database.php’);to class.testobject.php.
That should do it. Make your own or use the POGTestingServices and play with it. Keep in mind that even though my provided files work, you might get some PHP specific errors that appear to fail silently. If you experience this behavior you need to check your php.log to see what the issue is. Generally its due to the remoting code rather than the POG code.
Retrospective
I really like the idea of remoting for prototyping. It takes the hassle away from having to parse your responses in flex. POG is an ideal solution for developers not that familiar with PHP as the objects translate rather easily and since it is OO, its easy to do the mysql input without having to get involved with writing queries.
When time is of the essence, maybe you will consider this beautifully simple solution. Thanks goes out to Joel Wan (POG) and Renaun Erickson (the gunslinger) for help sorting this out. Let me know if you have any advice, suggestions, criticism and or corrections for this tutorial.
[UPDATE]
Looks like a bounty hunter has stepped up to the task and fixed my issue. Right on man! Now I am sure I will be running into more AMF + POG + PHP issues in the future. If they get too time consuming or just can’t get em, I will be issuing further bounties. Thanks for the help R.E.!!!
[ORIGINAL]
So I have been really trying to tackle the whole ORM thing for a while now. I sometimes suspect that AMFPHP is just a pain. It deceivingly allows simple transactions between Flex, AMF, and MySQL when making manual queries. But trying to get it working with various frameworks just does not want to work. The only ORM I have successfully gotten to work with it is Junction which, though working and simple enough, has a funky API I just don’t like. Maybe if no other WORKING options are available, I will just digest it and proceed. But being OCD, I want something for me that makes a helluva lot of sense.
Enter POG. For those of you who don’t know what POG is, it stands for PHP Object Generator. The API is exactly what I am looking for. Simply update the object properties much like you would any ActionScript object. Okay so enough of the honeymoon BS. It works great outside of AMFPHP. But the minute it needs to work in concert with AMFPHP, if it makes any database call, it likes to crap out. Either it can’t seem to find the PDO driver, or it fails silently or some other stupid unknown reason.
I am issuing a bounty (a.k.a. monetary reward). I am going to be uploading my test project which will include the deployment and the flex source. If you can successfully make this P.O.S. work, then I will sending $150+ your way (if you think this is not enough, then let’s talk about it). Forums and user groups can get your far, but only so far. Here is(are?) the criteria:
- make a flex to service call entailing a successful CRUD method.
- have flex respond reflecting an ActionScript VO representation of the POG object.
- have the AMFPHP browser successfully be able to test the services.
- ensure that this will work in my dev environment which is MAMP (I really don’t want to have to mess with new environments. MAMP works great for me in many capacities).
Why am I issuing this bounty. Many reasons but the main two are:
- The opportunity costs for me trying to aimlessly figure this out on my own have cost me dearly. I’d rather make better use of someone else’s time by paying for their expertise allowing me to truly focus on the end game of getting my application out to the public.
- If there is a successfully melding of Flex + AMFPHP + POG, then we have just introduced a huge opening for the use of a very simple ORM framework. No more complex setups, no more funky APIs, no more manual queries. Just easy OOP the whole way throughout the development process. That way you as fellow developers do not incur costly opportunity costs as I have.
The test project source can be downloaded here. I look forward to some bounty hunters emailing me
=> jwopitz (at) gmail.
Depending on your services setup, and if you use Cairngorm, you have probably seen or written alot of code like this:
public function execute (event:CairngormEvent):void {
var call:AbstractOperation = ServiceLocator.getInstance().getWebService("someName").getOperation("someOperation");
So suppose you have many WSDLs or if you are like me and are using AMFPHP, you might have quite a few Remote Objects logically split up. For instance, you might have 6 RemoteObjects in your ServiceLocator subclass mxml. Like so:
<?xml version="1.0" encoding="utf-8"?>
<adobe:ServiceLocator
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:adobe="http://www.adobe.com/2006/cairngorm">
<mx:RemoteObject id="userServices" source="userServices" destination="amfphp" showBusyCursor="false"/>
<mx:RemoteObject id="journalServices" source="journalServices" destination="amfphp" showBusyCursor="false"/>
<mx:RemoteObject id="adminServices" source="adminServices" destination="amfphp" showBusyCursor="false"/>
<mx:RemoteObject id="activityServices" source="activityServices" destination="amfphp" showBusyCursor="false"/>
<mx:RemoteObject id="miscServices" source="miscServices" destination="amfphp" showBusyCursor="false"/>
</adobe:ServiceLocator>
I like being able to code quickly and know that I am pointing to the correct RemoteObject without a) having to look at the mxml to get the right name or b) hope that I remember what I called it. In order to do so I added a few lines of code in my <script/> tags to my ServiceLocator subclass named ApplicationServices.mxml:
public static function getInstance ():ApplicationServices {
return ApplicationServices(ServiceLocator.getInstance());
}
Now when I am quickly making command classes that I want to ensure use a particular RemoteObject without relying on the getRemoteObject() method and my fuzzy memory of what was named I can type:
public function execute (event:CairngormEvent):void {
var call:AbstractOperation = ApplicationServices.getInstance().userServices.getOperation("someOperation");
I think this is a bit cleaner and nicer looking. And its just one less step to have to remember or reference when creating your commands.
I promise this is the last posting I am doing for the HRule and VRule components. My buddy just kept on buggin’ me that he needed padding for the standard HRule and VRule components IN ADDITION to needing dashed styling. So I added it.
The source code on jwo_lib has been updated (haven’t updated the swc just yet).
Here is the new and improved HRule and VRule explorer.
Now I want to get into my proposed approach. If you are just now joining us and didn’t catch part 1, you can catch up here.
Keep in mind this is still in the infant stages and I am currently developing and rethinking how this works. I certainly welcome ideas, criticism, and recommendations on my approach. So please hammer away. Onto the code….
The first step is to allow our commands a means of firing events when they do their result and fault logic. So we need to extend the EventDispatcher class. I created a base class called CommandBase that extends the EventDispatcher and implements ICommand and IResponder. So we are still maintaining the whole Command architecture in respect to Cairngorm 2.1. You could easily do this using the deprecated Cairmgorm Responder interface as well. So now every command we create just needs to extend CommandBase and override the execute, result and fault methods. But in doing so we need to make sure to call the super.execute(), super.result() and super.fault() methods as well or at least dispatch those events when overriding. Here is some sample code:
[Event (name='execute', type='flash.events.Event')]
[Event (name='result', type='flash.events.Event')]
[Event (name='fault', type='flash.events.Event')]
public class CommandBase extends EventDispatcher implements ICommand, IResponder {
public function execute (event:CairngormEvent):void {
dispatchEvent(new Event('execute'));
}
public function result (data:Object):void {
dispatchEvent(new Event('result'));
}
public function fault (info:Object):void {
dispatchEvent(new Event('fault'));
}
}
Really simple stuff and in fact it looks exactly like your regular ol’ Cairngorm Commands you have been using for quite awhile. Next we need to setup a Sequence type Command. I decided to go with SequenceCommandBase which extends…yep, you guessed it CommandBase. Why? Well, code reusage for one and also I think there may be some crazy times when you want to nest these guys. Now SequenceCommandBase has quite a bit of added stuff in order to work correctly. We have a command queue, a current index, and a command log that we can use for tracing and tracking stuff. We also have added a few more methods which I will go into detail. When I started thinking about how to decouple these sequenced commands, I came up with a few thoughts on what was needed to assist this concept:
- a reference to the command class
- events for the commands
- contingency for a failed command within the sequence
Well the first point is handled pretty much the same way Cairngorm’s FrontController handles creating new events. You pass a class reference and it create a new instance of that particular class. Like in a mx.effect.Sequence we need a means of attaching child commands. I chose to use addCommand rather than addChild. I am passing a few parameters as well and assigning event handlers to the command’s result and fault events. The tricky part is how to handle events for the commands in question during the execution phase.
In a normal application of the command pattern, we just dispatch our CairngormEvent via the CairngormEventDispatcher. So events are created and almost immediately used. In our case, we are predefining the events. Normally this is not an issue. We can just create them when we add the commands and then when the commands are executed, we pass the predefined events in with it. But what happens if there are what I call data modification dependencies? Meaning what if there is a dependency on data that may be altered by a previous command’s result or failure. For example, commandTwo needs a value in the Model which currently is set to “”. And we need commandOne’s result to set that value in the Model. If we are predefining these events based on those values then we will get the original value and not the previous command’s result’s assigned value. Right now, I have a solution, but not a very elegant solution. For now I am passing an event modifier function as another parameter when we add child. These modifiers will most likely be defined in the subclasses of SequenceCommandBase.
Next we need to execute each command. I called it executeCurrentCommand. Pretty original huh? Basically it does a few things. It does what it says namely, but before doing so it also does the following:
- checks to see if we have an event,
- if not creates a generic CairngormEvent,
- sees if there is any needed modification to the non-generic event if we passed in during addCommand,
- creates an instance of the current command class (remember which will be a subclass of CommandBase).
- executes the current command and passes the current event as the parameter.
So you might be thinking, isn’t that what the FrontController does? Yes. But unfortunately since the FrontController subclasses create new instances of the needed commands on the fly, we can’t really tap into that functionality. So right now the SequenceCommandBase is also subbing as a mini-FrontController.
The next set of methods are really event handlers for the current command’s result/fault events. But they do handle the contingency logic for what happens if something fails. But first I should explain the command queue a bit further. It not only stores the commands, it also stores references to their respective events, event mod functions, and the boolean values as to handle what to do on failures. So when the current command fails or succeeds then the respective event chimes in and says, “well if he succeeded then go on to the next command, but if he failed then we need to follow his contingency booleans and execute the logic to see if we proceed or blow chunks.”
So I guess this would be a really good time to start pasting more code. Okay here is a sample of the addCommand method:
public function addCommand (commandClass:Class,
event:CairngormEvent = null,
eventModificationLogic:Function = null,
continueOnFaultFail:Boolean = false,
jumpOnFaultFail:Boolean = false,
jumpIndex:int = 0):void {//is there a more elegant way of handling this?
var command:CommandBase = new commandClass();
command.addEventListener(‘result’, onResult_currentCommandHandler);
command.addEventListener(‘fault’, onFault_currentCommandHandler);_commandQueue.push([command, event, eventModificationLogic, continueOnFaultFail, jumpOnFaultFail, jumpIndex]);
}
Here is a glimpse of what is currently the logic behind the execution:
protected function executeCurrentCommand ():void {
//checking to see if we need to update the event before executing the currentCommand
if (_commandQueue[_currentIndex] [SEQ_EVENT_MOD_INDEX]){
var func:Function = _commandQueue[_currentIndex] [SEQ_EVENT_MOD_INDEX] as Function;
}var currentCommand:CommandBase = _commandQueue[_currentIndex] [SEQ_COMMAND_INDEX] as CommandBase;
var commandEvt:CairngormEvent;if (_commandQueue[_currentIndex] [SEQ_EVENT_INDEX] == null){
commandEvt = generateGenericEvent();
} else {
commandEvt = _commandQueue[_currentIndex] [SEQ_EVENT_INDEX] as CairngormEvent;
}currentCommand.execute(commandEvt);
}
And finally here is some quick code for the handlers :
protected function onResult_currentCommandHandler (evt:Event):void {
updateLog(‘RESULT’);
_currentIndex++;
executeCurrentCommand();
}protected function onFault_currentCommandHandler (evt:Event):void {
var allowPassThru:Boolean = _commandQueue[_currentIndex] [SEQ_ALLOW_CONTINUE_INDEX] as Boolean;
var allowJumpTo:Boolean = _commandQueue[_currentIndex] [SEQ_ALLOW_JUMP_INDEX] as Boolean;
var jumpTo:int = _commandQueue[_currentIndex] [SEQ_JUMP_INDEX] as int;if (allowPassThru){
if (allowJumpTo){
updateLog(‘FAULT JUMP’);
_currentIndex = jumpTo;
} else {
updateLog(‘FAULT PASS’);
_currentIndex++;
}executeCurrentCommand();
} else {
updateLog(‘FAULT TERMINATE’);
fault(_commandLog);
}
}
I apologize for the fact I don’t have a REAL blog where I can format the code. Maybe here shortly I will, but for now I am stuck with the free online blog @ wordpress.
Anywho. Let me know some of your thoughts. Again, keep in mind that this is just a proof-of-concept in progress and will evolve.
Thanks ,
Jwopitz
With an ever-growing code base on our ever-growing project, I have been doing quite a bit of thinking regarding the Cairngorm SequenceCommand. It seems that every time we add a new feature, we have to add at least one new command, that is just a slight variation on the same thing. This is especially true in our initialization of our application. It could be even more true if you were using a modular type approach to building your applications.
During the initialization of our application, a chain of SequenceCommands fire off to get their needed data. There are also times that this same information needs to be retrieved out-of-sequence or retrieved solely on its own. So in a traditional approach, you would have a regular Cairngorm Command subclass when you need this information out-of-sequence, and then an almost duplicate Cairngorm SequenceCommand for those times previously mentioned. So essentially you are duplicating the needed code to achieve the same results. And the reason this is, is because the logic to perform the ‘guts’ of the SequenceCommand has some dependencies on the next command to be called. This then can have an effect not only the command in question but also the possible command preceding it and/or the next command as well.
I don’t like this for a few reasons:
- unnecessary code duplication.
- code dependencies at the logic level of the commands (increased coupling?).
- ripple effects for related commands.
So I started to think about how to make this process more efficient. How could I achieve code re-usage and still maintain the ability to ’sequence’ commands together. I have been looking at how the mx.effects classes work. You can have a Move instance do something once like move a box from ptA to ptB. You can also have several other effects do their tasks, and then turn around and use your Move instance again. You can even chain Move along with those other effect to fire off in sequence with out modifying the original instances’ properties. So why can’t the same be applied to how we chain commands together? I think it can with very little effort. We’ll talk about the details in part 2.







