Adobe publishes AMF3 spec

Adobe open-sourced their FDS (Flex Data Services) product today, and along with it published the AMF3 spec (this time without NDA!).

FDS, re-branded as BlazeDS is available under a LGPL v3 license. In their press release they also mention AMFPHP a couple of times, which is great news for the PHP community, because it implies they are backing the open source implementations.

I wanted to make sure the AMF implementation in SabreAMF is correct, by checking out the official spec. The spec is not really helpful though. It only covers AMF3, and missing some of the details. I guess I'm going to have to reverse engineer the 122MB behemoth that is BlazeDS.

SabreAMF 0.7

It's been crazy crazy busy at work, so sadly because of this I haven't been able to spend enough time on SabreAMF ..

Therefore, no new features.. just wanted to get this bugfix release out.

Hopefully after april, I'll be able to spend some time on my own projects again, including sabreamf..

Changes:

  1. Changed ArrayCollection to allow pushing new items through [].
  2. Fixed a major bug in the AMF3 deserializer which would appear with multiple requests in the same http package.. (found by Kevin Koster)
  3. Fixed some PHP5.0.x compatibility problems (not a goal of the project, but this was long hanging fruit..
  4. Speed fix in SabreAMF_Server.. now using file_get_contents instead of fopen.. (found by Develar)
  5. Major speed improvements in the AMF3 deserializer.. This patch also came from Develar (thanks a lot for this one!).

Downloads can be found here.

SabreAMF 0.6 -> upgrade recommended

Edwin Koster found a pretty big bug in AMF3 deserializing, which was actually also identified by Patrick Mineault right before my vacation.. Thanks for those bug reports!

That one's fixed now.. It was related to AMF3 object deserialization. For the people using SabreAMF for their flex projects: Upgrading is highly recommended!

IExternalized and ArrayCollection

Additionally, I added IExternalized-object support. What most likely the biggest change is for people, is that the ArrayCollection object now arrives differently. Before it would have been an anonymous object with the 'source' property containing the data, now there's an actualy php equivalent for the ArrayCollection object, namely SabreAMF_ArrayCollection.

If you want to see how it works, I'd recommend simply checking out the source.

For people who don't know PHP5's SPL objects too well, the ArrayCollection implements IteratorAggregate, Countable and ArrayAccess.. in practice this means you can do most general Array operations on this object..

  1. <?php
  2.  
  3. $data = array();
  4. $data[] = array('property1'=>'yo','property2'=>'test2');
  5. $data[] = array('property1'=>'foo','property2'=>'bar');
  6.  
  7. $arrayCollection = new SabreAMF_ArrayCollection($data);
  8.  
  9. foreach($arrayCollection as $row) {
  10.  
  11. // So yea, you can just loop through it like a normal array (done through IteratorAggregate)
  12.  
  13. }
  14.  
  15. // Or get values straight from a certain row (done through ArrayAccess)
  16. echo($arrayCollection[0]['property1']);
  17.  
  18. // Or get the total number of rows (done through countable)
  19.  
  20. echo(count($arrayCollection));
  21.  
  22. // In the case you need a normal array, based on the ArrayAccess class
  23.  
  24. $normalArray = iterator_to_array($arrayCollection);
  25.  
  26. ?>

If you want to check out how to create your own externalized objects.. (remember this always has to go paired; create one in flex, and create one in php), base your class on the SabreAMF_Externalized interface.

Also, be sure to let me know if there are any other well known flex classes that could really use SabreAMF equivalents..

The only other change is, that if exceptions don't provide a value for the 'code' property, the classname is passed by default.

Upgrade/Download

As usual you can upgrade using:

  1. pear upgrade http://www.rooftopsolutions.nl/code/SabreAMF/downloads/SabreAMF-latest.tgz

Or do a fresh install with:

  1. pear install http://www.rooftopsolutions.nl/code/SabreAMF/downloads/SabreAMF-latest.tgz

Mailing list

I'd also like to point out that there's a mailing list do drop your questions.. The response might be quicker than the comment box..

Subscribe at osflash

SabreAMF 0.2 is here

I just published a new version of SabreAMF, and it includes support for the flex2 messaging system. This means you can now use flex2 remoting with great ease.

It also includes a callback server class, which is now recommended for use with flex2. This class handles the standard AMF3 stuff like CommandMessages and translates Exceptions into ErrorMessages.

You can download it here. You can find an example on how to use the CallbackServer class here. An article on how to use this will follow shortly.

Decoding AMF3

Although I thought i was well on my way in decoding the AMF3 format, it seems that there's still some stuff not working correctly.

The SabreAMF deserializer is working perfectly, but there's issues with the serializer part.. While the deserializer is built loosely and accomodating for possible bugs from a different serializer, the SabreAMF serializer has to be built as strict as possible. My own produced AMF data seems to decode fine in my own deserializer, but Flex seems to have an issue with it, and throw s and index out of range error.

The guys over at Fluorine (an AMF server implementation for .NET seem to have stuff working in their alpha builds, so I'm going to see if I can learn from their sources or maybe contact them..

A second thing I learned was that there's a 4th object serialization format.. I was aware of 0, 1, and 2 (which are all different formats of serializing objects) but apparently there's also '3'. I noticed this, because I was using Charles for HTTP packages and it threw an exception on me..

Overall it seems that AMF3 is a great format for communication, but also a great overkill for the remoting aspect. The fact is that Flex heavily relies on it, which makes me want to do this, but there are definitly easier ways to encode variables, servicepaths and methodscalls. While they have done a great job in reducing the number of bytes needed to send an integer over the wire, just a simple 'Hello world' call would most likely be tripled or quadrupled in size.. I understand that we are dealing with a messaging service here, and not just a remoting protocol, but do we really need all that overhead when we're dealing with plain methodcalls?

The biggest example I have for this is AMF0 had features for connecting a call to a result (using an id) and a special field for the servicename and methodcall. AMF3 also contains all this information, but its not standing on itself, it is a protocol within AMF0. These fields and information are therefore doubled.. The 'backwards compatibility' doesnt mean much for me, because its still a new protocol to learn, and if you are new in this and want to hop straight to AMF3, you would still need to learn everything about AMF0.

Once there's a final spec for AMF3, which I will try making after SabreAMF is done (and if there isnt a good one already at that point), I will need to write about 4 levels of serialization (the byte level, AMF0 level, AMF3 level and the Messaging class structure). I feel like the classes I made for decoding this are quite efficient and not too-bad structured, but still I need a whole dosen of classes and code just for decoding AMF.. Compare that to the XMLRPC spec, which essentially does the exact same thing, but can be written in 50 lines of code give or take.

A second thing is, that the FlashPlayer first does some kind of ping call, which is a whole new http call.. and requires the entire 4 layer structure to be decoded again.. All it does is checking if the server is up and it receives an acknowledgement.

Essentially that could be encoded as:

"you up?"

and the reply

"yep"

But instead the developers of Adobe decided they need their over-designed over-complex 4-layer AMF protocol .. While my example would be 11 bytes (excluding HTTP wrappers, and all other overhead). Their method of saying the exact same thing requires around 500 bytes.. This might not seem much, but since you can express true or false in 1 byte (1 bit actually) using 250 bytes to just submit true over the wire, is a lot. I wonder why they put so much effort in packing integers in a smaller number of bytes, since basically every other aspect of the protocol grew in bloatyness..

Fair enough, its fun doing this, but it just takes a bit more time to do it..

 1

About

My name is Evert, and I've been writing semi-regularly on this blog since 2006.

I'm currently available for contract work.

more info.

Subscribe

Dropbox

Dropbox is a simple cross-platform online backup and sync application. The first 2GB of space is free, and both you and me get an extra 250MB extra space if you sign up through this link.