Categories Displayed in Flash

AS3 and Serialization, Memento Pattern

Starting to work on porting the persistence aspect of Prevayler to Flash/AS3. It's a perfect fit with Flash, as Prevaylence assumes that everthing can fit into RAM (which flash does, aside from loading new things in), and changes have to be synchronized, which seeing as it's a primarily a single thread doesn't have to worry about synchronizing multiple writes.
Prevaylence relies heavily on understanding the serialization of objects, both the commands and the business object state should be save and restoreable. Since ByteArray supports AMF packets (as does shared object) this means that private vars and Class definitions, functions should be able to be written to disk and brought back from dead...but this leaves the larger question, just like the dinosaurs ...should they be brought back?
It's certainly tempting.  Java has faced this for years in it's serialization routines. In general built in serializing is good, but doing it across version is bad, as it's inevitable that the Class definition will change, adding, removing variables and methods ...even changing types, during refactoring. When reconstituting things may not serialize properly much as you don't fit into your GI Joe pajamas from kindergarden (well hopefully). It's unpredictable what the Flash player will do when forced to put version 1.2 into 1.3 shoes, or potentially version 1.4 into 1.2.  So it's important to know exactly what is being saved and how flexible it is.

Since I was working on Trace.me this week, and private, protected, etc variables didn't show up in the output, (which is proper Object encapsulation), I was curious as to if the variables were invisible or lost. I remembered  hitting similar things when working with and on openAMF, so I dug a bit, and just found a document I wrote a few years ago, on openAMF, ah good times...

http://openamf.cvs.sourceforge.net/*checkout*/openamf/openamf/docs/understanding.htm?revision=1.1

There the issue there was different, was actually whether java's accessors e.g. get someValue and set someValue translated across the wire. The serialization in Java openAMF calls the accessors and puts them into a hashmap, before sending across the wire. Flash does something similar when sending back to the server, skipping the accessors as back then it didn't really know what those were. But I wasn't sure if this was the case when targetting ByteArray and Shared Local Object for output.

I have an dummy object called IntrospectableObject, it has all manner of public, private, protected etc vars of all different types (well at least enough to test), I've been using to test. I've added a few accessors and a toString method which outputs everything.

The code to test ByteArray as a serialization is simple

import flash.net.SharedObject;
import com.troyworks.prevayler.*;
import flash.utils.ByteArray;
import flash.net.registerClassAlias;
import flash.utils.describeType;

////////////// BYTE ARRAY TESTS ////////////////

var bA:ByteArray = new ByteArray();
//registerClassAlias("com.troyworks.prevayler.IntrospectableObj", IntrospectableObj);
var iObj:IntrospectableObj = new IntrospectableObj();

bA.writeObject(iObj);
bA.position = 0;
var aObj:Object = bA.readObject();
trace("aObj " + aObj.toString());

trace("XML " + describeType(iObj).toXMLString());
trace("attempting to introspect ");
for (var i:String in aObj){
trace( i + " " + aObj[i]);
}

It outputs:

new Introspectable //consturctor of source
aObj [object Object]
attempting to introspect
pubStrVar public testString
pubBooTrueVar true
pubVar undefined
pubUIntVar 1
pubIntVar -1
pubNumVar 0.5
pubBooFalseVar false
pubDateVar Wed Aug 29 02:40:48 GMT-0700 2007

which reveals no accessors are called, and nothing but public vars are called, which is to be expected. Uncommenting:

registerClassAlias("com.troyworks.prevayler.IntrospectableObj", IntrospectableObj);

We get something completely different. As it's creating a new class upon reconstitution, and then calling it's toString() which has access to the private/internal so can see more. This means that ByteArray does get the whole picture even if it doesn't share all of it.

new Introspectable //constructor of source
new Introspectable  //constructor of reconstructed
aObj pubStrVar public testString
pubNumVar 0.5
pubIntVar -1
pubUIntVar 1
pubBooFalseVar false
pubBooTrueVar true
pubDateVar Wed Aug 29 03:00:12 GMT-0700 2007
priStrVar priTestString
priNumVar 0.2
priIntVar 2
priUIntVar 2
priBooFalseVar false
priBooTrueVar true
pritDateVar Wed Aug 29 03:00:12 GMT-0700 2007
attempting to introspect
--none--- //can't see anything as it's now class based.

What interesting is simliar to AMF, the constructor is called by Flash/AS3, but the values of the items as serialzed overwrite, bypassing the encapsulation layer (and thus any events). This is good if sometimes tricky to remember. It's resetting the snapshot of the object's state. Which compared to broadcasting a dozen+ change events makes sense, as it really hasn't changed, it's just been restored. This is basically what we want but as prior this may hit the shoes don't fit problem, break on newer swfs with different code coming out.

What this indicates to me is that serialization for Prevayler like approaches, should be done via the memento pattern, and only the mementos should be serialized. Wikipedia has a good article on it.
http://en.wikipedia.org/wiki/Memento_pattern  which interestingly links to a large page on finite state machines. which uses the memento pattern to save state/shallow history, with extended variables.
http://en.wikipedia.org/wiki/Finite_state_machine

Both the business logic and the commands should implement the pattern.  Mementos immutable read-only ideally, with all values passed into the constructor and only accessible via getters. But if the number of attributes are large, I could see a Object/struct with purely public variables may be better for useability and performance, as Mementos shouldn't do anything. In addition, Mementos should have a version number of the 'file format', and preferrably some mechanism can faciliate putting the data in via calling getters on the originator object, if they aren't marked as non-serializable (e.g. calculated results like totals shouldn't be serialized). Which I often like to put into a separate class, as the serialization/deserialization may be for different formats, XML, and they aren't really 'business object' concerns. One could even use the namespace feature to manage which one is being used.
This is exciting to me as Shared Local Object is cheap and fast and shared..a great place for multiple flash movies potentially in different web pages, maintaining a common log. Inside AIR's using it's DB, is another good place to store offline/online commands that get synched back up..potentially against other users making changes at one, when connected again.
This would take Flash RIA's closer to conventional applications, even if they are microcontent. It's always annoyed me how long running flash games how some don't remember where you are, using cheat codes so you can jump to a particular level, and that undo is so problematic, so it's either being petrified to explore for fear of making a mistake or having to do the same thing over and over again. There are many games I'd play longer if these capabilities existed. Flash makes these features easy,  it's just that most applications aren't written to support.
Since ByteArray can be compressed and written to Strings, this means they can be files, and thus to disk somewhere, be it SaveAs in AIR,  POST, XML. Sockets, meaning that a saving a application and then logging into another machine and getting everything back would be easy, or potentially opening and saving multiple versions so people can try things or create things easily.

Add a Comment: