Home Tutorials Forums Articles Blogs Movies Library Employment Press

Go Back   ActionScript.org Forums > ActionScript Forums Group > ActionScript 2.0

Reply
 
Thread Tools Rate Thread Display Modes
Old 11-11-2003, 08:07 PM   #1
Leo Vildosola
Registered User
 
Join Date: Nov 2003
Posts: 4
Default Making Flash Remoting PSeudo-Synchronous

Flash remoting is asynchronous by nature. In order for a flash client to process results it is required to write two callback functions per service call or simply an onResult method for handling returned values and an onStatus method for error handling.

I don't want to have to create these methods all the time, so I created a base class in AS2 to support any service consumer. The class is called AbstractServiceConsumer. In this class I have onResult and onStatus methods to deal with the information being returned as a result of the remote call. I also have a property that stores the returned value for the last call onResult handled.

My goal is to create a layer over flash remoting that will allow me to simulate a synchronous call. I basically would like to make the service call, wait until the onResult is called, and access the property to get the value.

Eveything works fine until I have to wait for the onResult call. The problem I have is that I don't know how to force a wait or sleep of the current processing. I can't find any functionality that will allow me to do just that. I have looked into setInterval but I don't think it does what I need since it continues processing after the function is called.
Leo Vildosola is offline   Reply With Quote
Old 11-12-2003, 03:27 AM   #2
hangalot
lala
 
hangalot's Avatar
 
Join Date: Feb 2002
Location: on the road
Posts: 2,858
Default

what you are saying sounds pretty async 2 me, and to be honest their is no way i can imagine you can get this to function in a synchranous fashion wihout the use of a socket.
__________________
oi poloi
http://www.memorphic.com/news/
hangalot is offline   Reply With Quote
Old 11-12-2003, 08:01 AM   #3
Eric Echols
Registered User
 
Join Date: Nov 2003
Posts: 22
Default A little Clarification

I'm heavily into Flash Remoting, and I may be able to help, but I have to have more specific information.

The wait you are attempting, its purpose? If you merely don't want to populate the data, you could use a dataholder, and populate a UI component with an event.

Maybe I misunderstood, however if you reply with more information I will be more than happy to help.
Eric Echols is offline   Reply With Quote
Old 11-12-2003, 11:28 AM   #4
Leo Vildosola
Registered User
 
Join Date: Nov 2003
Posts: 4
Default

Let me go into a little more detail. Let's start by noting that there's no way to make Flash Remoting synchronous. Its nature is to be asynchronous and that cannot be changed. What I want to do is create a layer that performs the interaction with Flash Remoting and handles the results in such a manner as to encapsulate the fact that I am using Flash Remoting.

The typical way to do remoting, once you initialize a service connection, is to make the call something like this:
ActionScript Code:
// Perform the remote call, which in and by itself does not return any value. service.someRemoteMethod(); // Handle result. function someRemoteMethod_Result(result) { } // Handle error condition. function someRemoteMethod_Status(status) { }
This code is all implemented as part of a frame's action script or similar. It assumes that the handlers will have access to the presentation components such as dynamic text fields or the like. BTW, we can also use classes to handle such an interaction in which case we create two methods, onResult and onStatus, to handle the result of the call and the error thrown by the call, respectively.

I want to be able to separate my presentation logic completely and make it deal with pure AS objects, which model services, that do not, and should not, know anything about the presentation logic. Conversely, the presentation logic will not know that I decided to implement the service using Flash Remoting, or any other technique for that matter. This is simply isolation of responsibilities.

To do this you can create a AS class that encapsulates the remote calls. This serves as your facade layer and the entry point to your service. The base class contains the basics required to deal with the remote calls.
ActionScript Code:
/**  * Base for all classes that require interaction with a service on the server side.  */ class AbstractServiceConsumer {     /** Reference to the remote service instance. */     private var service:Object = null;     /** Place-holder for the results returned by the last remote call. */     private var result:Object = null;     /** Flag indicating whether or not the service is waiting for the remote response. */     private var wait:Boolean = false;     /**      * Construct using the given service name.      * @param serviceName name of the service we are to represent.      * @throws an error when it is not able to instantiate the requested service.      */     private function AbstractServiceConsumer(serviceName:String)     {         // Attempt to get the requested service.         this.service = ServiceLocator.getService(serviceName);         if (null == service)         {             throw (new Error("AbstractServiceConsumer: Unable to instantiate service \"" + serviceName + "\""));         }     }     /**      * Returns the service instance associated to this consumer.      * @return service instance.      */     public function get Service():Object     {         return this.service;     }     /**      * Returns the result of the last remote call.      * @return result of the last call.      */     public function get Result():Object     {         return this.result;     }     /**      * Stops processing until either a result or status is received or a predetermined amount of time is expired.      */     private function waitForService():Void     {         // Initialize the internal flag to wait.         this.wait = true;         // TODO: Find a way to force this call to wait here while allowing other calls to execute. The result is that the         //       calling process cannot continue.     }     /**      * Default result handler.      * @param result object representing the result of the call.      */     private function onResult(result:Object):Void     {         // Store the result for use.         this.result = result;         // Clear the wait flag to allow processing to continue;         this.wait = false;         // Output the details of the result;         trace("AbstractServiceConsumer: call returned with result = " + result);     }     /**      * Default error handler.      * @param status object representing the status of the call.      */     private function onStatus(status:Object):Void     {         // Clear the wait flag to allow processing to continue;         this.wait = false;         // Output the details of the result;         throw (new Error("AbstractServiceConsumer: call returned with status = " + status));     } }
We can then create a service. Call this service Foo.
ActionScript Code:
class Foo extends AbstractServiceConsumer {     public function Foo()     {         // Initialize the base class with the service identifier. The base class will call a helper class called ServiceLocator that will         // take care of initializing the service instance.         super("nameOfMyRemoteService");     }     public function getSomeDataOrPerformSomeOperationThatReturnsAValue():String     {         // Delegate the call to the remote service. Note that we pass "this" as the first parameter indicating to Flash Remoting that         // we want this class instance to receive the result/status generated from the call.         super.Service.remoteMethod(this);         // Wait for the service call to send back either a result or status.         super.waitForService();         // Return the result of the operation.         return super.Result;     } }
Now that I have a business delegate I can simply call it from my frame's action script without knowing that it is implemented using Flash Remoting.
ActionScript Code:
var foo:Foo = new Foo(); var resultOfTheCall:String = foo.getSomeDataOrPerformSomeOperationThatReturnsAValue();
From the eyes of my client using my service it is nice and clean and I can encapsulate any interactivity with Flash Remoting. That's why I need to find a way to freeze/sleep/wait/etc the specific AS line of code. Also, if you notice, you never have to deal with writing specific handlers for corresponding remote calls.

I tried using a while loop but because the flash player is essentially running in a single thread I freeze that thread and any results from the backend do not get processed until the while loop is exited. There's no way that I found to allow a yield. This would essentially allow other processes to complete pending events.

I hope the concept is clearer now, and hopefully not more complicated. Thanks for your interest.
Leo Vildosola is offline   Reply With Quote
Old 11-12-2003, 11:19 PM   #5
Eric Echols
Registered User
 
Join Date: Nov 2003
Posts: 22
Default I PMed you a sample

Take a look at the sample I sent, I have used this type of interface with much success.
Eric Echols is offline   Reply With Quote
Old 11-17-2003, 11:42 AM   #6
Leo Vildosola
Registered User
 
Join Date: Nov 2003
Posts: 4
Default

I have not been able to get this issue resolved and was wondering if any one else has any suggestions to the matter.
Leo Vildosola is offline   Reply With Quote
Old 08-04-2004, 09:09 PM   #7
hugobossv8
Registered User
 
Join Date: Apr 2003
Location: Southern California
Posts: 58
Send a message via AIM to hugobossv8
Default

You initially stated:

Quote:
I have looked into setInterval but I don't think it does what I need since it continues processing after the function is called.
Can't you use clearInterval in combination with setInterval to clear processing? If you don't like this idea, how about onEnterFrame and then delete onEnterFrame when the call is complete.
hugobossv8 is offline   Reply With Quote
Old 08-04-2004, 09:25 PM   #8
deadbeat
Registered User
 
Join Date: Feb 2001
Location: vancouver
Posts: 2,219
Default

I would suggest setting up your abstract class to implement EventDispatcher and then broadcasting an event once the result has been returned from the remoting service and parsed...

Your presentation layer would then simply register as listeners to the abstract class and fire callback handlers to manage the view state when the result event is broadcast...

K.
deadbeat is offline   Reply With Quote
Old 03-06-2006, 12:41 AM   #9
mscheliga
Mario Scheliga
 
Join Date: Mar 2006
Posts: 1
Smile found out a solution, that works for me

hi every one,
this is a very tricky task, but i found out a solution that works for me, to encapsulate the modell and the presentation tier. Because i am not able to let stop/halt/wait/etc. tha actionscript because of the single thread. I decided to do it otherwise. I coded a thread that synchronizes my modell. I wrote a abstract class for it:

Code:
import mx.rpc.ResultEvent;
class de.dimx.icestorm.defamemorial.services.AbstractService
{
	private var synchronized:Boolean = false;
	private var valueObject:Object;
	
	private var synchronizerIntervalID:Number;
	private var dirtymakerIntervalID:Number;
	
	private var syncInterval:Number;
	private var dirtymakerInterval:Number;
	
	public function AbstractService()
	{
		syncInterval = 1000;//0;		//every 10sek it will be checked
		dirtymakerInterval = 6000;//0;	//every minute it has too be updated.... -> hardly realtime you get with a socket call for modellChanged?
		//this could be implemented by timestamp for the entities in the database, the amfphp service could compare both and return a dirty or not
		//just to reduce loading overhead......
	}
	
	public function toggleAutosync()
	{
		trace ("toggleAutosync");
		if (this.synchronizerIntervalID == null)
		{
			//switch on the intervall
			this.synchronizerIntervalID = setInterval(this.doSynchronize,this.syncInterval,this);
			this.dirtymakerIntervalID = setInterval(this.makeDirty,this.dirtymakerInterval,this);
		}
		else
		{
			//kill the intervall
			clearInterval(this.synchronizerIntervalID);
			clearInterval(this.dirtymakerIntervalID);
			this.synchronizerIntervalID = null;
		}
	}
	
	public function isSynchronized()
	{
		return this.synchronized;
	}
	
	public function doSynchronize(callObj:Object)
	{
		 
		if (callObj.synchronized == false)
		{
			trace ("synchronizing....");
			//synchronize that valueObject with load or something;
			//note store and update also have to set the ValueObject; 
			
			//for objects that have a tbl_key named "id"
			if (callObj.valueObject != null && callObj.valueObject.id != null)
			{
				trace ("loading new one");
				callObj.load(callObj.valueObject.id);
			}
		}
	}
	
	public function makeDirty(callObj:Object)
	{
	 
		//mark as dirty so synchronize go on.
		//if a setter is called or the objekt is
		//modified, then dirty is also called
		callObj.synchronized = false;
	}
	
	public function load(oid)
	{
		 
		this.synchronized = false;
	}
	
	public function onLoad(re:ResultEvent)
	{ 
		this.valueObject = re.result; 
		trace ("loaded:"+this.valueObject.name);
		this.synchronized = true;
	}
	
	public function store()
	{
		this.synchronized = false;
	}
	public function onStore(re)
	{
		this.valueObject = re.result;
		this.synchronized  = true;
	} 
}
And on the constructor for the implementation is this:
Code:
	public function MemorialService()
	{
		super();
		NetDebug.initialize();
		this.service = new Service(this.gatewayUrl, null, "MemorialService", null, null);
		this.toggleAutosync();
	}
the load function:

Code:
public function load(oid)
	{
		super();
		trace ("load");
		var pc:PendingCall = service.load(oid);
		pc.responder = new RelayResponder(super, "onLoad", "handleRemotingError");
	}
It can be enhanced by establishing a xmlsocket connnection to the server and get noticed of a "modellChanged" event, then the make dirty function is called and the synchronization is done. Here you can use the xmlSendAndLoad function. I will write the next couple of days a quite better version of this workaround.

It is ment to load the modell, and then synchronize the changes.

greetz

Mario

Last edited by mscheliga; 03-06-2006 at 12:49 AM.
mscheliga is offline   Reply With Quote
Reply


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump


All times are GMT. The time now is 02:43 PM.

///
Follow actionscriptorg on Twitter

 


Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Ad Management plugin by RedTyger
Copyright 2000-2013 ActionScript.org. All Rights Reserved.
Your use of this site is subject to our Privacy Policy and Terms of Use.