Well, after much deliberation, the solution was to stick with an external list manager to control Server Queries. Adding the list management to the ServerQuery class module proved to be more trouble than it was worth since each query would need to track its own status and timing. This could be better served with an external management class.
All that was needed to support an external manager was a simple callback function to allow the manager to know when queries finished execution.
Here is the pre-test code for the ServerQuery and ServerQueryList classes:
import flash.events.*;
import flash.net.*;
//
// a static helper class to queue queries to the server, all in one place... reports average server response time as a bonus!
//
public class ServerQueryList {
static var serverQs : Array = new Array(); // array of ServerQuery objects
static var _networkLatency : int = 0; // the average response time from the server
function ServerQueryList() {
}
// request data from the server... takes URLstring and callback function as paramaters
static function QueryServer(req:String, callback:Function, bMeasureLatency:Boolean=false) {
// create a new ServerQuery object
var sq : ServerQuery = new ServerQuery(req, callback);
// set the callback to our private function
sq.setListCallback(sqCallback);
// push it onto our list
newindex = serverQs.push(sq);
// pass along the index... push actually adds to end of array not to beginning ala a stack... confusing function name there
sq.setIndex(newindex);
sq.Load(); // do it!
}
private function sqCallBack(target:ServerQuery) {
// our target has returned...
// record the round trip time and then delete it from the array
var sqIndex = target.getIndex();
if (sqIndex != -1 && sqIndex < serverQs.length) { // validate index
accumulateLatency(ServerQuery(serverQs[sqIndex]).getResponseTime());
//do the cleanup!
ServerQuery(serverQs[sqIndex]).kill();
delete serverQs[sqIndex];
serverQs[sqIndex] = null;
serverQs.splice(sqIndex, 1);
}
}
private function accumulateLatency(newResponseTime:int) {
// add the response time to our aggregate response time
if (_networkLatency != 0)
_networkLatency = (_networkLatency + newResponseTime) / 2;
else
_networkLatency = newResponseTime;
}
} // end ServerQueryList
import flash.events.*;
import flash.net.*;
//
// actually gunna leave this one as a generic query class.. will make a queue class to manage these
// a helper class to queue queries to the server, all in one place... reports average server response time as a bonus!
//
public class ServerQuery {
private var _urlloader : URLLoader;
private var _callback : Function; // supplied by caller
private var _urlrequest : URLRequest;
private var _listCallback : Function; // supplied by query list manager
private var _responseTime : int; // milliseconds for round trip
private var _opened : Number; // time when connection opened
private var _closed : Number; // time when response has arrived
//TODO: add timer for timeout failure
private var _debugStr : String;
private var _index : int; // the index of this query within the external list of queries
public function ServerQuery(req:String, callback:Function) {
_debugStr = "";
_urlloader = new URLLoader();
configureListeners(_urlloader);
_urlrequest = new URLRequest(req);
_callback = callback;
_urlloader.addEventListener(Event.COMPLETE, CTQueryPreCallback);
_responseTime = -1;
_index = -1;
_listCallback = null;
}
public function setListCallback(newFunc:Function) {
_listCallback = newFunc;
}
public function setIndex(newIndex:int) {
_index = newIndex;
}
public function getIndex() : int {
return _index;
}
public function getResponseTime() : int {
return _responseTime;
}
public function Load() {
try {
var date : Date = new Date();
_opened = date.getTime();
_urlloader.load(_urlrequest);
} catch (error:Error) {
_debugStr += "ServerQuery: Unable to load requested document";
}
}
public function getDebugReport() : String {
return _debugStr;
}
public function kill() {
// do some cleanup
delete _urlloader;
delete _urlrequest;
}
private function CTQueryPreCallback(e:Event) {
deconfigureListeners(_urlloader);
var date : Date = new Date();
_closed = date.getTime();
_responseTime = _closed - _opened;
// inform the list manager, if any, we have returned.. pass it our this pointer
if (_listCallback != null)
_listCallback(this);
if (_callback != null)
_callback(e); // call our stored callback
}
private function configureListeners(dispatcher:IEventDispatcher):void {
//dispatcher.addEventListener(Event.COMPLETE, completeHandler);
//dispatcher.addEventListener(Event.OPEN, openHandler);
//dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
}
private function deconfigureListeners(dispatcher:IEventDispatcher) {
dispatcher.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
dispatcher.removeEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
dispatcher.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
}
private function securityErrorHandler(event:SecurityErrorEvent):void {
trace("ServerQuery: securityErrorHandler: " + event);
_debugStr += "securityErrorHandler: " + event + "\n";
}
private function httpStatusHandler(event:HTTPStatusEvent):void {
trace("ServerQuery: httpStatusHandler: " + event);
_debugStr += "httpStatusHandler: " + event + "\n";
}
private function ioErrorHandler(event:IOErrorEvent):void {
trace("ServerQuery: ioErrorHandler: " + event);
_debugStr += "ioErrorHandler: " + event + "\n";
}
} // end class
OMG WHY AM I TREADING DOWN THIS ROAD!
ReplyDeleteI am still stuck here...
http://devcenter.heroku.com/articles/facebook#what_is_heroku