Occurrence of ResultEvent event in remoting a spring Object - apache-flex

In my attempt to learn flex remoting I came across this
flexService.getRules.addEventListener(ResultEvent.RESULT, loadRules);
here flexService is a remote java object .. In above function call can any one help me that when ResultEvent.RESULT will occur. On studying about ResultEvent in AS document it states as
The event that indicates an RPC operation has successfully returned a result
So keeping that in mind my guess is ResultEvent will be fired when flexService.getRules method will successfully return a list of object,where flexService is object of remote class FlexService having getRules function which returns list of object, Can any one please tell how exactly it works..
Also can some one plz tell me how eventListener can be added to a list of object
PS: I am using Spring as backend

Here you set result to arraycollection
private function loadRules(event:ResultEvent):void
{
var list:ArrayCollection = new ArrayCollection();
list = event.result as ArrayCollection;
}

I'll be going on assumptions since you apparently aren't keen on showing more code or giving pertinent information.
I'm assuming that 'flexService' is a RemoteObject that has set all required properties (destination, endpoint, etc)
I'm assuming that 'getRules' is an available function on your java remote class which returns the information needed.
I'm assuming that everything is being sent over using AMF.
in that case, it's as simple as doing this:
var token:ASyncToken = flexService.getRules(arg1, arg2);
token.addResponder(new Responder(yourResultFunction, yourFaultFunction));
private function yourResultFunction(data:Object):void
{
// Do something with data here
}
private function yourFaultFunction(fault:Object):void
{
// do something if a fault happens
}
Of course, this is very basic and you should try to implement a better pattern (commands) around it.

Related

Solution for asynchronous notification upon future completion in GridGain needed

