Defining multiple RemoteObjects in MXML

Is it possible to define multiple RemoteObjects in MXML?

For instance:

//amf_tests.mxml


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 layout="absolute"
 creationComplete="init()">

<mx:Script>
<![CDATA[

  import mx.collections.ArrayCollection;
  import mx.rpc.events.ResultEvent;
  import mx.controls.Alert;

  [Bindable] private var serviceTypes:Object; // the remote object service names and instances
  [Bindable] private var ro:RemoteObject; // the selected service

  private function init() {
    serviceTypes = { amfphp: amfphp_ro, zendamf: zendamf_ro, sabreamf: sabreamf_ro };
  }

  private function sendRemoteServiceRequest():void {
    ro = serviceTypes[serviceType.text];

    ro.sayHi();
    ro.sayBye();
  }

  private function resultHandler(event:ResultEvent):void {
    Alert.show(event.result.toString());
  }

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

  private function getKeys(obj:Object):ArrayCollection {
    var keys:ArrayCollection = new ArrayCollection();

    for (var key:String in obj) {
      keys.addItem(key);
    }

    // there's got to be a better way to sort than this
    keys = new ArrayCollection(keys.toArray().sort(Array.CASEINSENSITIVE));
    return keys;
  }

\]]>
</mx:Script>

<mx:RemoteObject id="amfphp_ro" source="amf_tests_amfphp.HelloWorld" destination="amfphp">  
  <mx:method name="sayHi" result="resultHandler(event)"/>   
  <mx:method name="sayBye" result="resultHandler(event)"/> 
</mx:RemoteObject>

  <mx:RemoteObject id="zendamf_ro" source="amf_tests_zendamf.HelloWorld" destination="zenfamf">  
    <mx:method name="sayHi" result="resultHandler(event)"/>   
    <mx:method name="sayBye" result="resultHandler(event)"/>
  </mx:RemoteObject>

  <mx:RemoteObject id="sabreamf_ro" source="amf_tests_sabreamf.HelloWorld" destination="sabreamf">
    <mx:method name="sayHi" result="resultHandler(event)" fault="faultHandler(event)"/> 
    <mx:method name="sayBye" result="resultHandler(event)"  fault="faultHandler(event)"/>
  </mx:RemoteObject>

  <mx:HBox>     <mx:Label text="Service Type:"/>
    <mx:ComboBox id="serviceType" dataProvider="{getKeys(serviceTypes)}"/> 
    <mx:Button label="Send Request" click="sendRemoteServiceRequest()"/>
  </mx:HBox>

</mx:Application>

// services-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<services-config>

 <services>

 <service id="amfphp-flashremoting-service"
 class="flex.messaging.services.RemotingService"
 messageTypes="flex.messaging.messages.RemotingMessage">
 <destination id="amfphp">
 <channels>
 <channel ref="my-amfphp"/>
 </channels>
 <properties>
 <source>*</source>
 </properties>
 </destination>
 </service>

 <service id="zendamf-flashremoting-service"
 class="flex.messaging.services.RemotingService"
 messageTypes="flex.messaging.messages.RemotingMessage">
 <destination id="zendamf">
 <channels>
 <channel ref="my-zendamf"/>
 </channels>
 <properties>
 <source>*</source>
 </properties>
 </destination>
 </service>

 <service id="sabreamf-flashremoting-service"
 class="flex.messaging.services.RemotingService"
 messageTypes="flex.messaging.messages.RemotingMessage">>
 <destination id="sabreamf">
 <channels>
 <channel ref="my-sabreamf"/>
 </channels>
 <properties>
 <source>*</source>
 </properties>
 </destination>
 </service>
   </services>

 <channels>

 <channel-definition id="my-amfphp" class="mx.messaging.channels.AMFChannel">
 <endpoint uri="/amfphp/gateway.php" class="flex.messaging.endpoints.AMFEndpoint"/>
 </channel-definition>

 <channel-definition id="my-zendamf" class="mx.messaging.channels.AMFChannel">
 <endpoint uri="/zendamf/index.php" class="flex.messaging.endpoints.AMFEndpoint"/>
 </channel-definition>

 <channel-definition id="my-sabreamf" class="mx.messaging.channels.AMFChannel">
 <endpoint uri="/sabreamf/index.php" class="flex.messaging.endpoints.AMFEndpoint"/>
 </channel-definition>

 </channels>

</services-config>

Maybe there’s a typo, but amfphp works, and all the others claim there’s no channel associated with the destination:

[MessagingError message=’Destination ‘sabreamf’ either does not exist or the destination has no channels defined (and the application does not define any default channels.)’]

