When a service is called, there are two type of responses you can get: either a result with the contents of what the service returned, or a fault when there was an error when contacting the server or an error was thrown by the server. It's important to note that these possible responses are received asynchronously, so that after the request to the server was made, it is not possible to know when the response will be received.
When you use the service tags (RemoteObjectInvoker, WebServiceInvoker, HTTPServiceInvoker) inside an EventHandlers block or MessageHandlers block and the event is dispatched or message is received, the server request is made and the execution of the handlers continues. Any other handler placed after the service will execute right after the server request is made. But what if you want to wait until the server responds to the request? Inside all of the service invoker tags, you can place another list of handlers that will execute when thes erver replies, or throws an error.
<WebServiceInvoker instance="{myServiceInstance}" ...> <resultHandlers> ... this list executes when server returns results ... </resultHandlers> </WebServiceInvoker>
In the same way, you can place another list of handlers that will execute when the request ends up in an error.
<WebServiceInvoker instance="{myServiceInstance}" ...> <faultHandlers> ... this list executes when server returns a fault ... </faultHandlers> </WebServiceInvoker>
Of course you can have both sequences inside one service tag:
<WebServiceInvoker instance="{myServiceInstance}" ...> <resultHandlers> ... this list executes when server returns results ... </resultHandlers> <faultHandlers> ... this list executes when server returns a fault ... </faultHandlers> </WebServiceInvoker>
Inside the resultHandlers or faultHandlers tags, you can place any other tag you would normally place in your <EventHandlers> block. They are handler lists that run asynchronously when the server response is received. Inside the resultHandlers, you have a special value your handlers that are inside the result or fault handlers block can use: the"resultObject" that contains what was sent by the server as a response to the call made. Inside the faultHandlers, they can access the"fault" that contains the server error. Those two values can be used as arguments for MethodInvokers, EventAnnouncers, other services, etc.
Those two sub-handlers are only run after the server response is received, so you can be sure that you will have the values needed to continue execution. In this way, you can even create a chain of service calls, such that one is called only when the response from the previous service call has been received.
For example, suppose you have an event of type"myEventType". When that event is dispatched, you would like to make a service call and also call a method on an object to execute some business logic. When the response of that server call, you want to create an event, perhaps to notify views that the data has been received and also call a method passing the result so that is can save it in the model.
To do that, you would write your sequence as follows:
<EventHandlers type="myEventType"> <WebServiceInvoker instance="{myServiceInstance}" ...> <resultHandlers> <EventAnnouncer type="myEventTypeTwo" generator="EventClassNameToInstantiate" /> <MethodInvoker generator="WorkerTwo" method="receiveResults" arguments="{resultObject}" /> </resultHandlers> </WebServiceInvoker> <MethodInvoker generator="WorkerOne" method="doSomething /> </EventHandlers>
In this scenario, the following will happen:
- The service call will be made
- The WorkerOne function doSomething will be called
- After some time, say 5 seconds, the server returns the results
- A new event of type "myEventTypeTwo" will be dispatched by the EventBuilder
- The WorkerTwo function receiveResults will be called with one argument containing the results of the server call.
See Using Smart Objects for more information on the resultObject and fault.
Application-wide service fault handling
If you omit the faultHandlers, normally, a runtime exception will be thrown, unless you are handling that fault within the <mx:RemoteObject>, <mx:WebService>, or <mx:HTTPService> tags.
If there are no faultHandlers, then Mate will dispatch an event of type "UnhandledFaultEvent.FAULT" that you can use to handle any fault that was thrown by a service. You can have EventHandlers tags to handle that fault:
<EventMap ...>
<mx:Script>
<![CDATA[
import com.asfusion.mate.events.UnhandledFaultEvent;
]]>
</mx:Script>
<EventHandlers type="{UnhandledFaultEvent.FAULT}">
<!-- here you specify what to do when a fault was not handled -->
<MethodInvoker generator="{GenericFaultHandler}" method="handleFault" arguments="{event.fault}" />
</EventHandlers>
</EventMap>
In that example, you will have to create a class that handles that fault in some way (GenericFaultHandler). That is only an example, as you can have any tags you would normally have in the EventHandlers tag.
That event has a property fault that contains the original fault that was generated by the service call.
2. Im using Mates HTTPServiceInvoker to invoke a restful service which sends back data in XML form (if the req is processed correctly)
3. On the server side if there is a prob (example stale data being updated) I throw an error which was used to generate an error XML and set the HTTP status code to error.
4. Step 3 causes Mate to call the faultHandlers within my Event Handler which triggered Step 2 i.e http request
5. However in the fault event there is neither headers nor body of the fault generated on the server side. this is an IE problem of not passing these to the Flex VM - not a Mate issue (see article http://onrails.org/articles/2008/02/20/dealing-with-http-errors-in-a-flex-with-rails-application)
6. So now to get the error headers and body Im changing the http status to 200 (ok) and sending back the error xml. however now Mate will not trigger the faultHandlers
7. So in my resultHandlers I have a StopHandler which detects if the xml sent by the server is an ErrorMsg and stops the resultHandlers regular sequence
8. Now I want to trigger the faultHandler upon detection of an Error - how do I do this ?
In effect Id like to trigger my faultHandler from my resultHandler on certain conditions - how can I achieve this ?
Hope my long winded question is clear :)
When I throw an exception on the server side in Rails - I get
<mx:HTTPService id="teamSearchService" url="/teams/teamList/-1.xml" />
<EventHandlers type="{TeamEvent.TEAM_SEARCH}" debug="{debug}">
<MethodInvoker generator="{MainScreen}" method="setBusyCursor" arguments="{MainScreen.TEAM_TAB}" />
<HTTPServiceInvoker
instance="{teamSearchService}"
contentType="application/xml"
request="{event.data}"
method="POST"
resultFormat="e4x"
debug="{debug}">
<resultHandlers>
<StopHandlers stopFunction="myStopHandlerFunction" />
<MethodInvoker generator="{TeamModel}"
method="setTeams" arguments="{resultObject}"/>
<ServiceResponseAnnouncer type="result" />
<MethodInvoker generator="{MainScreen}" method="removeBusyCursor" arguments="{MainScreen.TEAM_TAB}" />
</resultHandlers>
<!-- server fault -->
<faultHandlers>
<MethodInvoker generator="{MsgDisplay}"
method="show" arguments="{[fault,resultObject]}"/>
<ServiceResponseAnnouncer type="fault"/>
<MethodInvoker generator="{MainScreen}" method="removeBusyCursor" arguments="{MainScreen.TEAM_TAB}" />
</faultHandlers>
</HTTPServiceInvoker>
</EventHandlers>
And my stopHandler function is
private function myStopHandlerFunction(scope:ServiceScope):Boolean {
var msg:XML = scope.result as XML;
var tag:String = msg.error_msg;
if( tag.length > 0 ) {
return true;
}
return false;
}
Please ask your question in the forums.
Thanks!
I am currently developing a flex Ent. aplication.
There is a situation where, when an item in a pre-populated list is clicked an event is triggered, remote service is invoked followed by a call back method in result handler tag.
While testing say 3 items are clicked so fast. three events are triggered , their callback will be called. when the remote object gets the result. but if the second click event 's remote object returns the result at last.Then even thought third item click event 's call back should be the last one to be executed as per requirement, due to asyn the second item click event 's call back will be called.
How to solve this?
Option - 1
<EventHandlers type="{UnhandledFaultEvent.FAULT}">
<MethodInvoker generator="{ExceptionHandler}"
method="handleFault"
arguments="{event.fault}"/>
</EventHandlers>
Option - 2
<faultHandlers>
<MethodInvoker generator="{ExceptionHandler}"
method="handleFault" arguments="{event.fault}"/>
</faultHandlers>
Option - 3
<faultHandlers>
<MethodInvoker generator="{ExceptionHandler}"
method="handleFault" arguments="{event}"/>
</faultHandlers>
Option - 4
<faultHandlers>
<MethodInvoker generator="{ExceptionHandler}"
method="handleFault" arguments="{fault}"/>
</faultHandlers>
Option - 5
<faultHandlers>
<MethodInvoker generator="{ExceptionHandler}"
method="handleFault" arguments="{resultObject}"/>
</faultHandlers>