We are evaluating Grid Gain 6.5.5 at the moment as a potential solution for distribution of compute jobs over a grid.
The problem we are facing at the moment is a lack of a suitable asynchronous notification mechanism that will notify the sender asynchronously upon job completion (or future completion).
The prototype architecture is relatively simple and the core issue is presented in the pseudo code below (the full code cannot be published due to an NDA). *** Important - the code represents only the "problem", the possible solution in question is described in the text at the bottom together with the question.
//will be used as an entry point to the grid for each client that will submit jobs to the grid
public class GridClient{
//client node for submission that will be reused
private static Grid gNode = GridGain.start("config xml file goes here");
//provides the functionality of submitting multiple jobs to the grid for calculation
public int sendJobs2Grid(GridJob[] jobs){
Collection<GridCallable<GridJobOutput>> calls = new ArrayList<>();
for (final GridJob job : jobs) {
calls.add(new GridCallable<GridJobOutput>() {
#Override public GridJobOutput call() throws Exception {
GridJobOutput result = job.process();
return result;
}
});
}
GridFuture<Collection<GridJobOutput>> fut = this.gNode.compute().call(calls);
fut.listenAsync(new GridInClosure<GridFuture<Collection<GridJobOutput>>>(){
#Override public void apply(GridFuture<Collection<GridJobOutput>> jobsOutputCollection) {
Collection<GridJobOutput> jobsOutput;
try {
jobsOutput = jobsOutputCollection.get();
for(GridJobOutput currResult: jobsOutput){
//do something with the current job output BUT CANNOT call jobFinished(GridJobOutput out) method
//of sendJobs2Grid class here
}
} catch (GridException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
return calls.size();
}
//This function should be invoked asynchronously when the GridFuture is
//will invoke some processing/aggregation of the result for each submitted job
public void jobFinished(GridJobOutput out) {}
}
}
//represents a job type that is to be submitted to the grid
public class GridJob{
public GridJobOutput process(){}
}
Description:
The idea is that a GridClient instance will be used to in order to submit a list/array of jobs to the grid, notify the sender how many jobs were submitted and when the jobs are finished (asynchronously) is will perform some processing of the results. For the results processing part the "GridClient.jobFinished(GridJobOutput out)" method should be invoked.
Now getting to question at hand, we are aware of the GridInClosure interface that can be used with "GridFuture.listenAsync(GridInClosure> lsnr)"
in order to register a future listener.
The problem (if my understanding is correct) is that it is a good and pretty straightforward solution in case the result of the future is to be "processed" by code that is within the scope of the given GridInClosure. In our case we need to use the "GridClient.jobFinished(GridJobOutput out)" which is out of the scope.
Due to the fact that GridInClosure has a single argument R and it has to be of the same type as of GridFuture result it seems impossible to use this approach in a straightforward manner.
If I got it right till now then in order to use "GridFuture.listenAsync(..)" aproach the following has to be done:
GridClient will have to implement an interface granting access to the "jobFinished(..)" method let's name it GridJobFinishedListener.
GridJob will have to be "wrapped" in new class in order to have an additional property of GridJobFinishedListener type.
GridJobOutput will have to be "wrapped" in new class in order to have an addtional property of GridJobFinishedListener type.
When the GridJob will be done in addition to the "standard" result GridJobOutput will contain the corresponding GridJobFinishedListener reference.
Given the above modifications now GridInClosure can be used now and in the apply(GridJobOutput) method it will be possible to call the GridClient.jobFinished(GridJobOutput out) method through the GridJobFinishedListener interface.
So if till now I got it all right it seems a bit clumsy work around so I hope I have missed something and there is a much better way to handle this relatively simple case of asynchronous call back.
Looking forward to any helpful feedback, thanks a lot in advance.
Your code looks correct and I don't see any problems in calling jobFinished method from the future listener closure. You declared it as an anonymous class which always has a reference to the external class (GridClient in your case), therefore you have access to all variables and methods of GridClient instance.

Converting array of ObjectProxy objects to custom objects

I have a service which returns an Array of ObjectProxy objects. I would like to cast this to a custom object (a value object) and create an ArrayCollection. How can I do this?
Edited:
I am using Django and PyAMF for the backend. I had to write a custom SQL query and I am wrapping the resulting records in ObjectProxy and sending the whole result as an ArrayCollection.
Here is my client side code:
[ArrayElementType("SessionVO")]
[Bindable]
private var _list:ArrayCollection;
private function onSessionResultSuccess(event:ResultEvent):void
{
_list = new ArrayCollection(event.result as Array));
}
When I debug, I notice that the elements of event.result are of type ObjectProxy but the _list variable is null. Is there another than to loop over event.result and copy them into _list as SessionVO objects?
If you use the [RemoteClass] tag on your value objects, Flex remoting (Blaze, LCDS) will convert them to your value object for you when sending/returning from a remote service call.
The syntax for RemoteClass is
[RemoteClass(alias="com.co.custom.remote.class")] <--- point to the remote java/php class def
Public Class FooBar
{
public instance variable;
}
Your service can then return an array or hashtable of this class and Flex remoting will convert it for you.
There are cases where objects can become opaque, which you may need to create ObjectProxy code to do custom marshaling, but this is not common. The RemoteClass marshaling can handle very ccomplex object types, subtypes, embedded objects in objects, etc. As long as all of objects on the AS side are typed with RemoteClass, it works as expected.
I'm not sure what you mean by "ObjectProxy objects." I sounds to me like you are already getting returned an array of custom objects.
I recommend looking into some form of AMF gateway. Most serer side languages have an AMF add-on piece to them. It is built into ColdFusion, BlazeDS, and LiveCycle. PHP has ZendAMF and AMFPHP. .NET has FlourineFX and WebORB. Those are just a few examples.
AMF Gateways have a automatic conversion facility; so that the server side object can easily map to a client side object. Here is some info on the RemoteObject tag that describes this. Basically, you specify the RemoteClass metadata on your client side object, and usually specify some form of mapping on the server side object. The AMF Gateway magically handles the rest of the conversion.
In your RemoteObject result handler, you'll just have to convert the returned array to an ArrayCollection. Usually something like this:
var resultArray : Array = event.result as Array;
var resultCollection : ArrayCollection = new ArrayCollection(resultArray);
If you have no control over the server side piece of this application, you may be stuck looping over the results and manually converting them into client side Flex objects.
You can use com.adobe.serializers.utility.TypeUtility;
public function result_handler(event:ResultEvent):void{
var result:Array = TypeUtility.convertListToStrongType(event.result,YourValueObject) as Array;
}
make makeObjectsBindable="false" in the web service property, it will return object.
<s:WebService id="ws" wsdl="http://`xxxx/mobiledata/MobileDataService.asmx?wsdl" fault="fault(event)">
<s:operation
name="GetAll"
resultFormat="object"
result="GetData(event)" makeObjectsBindable="false"
/>
<s:operation
name="Create"
resultFormat="object"
result="SaveData(event)"
/>
</s:WebService>

Flex Event Dispatching

I have some questions with a particular structure of a program I'm writing.
I'm using a Remote Object to make a remote call to a Rails method (using WebOrb). The problem arises in the way that I get my data back.
Basically I have a function, getConditions, in which I add an event listener to my remote call and then I make the remote call. However, what I want to do is to get that data back in getConditions so I can return it. This is a problem because I only access the event result data in the event handler. Here's some basic code describing this issue:
public function getConditions():Array
{
remoteObject.getConditions.addEventListener("result", onConditionResult);
remoteObject.getConditions();
//Here is where I want to get my event.result data back
}
public function onConditionResult(event:ResultEvent):void
{
//Here's the data that I want
event.result;
}
How can I achieve this data turn-about?
Remote calls in flex are always asynchronous so you won't be able to call getConditions() and wait there for the result. You have to use a function closure to process the results, either by means of an event handler than you declare elsewhere or a dynamic one created immediately within getConditions(), like so:
remoteObject.getConditions.addEventListener("result", function(event:ResultEvent):void {
// Run the code that you would want to when process the result.
});
remoteObject.getConditions();
The advantage of doing the above is that you would be able to "see" parameters passed to getConditions() or the result of any logic that happened before addEventListener() in the function closure. This however, takes a slight performance hit compared to declaring an explicit function (for that exact reason).
I should also add that doing so requires you to clean up after yourselves to make sure that you are not creating a new listener for every request.
you do it like this
public function getConditions():Array
{
remoteObject.getConditions.addEventListener("result", onConditionResult);
remoteObject.getConditions();
}
public function callMyExtraFunction(data:Object):void
{
//Here is where you want to get your event.result data back
}
public function onConditionResult(event:ResultEvent):void
{
//Here's the data that you want
var data:Object = event.result;
callMyExtraFunction(data);
}
You could make use of Call Responder like so :
<s:CallResponder id="getOperationsResult"/>
then use these lines to get the result from get operations
getOperationResult.token = remoteObject.getOperation();
this creates the call and returns the result stores it in getOpresult
whnever u want to access this u can call that token or getOperationResult.lastResult
Hope that helps
Chris