My workaround is to declare the other RemoteObjects in the init() function and not try to use the <mx:RemoteObjects> and the services-config.xml. Definitely less elegant:

 
private function init():void
 {
   zendamf_ro.source = "HelloWorld";
   zendamf_ro.destination = "zendamf";
   zendamf_ro.endpoint = "http://localhost/zend_amf/index.php";
   sabreamf_ro.source = "HelloWorld";
   sabreamf_ro.destination = "sabreamf";
   sabreamf_ro.endpoint = "http://localhost/SabreAMF/index.php";

   serviceTypes = {amfphp: amfphp_ro, zendamf: zendamf_ro, sabreamf: sabreamf_ro};
  }

Defining a RemoteObject in ActionScript without -services compiler flag

I ran across a problem today trying to define a RemoteObject (mx.rpc.remoting.mxml.RemoteObject) in ActionScript instead of a services-config.xml file.

It seems like it would be fairly straightforward

 var myRo:RemoteObject = new RemoteObject();
 myRo.source = "amf_tests.HelloWorld";
 myRo.destination = "amfphp";
 myRo.endpoint = "/amfphp/gateway.php";

but, alas, I found that endpoint isn’t a property, though it looks like it might be in the future. It isn’t even a readily accessible class. You need to build a channelset, add a channel, and then pass a url (and id) to the channel to specify the endpoint. Something like this:

 myRo.channelSet(new ChannelSet().addChannel(new AMFChannel("my_amfphp", "/amfphp/gateway.php")));

The above is equivalent to the following services-config.xml (I think):

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
 <services>
  <service id="amfphp-flashremoting-service" class="flex.messaging.services.RemotingService" messageTypes="flex.messaging.messages.RemotingMessage">
   <destination id="amfphp">
    <channels>
     <channel ref="my_amfphp"/>
    </channels>
    <properties>
     <source>*</source>
    </properties>
   </destination>
  </service>
 </services>
 <channels>
  <channel-definition id="my-amfphp" class="mx.messaging.channels.AMFChannel">
   <endpoint uri="/amfphp/gateway.php" class="flex.messaging.endpoints.AMFEndpoint"/>
  </channel-definition>
 <channels>
</services-config>

This explains it better than me.

Actionscript collections

This guy implemented HashMap among other things.  Looks like you just have to cut and paste the listings to get it.
http://www.ericfeminella.com/blog/actionscript-3-apis/

The real problem is, you should be able to iterate over an associative array and get it’s values using array syntax.  I don’t want to call HashMap.put(key, object) and HashMap.get(key) every time.  I want to create an object declaratively like

var foo:Object = {myKey:myObject, anotherkey:anotherObject};

I then want to pass the keys to a dataProvider with foo.getKeys() or retrieve data with foo[‘mykey’].

I tried creating tacking a function onto the prototype

Object.prototype.getKeys = function(){
  var keys:ArrayCollection = new ArrayCollection();
  for each (key in this)
  {
    keys.addItem(key);
  }
  return keys;
}

