Updates to the AS3 DataManager

A customer of mine found a bug my AS3 DataManager when making multiple simultaneous calls.  Here is the fix to the bug.

The issue is that while the DataManager allows calls to many methods in a web service, each instance of the DataManager only has a single eventName property.  I was able to work around this by making use of hte AsyncToken, which is returned whenever a call to an AbstractOperation (such as a WebService) is made.  The AsyncToken is carried along with the request and available when results happen as part of the ResultEvent.  Even better, its a dynamic class, so you can add any arbitrary properties on it you want.  So, to fix the issue, replace the existing makeRemoteCall method with this:

public function makeRemoteCall(methodName:String,eventName:String, args:Object):void{
 trace("DataManager.makeRemoteCall("+methodName+","+eventName+","+args+")");
 this.eventName = eventName;
 var op:mx.rpc.AbstractOperation = ws[methodName];
 ws.addEventListener("result",doResults);
 ws.addEventListener("fault",doFault);
 
 if(args){
  op.arguments = args;
 }
 
 var token:AsyncToken = op.send();
 token.eventName = eventName;
}
private function doResults(event:ResultEvent):void{
 var e:DataManagerResultEvent = new DataManagerResultEvent( event.token.eventName, event.result);
 this.dispatchEvent(e);
}

Now, the event names is stored with the request, so we have access to a different event name for each request made!  The completed code looks like this:


package managers {
  import flash.events.EventDispatcher;
  import mx.rpc.soap.WebService;
  import mx.rpc.events.ResultEvent;
  import mx.rpc.events.FaultEvent;
  import mx.rpc.AbstractOperation;
  import events.DataManagerResultEvent;
  import flash.util.*
  import mx.rpc.AsyncToken;;
  /**  DataManager - singleton class which enforces only
  a single object is created for eachwsdl.  To
  access DataManager, use getDataManager(wsdl:String) */
  public class DataManager extends EventDispatcher {
  private var ws:WebService;
  private var eventName:String;
  // hashmap of instances for each wsdl 
  private static var instanceMap:Object = new Object();
  private static var methodEventMap:Object = new Object();
  public function DataManager(pri:PrivateClass, wsdl:String){
   this.ws = new WebService();
   ws.wsdl = wsdl;
   ws.loadWSDL();
   ws.useProxy = false;
  }
  public static function getDataManager(wsdl:String):DataManager{
   if(DataManager.instanceMap[wsdl] == null){
    DataManager.instanceMap[wsdl] = new DataManager(new PrivateClass(),wsdl);
   }
   
   var dm:DataManager= DataManager.instanceMap[wsdl];
   
   if(dm.ws.canLoadWSDL()){
    return dm;
   } else {
    throw new Error("BAD WSDL:"+wsdl);
   }
  }
  
  public function makeRemoteCall(methodName:String,eventName:String, args:Object):void{
   trace("DataManager.makeRemoteCall("+methodName+","+eventName+","+args+")");
   this.eventName = eventName;
   var op:mx.rpc.AbstractOperation = ws[methodName];
   ws.addEventListener("result",doResults);
   ws.addEventListener("fault",doFault);
   
   if(args){
    op.arguments = args;
   }
   
   var token:AsyncToken = op.send();
   token.eventName = eventName;
  }
  
  private function doResults(event:ResultEvent):void{
   var e:DataManagerResultEvent = new DataManagerResultEvent( event.token.eventName, event.result);
   this.dispatchEvent(e);
  }
  
  private function doFault(fault:FaultEvent):void{
   trace("DataManager.doFault("+fault.fault.faultString+")");
   this.dispatchEvent(fault);
  }
  
  public override function toString():String{
   return "DataManager";
  }
 }
}
 /**  PrivateClass is used to make   DataManager constructor private */
class PrivateClass{
 public function PrivateClass() {
 }
}
 

Comments
A visitor's Gravatar What if I have a Web Service that not only has complex types but a choice? So basically I don't have simple parameters to pass. I need to specify or pass in a whole custom build XML structure to be passed as the request. Is this possible with AS3?


Thanks for the time and response. I am having trouble finding an answer to this else where.

# Posted By A visitor | 12/20/06 12:04 AM
A visitor's Gravatar I'm still having a problem, even after updating my code. I am creating the WebService twice within the same application, and it is failing to return the result. If I take out either of the WebService calls, it works. Any suggestions?


My code (this DOES NOT work for me):


// Start retrieving the lists of data needed to build the form options/inputs
private function init():void
{
   var wsReports:webservices.wsCreate;
   wsReports = wsCreate.getWebService("/private/cfc/get_reports.cfc?wsdl");
   // Create an event listener for the result from the WebService


  • wsReports.addEventListener("reportsResult", reportsResult);



   // Create an event listener for any faults from the WebService

  • wsReports.addEventListener(FaultEvent.FAULT, faultEvent);


  • // Call the WebService



   wsReports.makeRemoteCall("get_reports", "reportsResult");
}


// Handle the object returned from the Reports WebService
private function reportsResult(evt:wsResultEvent):void
{
   // Create an XML object to store the results of the WebService call
    var reportsXML:XML = new XML(evt.result as Object);


   reportSel.dataProvider = reportsXML.report;


   var wsReportFilters:webservices.wsCreate;
   wsReportFilters = wsCreate.getWebService("/private/cfc/get_report_filters.cfc?wsdl");
   // Create an event listener for the result from the WebService


  • wsReportFilters.addEventListener("reportFiltersResult", reportFiltersResult);



   // Create an event listener for any faults from the WebService

  • wsReportFilters.addEventListener(FaultEvent.FAULT, faultEvent);



   // Call the WebService
   wsReportFilters.makeRemoteCall("get_report_filters", "reportFiltersResult");
}
# Posted By A visitor | 10/3/07 12:03 AM
eric belair's Gravatar Nevermind, I found my problem - I still had the parameter typed to be a "ResultEvent" in my event handler function, instead of a "wsResultEvent". I have this working now like a charm! Thanks again for this great app.
# Posted By eric belair | 10/4/07 12:02 AM
sanjaya's Gravatar I did all the things what you have shown in post. It is working fine. But my only problem is, the result of DataManagerResultEvent is returned as ObjectProxy not as a XMLLIST. But it was returning XMLLIST before changed the code. I have used resultFormat="e4x". Please help me to solve this problem. This is realy important thing.


Thank You
Sanjaya

# Posted By sanjaya | 11/5/07 12:01 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.001.