One of the great features of our opensource as3 package is that it contains a flash remoting package (nl.dpdk.services.remoting), for sending data via the amf protocol, that is fully integrated with our collections package to also be able to use a ResultSet. It is robust, fully unittested, has the power of sorting and selecting via the underlying lists from our collections package and has some very very very convenient features that really make it shine when using remoting as a means of communicating with a remote service.
update 2008-10-21: we added a timeout detection mechanism.
One of the other opensource remoting packages is a lightweight as3 package from Danny Patterson that is hosted on osflash. While it was one of the first ones out there and has some great stuff, it does not have some features we wanted to use. One of those was the ability to use resultsets (a translation in flash from a database recordset) and the other one was to use one instance of his serviceproxy to handle different calls to a service (service.callA(), service.callB()), as this would require setting up multiple instances of his serviceproxy.
We chose for an implementation that would let us register callbacks for the possible result and status messages that come back for each specific call to a method on a service. We also make use of fully functional RecordSets in our collections package.
Since the remoting calls are made through a proxy that functions as a remote proxy, we are able to dynamically implement the interface of the matching remote service (of course, dynamically also means we do not have an interface to program to).
Let me show you how it works:
var service: RemotingProxy = new RemotingProxy('http://www.example.com/afmphp/gateway.php', 'com.example.users.User'); service.addHandler('getUsers', onUsersResult, onUsersStatus); service. addHandler('update', onUserUpdateResult, onUserUpdateStatus); //somewhere else in our code we want to get all users from the service. service.getUsers(); //or do an update call on a specific user with an object that is translated from our domain object to a form ready to be consumed by the service service.update(UserFactory.createRemote(myUser)); public function onUsersResult(result: ResultData):void{ //the service tells us it will give back a resultset, but let's check that if(result.isResultSet()){ //yes, now process it trace(result.getData().toString(); } } public function onUsersStatus(status: StatusData):void{ //status data holds some information about why where and how something did not work trace(status.getDescription()); }
and that’s it!
Of course we can register to specific events related to the underlying NetConnection to get fine grained control over possible problems, we can add and remove callbacks to the service, have the same remote method invocation routed to different callbacks, use different syntax to invoke a remote method, iterate over the ResultSet and some other powerful stuff, but this is basically what needs to be done to succesfully implement your remote service with flash remoting.
Now let’s handle the ResultSet. It is basically a table format of data, that represents the result of a statement executed on a database engine that returns a recordset.
It is sent from the framework implemented on the backend that handles the amf protocol ( in our case amfphp at www.amfphp.orgor weborb at www.themidnightcoders.com) which translates it in the amf format to be consumed by flash.
One of the misconceptions that exists about resultsets and amf is that there is no serialization done by the flash player. This is not true. While it is true that the data is natively serialized from the amf format to a format that flash understands, this is only so for the builtin types: primitives and arrays and objects. ResultSet is not a native flash type and therefore it has to be generated. This was already the case when remoting first started out in flash 6.
But luckily (and by design), resultsets very easily translate in a representation of a multidimensional structure in the form of a multidimensional array or list and can be generalized to be a reusable datastructure. We lose type safety on the data itself, but that is one of the things that cannot be avoided in ResultSets. Martin Fowler has something to say about ResultSets in his excellent book patterns of enterprise application architecture.
Now, you might wonder after reading the above, why you should ever use ResultSets :)? Because they make life very easy when working with databases!
in php, you can just say (oversimplification):
return mysql_query('SELECT user_id, user_name FROM users');
and after translation to a ResultSet in flash (which happens automatically by the package) you can just use:
public function onUsersResult(result: ResultData):void{ var records: ResultSet = result.getData() as ResultSet; var iterator: IIterator = records.iterator(); var row: ResultRow; while (iterator.hasNext()){ row = iterator.next() as ResultRow; trace('the user with id ' + row.user_id + ' has name: ' + row.user_name); } }
In our case, we would create a domain object of the User type (nl.dpdk.users.User) and store that in a seperate list datastructure (nl.dpdk.collections.lists) to be used throughout the application.
As you can see, working with remote data is very easy when handled by a specific framework. It’s fast, fun, easy and saves you loads of work. Both the remoting and collection api are very easy to learn and intuitive to work with.
Play and have fun!
update 2008-10-06: We also found another remoting implementation in as3 which is also cool, but lacking resultsets, on bytearray.org
update 2008-10-21: We have added a timeout detection mechanism:
var proxy: RemotingProxy = new RemotingProxy(gateway, service); //register a listener proxy.addEventListener(RemotingEvent.ERROR_TIMEOUT, onTimeOut); //set a handler for the method we want to call proxy.addHandler('testTimeOut', onTimeOutResult, onTimeOutStatus); //set a timeout period, if this timeout period in milliseconds is exceeded, our event listener is called. //if either a result or a fault comes back after the timeout has been triggered, we will not be notified. proxy.setTimeOut(5000); //call the method and see what happens :) proxy.testTimeOut();
And it’s all been unittested of course (asynchronously)
Very handy, thanks for sharing these great classes.
I saw the different error handling (IO error, ASync etc) I was wondering what happens when the service is there but doesn’t react at a certain time. Do you have a timeout error ?
Niels
Hi Niels, no, at present there is no timeout error. but this is a great feature, and easy to implement, as each call made via the RemotingProxy has a seperate subclass of flash.net.Responder object that will be able to detect it.. I will take a look at it this week.
Hey thanks for very good and handy guidance i am basically a Flex developer just started to explore my career from last year. it helped me great ()please don’t mind if i post some query here.
Thanks Again
An update on the RemotingProxy features a way to detect timeouts
you can set the timeout period in milliseconds after which you flag a call as ‘failed’. The default is to not detect timeouts.
You can register to an event that fires a handler when the timeout is reached.
Does this work with ColdFusion? If so, can you show an example.
Thanks
I’ve come across this since I upgraded to CS4. Using internal classes with CS4 flash IDE will cause Interface errors.
For example LinkedList.as Line 90 gives a 1044 error. Interface method … in namespace … Not implemented by class …
Only work around has been to make internal classes external, that I know about anyway. Let me know if you’ve found another solution.
We thought this was due to the fact that multiple inheritance is used in the IList interface.
We refactored this a couple of weeks ago, to use an abstract List class, that implements the different interfaces that IList used to extend. This seems to have fixed the problem, all tests passed.
But now it seems that the asunit packages gives some errors when overriding it’s setup and teardown methods in our unittests, therefore, we run the testsuite under cs3
While it seems strange to us that it compiles in the cs3 suite and not in the cs4 suite, we haven’t really looked indepth in the issue, so if you have any more issues, please let us know.
For the moment, we run the testsuite in cs3, and we are looking to fix the issue. Some simple tests suggest that your provided probable cause of error is indeed what is causing the troubles.
Any reason why this has been done by Adobe, or is this a compiler bug?
Will put the new files in the svn repository this week.