But that didn’t seem to work.  (obviously we don’t want to add getKeys() to Object, so I’d create a class that extends Object, only I can’t find out an easy way to pass the literal instantiation

{myKey:myObject, anotherkey:anotherObject};

to the base Object.

Here’s another rant about actionscript and collections:

http://blog.iconara.net/2007/11/25/architectural-atrocities-part-8-is-there-no-equality/

moccasin – flex graphical framework

Moccasin looks very interesting for Taskboard.  Move, resize, and undo are built into the framework:

Excerpted from this description by the author of moccasin, Joe Berkovitz:

Moccasin is not a “thin” framework that encapsulates a set of recommended practices like Cairngorm. It’s more of a “thick” framework. Moccasin is aimed at building a particular type of app: one with interactive graphical views that support a lot of mouse gestures, have some notion of compound or nested views, have some notion of a current selection, a clipboard for cut/copy/paste, need robust undo/redo, and must load and save documents to persist the editor state. The views in question are generally not Flex UIComponents in Canvases or Boxes, but lower-level Flash DisplayObjects that can have very arbitrary shapes and layout geometries. Within this domain, Moccasin very much adheres to an MVCS way of thinking: there is a model representing the edited document’s state, a set of views that adjust to the model’s state via events, a controller which changes the model in response to user actions, and a set of services responsible for talking to the world around and outside the application.

Joe Berkovitz is the same guy that wrote the article introducing the MVCS blueprint and is also behind the really cool music notation program Noteflight.

flex mvc frameworks

There’s probably already more than enough commentary out there about Flex MVC frameworks.  Instead of adding my limited knowledge to the noise, I’ll link to other discussions.

http://www.anandvardhan.com/2008/11/13/popular-flex-frameworks/

a good primer discussion of several different frameworks and their basic design decisions.  Includes PureMVC, Cairngorm, Mate, Penne, Swiz, easyMVC, Guasax, Model-Glue Flex, & Ruboss.

http://www.adobe.com/devnet/flex/articles/flex_framework.html

compares Cairngorm, Mate, PureMVC, and Swiz with a well-thought-out opinion of strengths and weaknesses of each.  Somewhat surprising coming from an Adobe site, but they’re not trying to sell Cairngorm.

http://www.asserttrue.com/articles/2007/10/17/silvafug-application-frameworks-presentation

A great presentation by Ali Mills and Luke Bayes of PatternPark which helps narrow down the list, and has a discussion about PureMVC and Cairngorm. Summary: they really like PureMVC and dislike Cairngorm.  I think there’s pretty much a consensus that Cairngorm is the EJB 1.0 of Flex framworks.

Frameworks they eliminated due to lack of documentation or community:

  • Slide – doesn’t exist
  • ARP – by Aral Balkan, abandoned
  • Servebox Foundry – not really an MVC framework (they later say it’s worth a second look)
  • Guasax – too early stage, runtime XML configuration (a la Spring), only in Spanish
  • Flest
  • MVCS – by Joe Berkovitz – a blueprint not really a framework – definitely worth reading the article though
  • Model:Glue – port of CF framework, not MVC

Their summary also says they don’t use any particular framework, but that understanding the patterns is important, and Flex itself is often good enough without another framework if you can follow the proper patterns and make correct architecture choices on your own.

If you only look at one framework, look at Cairngorm (because everyone else is using it), but if they had to pick one framework, they’d choose PureMVC.

Note: my characterization of their comments does not necessarily accurately represent their opinions.

http://robsondesign.com/blog/index.php/2009/04/02/puremvc-vs-cairngorm-revisited/

Like the title says, a comparison of PureMVC and Cairngorm, which seem to be the two dominant frameworks.  Mate and Penne seem popular as well among the fans of simplicity in a framework.

http://www.adobe.com/devnet/flex/articles/blueprint.html

Joe Berkovitz’s discussion of MVCS mentioned by Luke & Ali.  It’s definitely worth reading, and includes a sample app that shows a concrete example of his ideas, if not an actual framework.

http://corlan.org/flex-frameworks/

A good list of frameworks, not just MVC, but everything from testing and continuous integration to  remoting  and 3d engines.

http://myflex.org/presentations/ComparingFlexFrameworks.pdf

A comparison of Cairngorm, Mate, PureMVC, and Clear Toolkit, by (I think) the creator of Clear Toolkit.  The first three are MVC frameworks, but Clear Toolkit is a library.  Has a very good architectural overview of each framework.

serverside communication in Flex

The basic web service components are HTTPService and WebService.

HTTPService is roughly analogous to XMLHTTPRequest in AJAX/DHTML.  It sends plain text, but is typically used to return XML data from REST-like requests (simple HTTP GET/POST, etc.)

WebService is used for SOAP-style RPC access.

Adobe has Livecycle Data Services (LCDS) and BlazeDS for remoting .

LCDS and BlazeDS use AMF, the Actionscript Message Format, a binary data serialization that reduces the size and processing complexity of of XML formats.

BlazeDS is a subset of what’s available in LCDS, and includes ProxyService, RemoteService, and MessageService.

ProxyService is an HTTP Proxy, prinicipally used to get around the cross-domain security constraint.  [rant deleted]

RemoteService uses RPC-style communication, maintaining client-side objects in Actionscript and POJOs on the server that are managed by the data service.

MessageService uses a Publish/Subscribe method, similar to RSS.  Clients can both publish and subscribe to data services, which is polled either periodically, or with a ‘long poll’  that uses (I think) HTTP timeouts (e.g, chat.-style communication.)  Besides text messages, Actionscript objects can be sent either in the body or as headers.  It also includes support for streaming.

LCDS includes Real Time Messaging Protocol (RTMP) messages, which allow persistent connections. You can simulate a persistent connection with BlazeDS long polling, but this doesn’t scale very well.

Cold Fusion includes Flash Remoting, but I’m not interested in this, as I’m not working directly with either CF or Flash.

Third party libraries like AMFPHP, SaberAMF Zend AMF, WebORB, RubyAMF, PyAMF, AMF.NET, FlourineFX, etc., can talk directly to Flex apps via AMF natively in the various languages (PHP, Ruby, Python, .NET), and not needing the java-based BlazeDS/LCDS from Adobe.

There is another intereting protocol I don’t know much about called SWX, which is essentially a subset of the native flash format (SWF) in a similar way that JSON is a subset of Javascript designed for client-server object passing.  It looks quite interesting, but I don’t know how much functionality is built around it.  SWXFormat is currently implemented in PHP.

Clear Toolkit has something interesting called a Change Object, which they say is similar to what’s offered by Data Management Services in LCDS.   It looks particularly interesting for collaboration apps like Taskboard and Harvest.

Other interesting projects include:

GraniteDS aims to be an open source alternative to LCDS, geared towards EJB3, Seam, and Spring (Java frameworks.)

SpiceFactory has another open source remoting framework.  Pimento is for data managment and Cinnamon for remoting. (Parsley is an MVC framework also by SpiceFactory.)