Prana enabled Cairngorm Store
ActionScript, Cairngorm, Flex, Inversion of Control, Prana Add commentsFollowing up on Douglas McCarroll's modified Cairngorm Store update, I thought I'd take this a step further and add a Prana application context to configure the business delegates and the service locator. This example has support for mock delegates that contain hardcoded local data and is also able to connect to php services using Remote Objects and AMFPHP.
This examples replaces the older Cairngorm Store example that was configured to work with AMF0 and Renaun Erickson's RemoteObjectAMF0. It now uses the latest beta version of AMFPHP and the AMF3 protocol. The services are hosted on this domain so you don't need to setup AMFPHP in order to see this in action.
The code is currently in svn and can be checked out at http://prana.svn.sourceforge.net/viewvc/prana/trunk/samples/PranaCairngormStore/. This sample will also be included in the next release.
Here's a snippet from the readme file:
***
The following files have been added/changed in order to add Prana configuration support for business delegates and service locator:
* Main.mxml: added application context loader and forced compilation of configured classes
package com.adobe.cairngorm.samples.store.business
* BaseBusinessDelegateMock.as: implements IResponderAware, removed responder constructor argument
* CreditCardDelegate.as: extends AbstractRemoteObjectDelegaten, implements ICreditCardDelegate
* CreditCardDelegateMock.as: implements ICreditCardDelegate
* ICreditCardDelegate.as: interface for credit card delegates
* IProductDelegate.as: interface for product delegates
* ProductDelegate.as: extends AbstractRemoteObjectDelegaten, implements IProductDelegate
* ProductDelegateMock.as: implements IProductDelegate
package com.adobe.cairngorm.samples.store.commands
* GetProductsCommand.as: added delegate lookup via ShopModelLocator
* ValidateCreditCardCommand.as: added delegate lookup via ShopModelLocator
package com.adobe.cairngorm.samples.store.model
* ShopModelLocator.as: added creditCardDelegate and productDelegate variables to configure business delegates
***
As a result, we can now lookup the implementation of our business delegates in the commands instead of instantiating new ones. The commands are completely unaware of the implementation of the business delegates. One note though: since we are not creating new delegate instances, we need to set the responder as a property of the delegate before calling its methods.
-
var delegate:IProductDelegate = ShopModelLocator.getInstance().productDelegate;
-
delegate.responder = this;
-
delegate.getProducts();
Here's how the application is configured in the application context to use the mock delegates:
-
<object id="shopModelLocator" class="com.adobe.cairngorm.samples.store.model.ShopModelLocator" factory-method="getInstance">
-
<property name="creditCardDelegate">
-
<object class="com.adobe.cairngorm.samples.store.business.CreditCardDelegateMock"/>
-
</property>
-
<property name="productDelegate">
-
<object class="com.adobe.cairngorm.samples.store.business.ProductDelegateMock"/>
-
</property>
-
</object>
And here's how the remote object delegates and the service locator are configured:
-
<object id="endPoint" class="String">
-
<constructor-arg value="http://www.herrodius.com/amfphp/gateway.php"/>
-
</object>
-
-
<object id="serviceLocator" class="org.pranaframework.cairngorm.CairngormServiceLocator" factory-method="getInstance">
-
<property name="productService">
-
<object class="mx.rpc.remoting.mxml.RemoteObject">
-
<property name="destination" value="GenericDestination"/>
-
<property name="endpoint">
-
<ref>endPoint</ref>
-
</property>
-
<property name="source" value="com.adobe.cairngorm.samples.store.business.ProductService"/>
-
</object>
-
</property>
-
<property name="creditCardService">
-
<object class="mx.rpc.remoting.mxml.RemoteObject">
-
<property name="destination" value="GenericDestination"/>
-
<property name="endpoint">
-
<ref>endPoint</ref>
-
</property>
-
<property name="source" value="com.adobe.cairngorm.samples.store.business.CreditCardService"/>
-
</object>
-
</property>
-
</object>
-
-
<object id="shopModelLocator" class="com.adobe.cairngorm.samples.store.model.ShopModelLocator" factory-method="getInstance">
-
<property name="creditCardDelegate">
-
<object class="com.adobe.cairngorm.samples.store.business.CreditCardDelegate"/>
-
</property>
-
<property name="productDelegate">
-
<object class="com.adobe.cairngorm.samples.store.business.ProductDelegate"/>
-
</property>
-
</object>
Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
Christophe Herreman is a software developer living in Belgium. He's working on high-end Flex and AIR solutions at 
February 25th, 2008 at 3:47 pm
Very interesting, Christophe.
It might make the first example a bit clearer to do it thus:
In GetProductsCommand:
We say this:
var delegate:IProductDelegate = ShopModelLocator.getInstance().productDelegate;
delegate.responder = this;
delegate.getProducts();
Rather than this:
var delegate : ProductDelegateMock = new ProductDelegateMock( this );
delegate.getProducts();
Also, a few words on why Inversion of Control makes it easier to write and maintain code might be a useful addition. At first glance people unfamiliar with this pattern might say, “What’s the payoff?”
Or, you could just link to http://en.wikipedia.org/wiki/Inversion_of_control. It’s got a nice succinct section on advantages and disadvantages.
On second thought, I guess I just did.
March 11th, 2008 at 12:05 pm
Hi Christophe,
i’ve connection problems to your svn. Could you add a download link here? Thanks Hagen
March 11th, 2008 at 1:46 pm
Hi Hagen,
please see the nightly builds at http://prana.herrodius.com/
regards,
Christophe
April 10th, 2008 at 11:01 am
Hi!
Doesn’t this cause a concurrencty isssue?
var delegate:IProductDelegate = ShopModelLocator.getInstance().productDelegate;
delegate.responder = this;
delegate.getProducts();
If the user is hyperactive and clicks on several buttons calling the product delegate he will overwrite the responder property, causing some actions not to be executed properly!
April 10th, 2008 at 3:52 pm
Hi Roberto,
that would indeed be a problem. This approach hence needs to be used when you can make sure only 1 call to the delegate will be made, for instance by disabling the UI until the response is received.
The best thing would be to have a delegate factory that is configured and stored in the modellocator and is then used inside the command to create a new delegate every time you need one.
April 16th, 2008 at 9:11 am
Blocking the user interface is as you know against the principle of a remote application so I do think that an other approach must be taken.
What is not clear to me using cairngorm/prana is which objects are meant to be reused and which one are not. In order to keep performance to the maximum, I guess that it would be nice to have the command and business delegates as singletones (this is btw coherent with the patterns used in spring). They do not need to keep any state. Besides, defining more than one method on a business delegate will need to set, through a property or through constructor, a lot of delegates. In my opinion is much simpler to accept a responder as argument of the business delegate call (altough it clutters the interface). It will solve all the concurrency problems and make more explicit how the result will be handled.
April 16th, 2008 at 12:15 pm
Hi Roberto,
it depends on what you see as blocking the UI. If you are firing a remote call that will load a big chunk of data, then I think it is perfectly acceptable to show a loading screen which informs the user and at the same time prevents the UI from being used.
About object reusability: I’m not sure if we should see commands and delegates as singletons. As you say, you would have to alter the interfaces so that responders can be passed in to the delegate methods. I think that a event/command/delegate sequence should really be handled by some sort of a factory mechanism that creates a new command and delegate each time. I don’t think performance will be an issue here. That way the concurrency problems would also be solved.
I like discussing this with you (and others). Would you mind subscribing to the mailinglist – if you haven’t already – so we can also get input from other developers? Thx for your time and interest! https://lists.sourceforge.net/mailman/listinfo/prana-user
April 17th, 2008 at 9:00 am
You are right, I’ll move to the mailing list!
September 17th, 2008 at 4:05 pm
Changes with AbstractRemoteObjectDelegate seem to corupt this project.
December 19th, 2008 at 12:07 am
Hi,
I’m using Prana framework with Flex application(Flex Builder3). I have problem but its not consisitant, service object is null sometimes.
service = CairngormServiceLocator.getInstance().getRemoteObject(“bgwpmMetadateService”);
and my xml
Any idea to solve this issue?
Thanks,
karthik
December 19th, 2008 at 9:23 am
Hi Karthik,
the xml seems the have disappeared, so I have no idea what is going on. Please join our forum at http://forum.springframework.org/forumdisplay.php?f=60 and repost your question there.
thx,
Christophe