TypeError: Error #1034: Type Coercion failed: cannot convert Object#1456c7b9 to mx.messaging.messages.IMessage

Im trying to connect a Flash client to BlazeDS. There has been some success with this from others using the vanilla BlazeDS setup. However I'm using the new Spring BlazeDS Integration from springsource and running aground.
The flash client actually seems to be working in that I can see the correct data in the body of the returned object, but for some reason unknown it fails casting as an IMessage. It fails in PollingChannel.as on this line with the subject line error
var messageList:Array = msg.body as Array;
for each (var message:IMessage in messageList) <--
On application load I register a whole bunch of classes like so
registerClassAlias( "flex.messaging.messages.RemotingMessage", RemotingMessage );
registerClassAlias("mx.messaging.messages.IMessage", IMessage);
etc..
my code is basically
var channelSet:mx.messaging.ChannelSet = new mx.messaging.ChannelSet();
var channel:mx.messaging.channels.AMFChannel = new AMFChannel("my-amf", "http://localhost:8400/SpringA/messagebroker/amf");
channelSet.addChannel(channel);
var consumer:mx.messaging.Consumer = new Consumer();
consumer.channelSet = channelSet;
consumer.destination = "simple-feed";
consumer.subscribe();
consumer.addEventListener(MessageEvent.MESSAGE, test);
private function test(event:IMessage)
{
trace("msg..");
// breakpoint never makes it here
}
I have a flex client which works 100% with same destination/channel.
The error in the title means that you, for some reason, got an object that is not implementing or extending the IMessage interface, therefore the loop can not cast it in this part:
for each (var message:IMessage in messageList){
Either you should somehow make sure that you don't add anything that is not extending or implementing IMessage, or check if the variable IS actually ext./imp. it. Also - if you want to do that, you will have to change the for each like this:
for each (var obj in messageList){
if (obj is IMessage){
var message:IMessage = obj as IMessage;
// DO STUFF HERE
}
}
Add this Object mapping:
registerClassAlias("flex.messaging.io.ObjectProxy", ObjectProxy);
If on your Java VO objects you have overridden the hashcode() method, this situation could happen.
Remove the hashcode() override (if you are able to).
See my blog for the backstory on how I discovered this. http://squaredi.blogspot.com/2013/12/remoting-landmine-without-stack-trace.html
I had the same error when trying to send an actionscript object to the backend. My problem was that my c# equivalent object was missing an public parameterless constructor.

Multiple asynchronous calls to populate an object

I'm developing a Flex application and am having some trouble working with asynchronous calls. This is what I would like to be able do:
[Bindable] var fooTypes : ArrayCollection();
for each (var fooType : FooType in getFooTypes()) {
fooType.fooCount = getFooCountForType(fooType);
itemTypes.addItem(fooType);
}
The issue I'm running into is that both getFooTypes and getFooCountForType are asynchronous calls to a web service. I understand how to populate fooTypes by setting a Responder and using ResultEvent, but how can I call another service using the result? Are there any suggestions/patterns/frameworks for handling this?
If possible, I Strongly recommed re-working your remote services to return all the data you need in one swoop.
But, if you do not feel that is possible or practical for whatever reason, I would recommend doing some type of remote call chaining.
Add all the "remote calls" you want to make in array. Call the first one. In the result handler process the results and then pop the next one and call it.
I'm a bit unclear from your code sample when you are calling the remote call, but I assume it part of the getFooCountForType method. Conceptually I would do something like this. Define the array of calls to make:
public var callsToMake : Array = new Array();
cache the currently in process fooType:
public var fooType : FooType;
Do your loop and store the results:
for each (var fooType : FooType in getFooTypes()) {
callsToMake.push(fooType);
// based on your code sample I'm unclear if adding the fooTypes to itemTypes is best done here or in the result handler
itemTypes.addItem(fooType);
}
Then call the remote handler and save the foo you're processing:
fooType = callsToMake.pop();
getFooCountForType(fooTypeToProcess);
In the result handler do something like this:
// process results, possibly by setting
fooType.fooCount = results.someResult;
and call the remote method again:
fooType = callsToMake.pop();
getFooCountForType(fooTypeToProcess);

Resources