AMF as a REST format, using BlazeDS and AS3's URLLoader - actionscript-3

I have a ColdFusion server with an HTTP API that's currently returning either JSON or XML formatted responses. Internally, all of these responses are represented using the ColdFusion 'struct' type, and then converted to the appropriate format before being presented to the requesting client.
The client team using this API has requested that in addition to JSON and XML, we also return AMF objects. Now, I've seen (and have myself made) arguments against using AMF as a 'returned format' in a REST scenario rather than as an RPC format. I'm not interested in comments about whether or not it's a good idea -- I'd just like to know if it will work. If not, I'm hoping for clear reasons why it won't. If it will work, I'd love some guidance on how to 'makeitgo'.
So, in the interest of achieving that proof of concept example, I'm trying to serialize a two-element ColdFusion Array using BlazeDS, then consume that serialized object in a Flash Player 10/AS3 test.
Here's what the code looks like on the server side:
//the test object I'm trying to return (keeping it simple)
var testArray = ArrayNew(1);
testArray[1]="test";
testArray[2]="monkey";
//set up output stream to requesting client
var pc = getPageContext();
var response = pc.getResponse();
var out = response.getOutputStream();
response.setHeader("Content-Type", "application/x-amf");
//not sure if AmfMessageSerializer is the appropriate class to be using here
var amfMessageSerializer = createObject("java", "flex.messaging.io.amf.AmfMessageSerializer");
var amfTrace = createObject("java", "flex.messaging.io.amf.AmfTrace"); //needed by initialize() method
amfMessageSerializer.initialize(variables.SerializationContext.getSerializationContext(), out, amfTrace);
amfMessageSerializer.writeObject(testArray);
out.close();
Now, this generates some kind of binary data. If I stick that in a .cfm and try to load the page, I get something I can read in a hex editor that looks like it contains the array members I set. One note here: part of the response message includes "flex.messaging.io.ArrayCollection." I'm not knowledgeable enough to know what this tells me yet: anyone who can provide details about typing between the two environments will have many thanks from me.
The next step is to try and consume this on the FlashPlayer side. Here's what the stripped down AS3 looks like:
myURLloader.dataFormat = URLLoaderDataFormat.BINARY;
myURLloader.addEventListener(Event.COMPLETE, completeHandler);
myURLloader.load(myURLRequest);
function completeHandler( event : Event) : void
{
var serverResponse : ByteArray = new ByteArray();
serverResponse = event.target.data;
//read the response into a generic object
var responseObject : Object = new Object();
responseObject = serverResponse.readObject(); //fails here: error #2006
}
As indicated by the comment, this fails with error #2006 "Supplied index is out of bounds." I've searched around for common causes of this error, but haven't found any clear answers. I've tried resetting the byteArray.position to both the beginning and the end of the byteArray before attempting readObject() -- changing it to the end spits out error #2030 "End of file was encountered" (as one might expect), but I've verified that the .position defaults to 0, which generates the #2006 error.
I'm pretty sure that the issue here lies with the choice of BlazeDS calls I've used; I think I might be serializing a message when I want to be serializing an object. Unfortunately, the JavaDoc autogenerated docs for BlazeDS are ... less than enlightening. All of the more readable resources I've found focus on Flash Remoting and RPC examples. Surprising, I know; but it is what it is. I'm using Adobe BlazeDS docs; if anyone else has a better resource I'd be quite appreciative.
As a reminder to anyone answering: I realize this isn't a typical use of AMF. I'm not interested in responses that suggest the typical RPC method or to switch to Flash Remoting rather than HTTP/GET. What I need is an AMF serialized response from an HTTP request which can be deserialized on a Flash Player client. I don't have a choice in this matter. I do need to know if this is possible, and if so I'm hoping for some guidance on how to make it work. I welcome any and all suggestions aside from "Just don't use AMF!" or "Just switch to Flash Remoting!"
Update: made a little bit of progress with this:
1) on the server side, I used the ASObject class of blazeDS to create a simple ASObject and populate it with a key-value pair.
2) on both the client and server side, I had to make sure to set the object encoding to AMF0. The same technique in AMF3 generates that #2006/Out of bounds error, and I'm not yet sure why.
Here's what the code now looks like on the server-side:
//set up output stream to requesting client
var pc = getPageContext();
var response = pc.getResponse();
var out = response.getOutputStream();
response.setHeader("Content-Type", "application/x-amf");
//not sure if AmfMessageSerializer is the appropriate class to be using here
var amfMessageSerializer = createObject("java", "flex.messaging.io.amf.AmfMessageSerializer");
amfMessageSerializer.setVersion(variables.MessageIOConstants.AMF0);
var amfTrace = createObject("java", "flex.messaging.io.amf.AmfTrace"); //needed by initialize() method
amfMessageSerializer.initialize(variables.SerializationContext.getSerializationContext(), out, amfTrace);
var ASObject = createObject("java", "flex.messaging.io.amf.ASObject");
ASObject.put("testKey", "testValue"); //simple key-value map to return to caller
amfMessageSerializer.writeObject(testArray);
out.close();
The primary difference here is that rather than trying to serialize a CF Array, I'm building a response object (of type ASObject) manually.
On the client side, the code now looks like this:
myURLloader.dataFormat = URLLoaderDataFormat.BINARY;
myURLloader.addEventListener(Event.COMPLETE, completeHandler);
myURLloader.load(myURLRequest);
function completeHandler( event : Event) : void
{
var serverResponse : ByteArray = new ByteArray();
serverResponse = event.target.data;
serverResponse.objectEncoding = ObjectEncoding.AMF0; //important
//read the response into a generic object
var responseObject : Object = new Object();
responseObject = serverResponse.readObject();
trace(responseObject.testKey); //displays "testValue", as expected
}
The difference here is that I've explicitly set the ObjectEncoding to AMF0 (defaults to AMF3).
If I switch the objectEncoding to AMF3 on both server and client, I'd expect things to work, but I still get the 2006: out of bounds error. The ByteArray.length property is the same in both the AMF0 and AMF3 cases, but the content of the returned object is different (when viewed in a hex editor).
Changing the objectEncoding in the first example I provided had no effect on the error that was being produced.
So, then, the issue seems to have been an attempt to serialize the ColdFusion array: the AMFSerializer doesn't know how to handle it. It needs to explicitly be built as an ASObject. I'll build a sanitize function to do the conversion between the two types.
I feel like progress has been made (and thanks for all the feedback in comments and answers), but I've still got a lot of unanswered questions. Does anyone have any input on why this might be failing when I try to encode in AMF3, but not for AMF0? I don't have any attachment to one or the other, but I don't like this 'throw things at the wall and see which ones stick' method of solving the problem... I'd like to know why it's failing =/

I did that a some time ago..you can check my blog post from here, maybe it can help you. I was using Java on the server side, not CF.

Related

why fabricjs kclass fromobject returning undefined on new version?

yesterday i have changed fabricjs version in our application. suddenly kclass.fromObject returning undefined.
my previous version is 1.7.22 and currently using 3.6.1 https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.1/fabric.min.js
kclass.fromobject returning undefined. but objects[i] has data.
> var klass = fabric.util.getKlass(objects[i].type);
> console.log(klass.fromObject(objects[i])); //returning undefined on 3.6.1
> fabricObj.add(klass.fromObject(objects[i]));
could you please let me know how to fix this issue?
Here is the screenshot
Your objects array contains just plain javascript objects that represent serialized Fabric objects (like path, circles, whatever).
Before rendering these plain javascript objects you need to transform them in Fabric objects. This process is called deserialization.
Your code does it, but only the if the async property of the variable klass is true.
It happens here:
var klass = fabric.util.getKlass(objects[i].type);
if (klass.async) {
klass.fromObject(objects[i], function (img) {
canvas1.add(img);
});
}
The object is deserialized, passed as an argument to the callback function and then added to the canvas, and this is great.
The problem is in the else branch of your conditional, where nothing of that happens. The only code present is this:
else {
console.log(objects[i]);
canvas1.add((objects[i]));
}
Here you are trying to add the plain object to the canvas, and that triggers an error.
One simple solution is to remove the if / else and always execute the deserialization step. If for other reasons you need to maintain the if / else conditional, you can simply deserialize the object in the else path too.
Here is a working Fiddle that preserves the conditional.
Why did it work in the previous version of Fabric? It is hard to say. Maybe that type of object was marked as async, so triggering the right path. Or maybe the canvas.add method was automatically deserializing javascript objects.

Firebase: What is being done behind the onDisconnect method? (AS3)

First, I want to mention, I understand how the Firebase onDisconnect method works in JavaScript. It tells the server what to do once the user is disconnected, in advance.
Now, I am using AS3. How should I tell the server the same thing as achieved by the 'onDisconnect' method?
When I tried debugging the code in JavaScript, it doesn't seem to send something to the server.(or maybe i am wrong).
Sample code in JavaScript:
userRef.on('value', function(snapshot) {
if (snapshot.val()) {
userRef.onDisconnect().remove(); //this line does the magic
}
});
What is being done by the onDisconnect method which tells the server what to do? What is the equivalent code if written in AS3?
EDITED:
The code in AS3, as reference by here, it works for Realtime Database.
private var myStream:URLStream;
private function loadLiveFeed():void
{
var header:URLRequestHeader = new URLRequestHeader("Accept", "text/event-stream");
var request:URLRequest = new URLRequest("https://<YOUR-PROJECT-ID>.firebaseio.com/breakingnews.json");
request.requestHeaders.push(header);
myStream:URLStream = new URLStream();
myStream.addEventListener(ProgressEvent.PROGRESS, progress);
myStream.load(request);
}
private function progress(event:ProgressEvent):void
{
var message:String = myStream.readUTFBytes(myStream.bytesAvailable);
trace(message);
}
The code you shared accesses the Firebase Database through its REST API:
new URLRequest("https://<YOUR-PROJECT-ID>.firebaseio.com/breakingnews.json");
This means that it is using a connectionless method to interact with the database. Unfortunately that also means that there is no way to register an onDisconnect() handler, since it would essentially have to fire between any two HTTP calls that you make.
No time to answer this, but you'd have to reverse engineer the communication. Under the hood, it's all just HTTP (or similar) as can be seen in the As3 code. To know what's going on exactly, get a working example code in JavaScript that contains the magic line you are curious about, then execute it in the browser. All requests can be monitored in the developer tools of the browser. You should be able to identify what's being sent.
Also, it's JavaScript, which means you have to have the source code which you can simply read. It might be minified and/or obfuscated, but maybe you can find a readable one.
With the knowledge of what the bare requests look like, you can then implement an API of your own in any language that's capable of performing the necessary network communication.

Actionscript 3 (Kongregate ?) server-server side calls

I'm a c++ programmer who's been forced to do some tweaks to an existing AS3 game to use the kongregate api for monetization and whatnot.
I've had no big trouble with the AS3 syntax, but now in the kongregate docs it refers to "server-side" calls which use a strange http POST syntax. Something like this: http://developers.kongregate.com/docs/rest/use-item
Can anyone point me to what it's doing (not the actual effect, that's pretty well covered by the docs)? Is it using some other language? A part of AS3 that I don't know about (that doesn't look much like a high level OO language). And what does it mean server-side? How can I write server code for an app that I build into a SWF file and upload to the server?
I feel there is a big chunk of something I'm missing to be able to research what is going on, but everyone in the comments I've seen talks about "server-side" as a given, without giving me any pointers to the basics I should know to actually use it.
Thanks,
Jaime
My understanding is that the docs are showing you what the api is expecting (in terms of HTTP request) and it's up to you to implement it in Actionscript.
If that's the case, you could use the URLLoader class.
Basically, you'd do something like this:
var url:String = "http://www.kongregate.com/api/use_item.json";
var request:URLRequest = new URLRequest();
request.url = url;
request.method = URLRequestMethod.POST
request.data = new URLVariables();
request.data.api_key = "MyApiKey";
// etc...
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.TEXT;
loader.addEventListener(Event.COMPLETE,handleComplete);
loader.load(request);
function handleComplete(e:Event):void {
var loader:URLLoader = e.currentTarget as URLLoader;
trace(loader.data); // a string containing the service response
}
You should also handle async errors (which I ommited in this sample). Another thing you should do is decode the JSON string into an Object to make working with the data easier. I suggest you google around for some library, there are a couple out there (off the top of my head, as3corelib, which was sponsered by adobe, had a JSON parser).

Loading an XML in ActionScript 3 before an event listener happens

I'm trying to fill some data from an xml feed we made into my Flash movie. The main action of this is in the constructor for MediaElementJS's .as file.
Anyway, the main problem is that I keep reading there is no way to load a URL synchronously in AS3 (which i still find hard to believe). This constructor calls both parse('url') and a function addEventListener(EVENT.ADDED_TO_STAGE, initializeAds);
Now the ads need info from the XML but the XML aint ready yet. I tried to call the ads at the end of the XML parser when I knew it would be prepped but it messes them up and the ad values never change from their defaults..
Oh wherefor art thou actionscript locking mechanism..
So is there anyway to preload data from a URL?
CODE:
public function LoadXML(e:Event):void
{
removeEventListener(Event.COMPLETE, LoadXML);
var xmlData:XML = new XML(e.target.data);
episodeData.pre.type = xmlData.episode.pre.ad.#type;
episodeData.pre.url = xmlData.episode.pre.ad.text();
episodeData.video = Number(xmlData.episode.video.#id); /*************** I CAN'T REMEMBER ***********/
episodeData.pageTitle = xmlData.episode.video.#pagetitle;
episodeData.title = xmlData.episode.video.#title;
episodeData.source = xmlData.episode.video.source.text();
episodeData.post.type=xmlData.episode.post.ad.#type;
episodeData.post.url=xmlData.episode.post.ad.text();
episodeData.nextEpisode=xmlData.episode.post.nextepisode.text(); //if not empty redirect to this
xmlLoading = false;
//THIS IS WHERE I TRIED TO CALL THE FUNCTION I NEED TO LOAD LATER
}
public function parse()
{
var xmlLoader:URLLoader = new URLLoader();
//var xmlData:XML = new XML();
xmlLoader.load(new URLRequest(rootURL + '/episode.aspx?associd=' + _episode));
//xmlLoader.addEventListener(Event.COMPLETE, processXML);
xmlLoader.addEventListener(Event.COMPLETE, LoadXML);
}
I've tried it with a static URL address and whatnot of course but no dice.
The code in the constructor works if I dynamically assign a static value but if I try chaining to events together to get the dynamic value and dynamic assignment it crunches.
In the constructor, definitely runs both by themselves:
parse();
// Google IMA EventListener
addEventListener(Event.ADDED_TO_STAGE, initialize);
Loading URLs is always asynchronous, so add the event listener in the response function for the URL loader.
Now your question sounds like you tried that but had some problem, so post that code and let us take a look.
Edit START
When I have multiple asynchronous calls that happen and I need something to happen after both of them are done I usually use booleans to store if each one has happened yet, then in a third function they both call I check both the booleans.
Here's how I'd do that:
protected function viewnavigatorapplication1_preinitializeHandler(event:FlexEvent):void
{
var loader1:Loader = new Loader();
var loader2:Loader = new Loader();
loader1.addEventListener(Event.COMPLETE, loader1_completeHandler);
loader1.load(new URLRequest("http://www.whitehouse.gov"));
loader2.addEventListener(Event.COMPLETE, loader2_completeHandler);
loader2.load(new URLRequest("http://www.nasa.gov"));
}
private function loader1_completeHandler():void
{
loader1Done = true;
//Maybe do some stuff here
moveOn();
}
private function loader2_completeHandler():void
{
loader2Done=true;
//Maybe do some stuff here
moveOn();
}
private function moveOn():void
{
if(!loader1Done||!loader2Done)
return;
//Do whatever needs to be done once both asynchronous events have completed
}
If this isn't your problem I think you need to provide more of the code in place of the comments that indicate other things happen, because it is a bit unclear.
For example I'm not sure what you mean by "The code in the constructor works if I dynamically assign a static value but if I try chaining to events together to get the dynamic value and dynamic assignment it crunches." Also since there's no example of the data or what the rootURL is there's no way to debug from here to understand what's going wrong.
Since there's no error we would need to be able to re-compile some portion of your code locally to give any better feedback.
Edit END
Blocking or synchronous calls are a horrible idea with regard to network communications due to the lack of reliability of networks and/or servers. If a front end application locked up to wait for a response before doing any other processing it would result in a horrible user experience, this is why there is no synchronous remote calls.
What happens with a synchronous call when the server bombs out, the client remains locked even though no response will result, the user can't interact with anything else in the front-end because it's waiting for said response which will never come? It's much better that remote calls of any sort are done in an asynchronous fashion, the same is true with local disk access in Java (or otherwise) where using asynchronous non-blocking calls is generally a better way to go to allow the other processes within an application to continue regardless of the state or use on the disk.
What you're doing should work just fine, you make a call to a remote service, it responds with some result and hits your "listener" or "callback" function then you want to do something with the results you can call another function, and the data is there.
It sounds to me like the only thing that's not happening is updates after the fact aren't being reflected in the UI, this is probably due to a lack of Bindable metadata/event dispatching for the properties. Have you inspected the result in the event that returns, have you put breakpoints in the method that is meant to be called after the data has returned? What you're doing is completely possible and it even looks like you have most of it right, but there's definitely something your doing wrong that's resulting in you not being able to make this work. If you can explain the behavior a bit clearer that will help, also what do you do here:
//THIS IS WHERE I TRIED TO CALL THE FUNCTION I NEED TO LOAD LATER

Understanding Json structure generated by an AJAX-enabled WCF Service

Good afternoon
In Visual Studio 2010 I am able to add to my solution a new item called in AJAX-enabled WCF service. That will add a new a .svc file.
Later, I have created a method just for debugging purposes:
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class DataAccessService
{
[WebGet]
[OperationContract]
public MyClass DoWork()
{
var o = new MyClass
{
Id = 1,
FirstName = "Junior",
LastName = "Mayhe"
};
return o;
}
}
When debugging here is the resulting Json string:
{"d":
{"__type":"MyClass:#MyProject",
"Id":1,
"FirstName":"Junior",
"LastName":"Mayhe"
}
}
The question is, what is this "d"?
Is it some result type code for a Json string, and if so, are there other codes?
thanks in advance
It is only "d", and it is intended as protection against some cross-site scripting attacks.
E.g. consider a method that returns an int array of sensitive data (e.g. bank account balances). It can be returned as:
[10000,12300,15000]
Or:
{"d":[10000,12300,15000]}
The problem is that in the first case, there's a (very advanced and obscure but nevertheless real) attack whereby another site can steal this data by including a call to the service in a tag and overriding the JavaScript array constructor. The attack is not possible if the JSON looks like the latter case.
There was some talk within Microsoft to extend the format beyond just "d", but I don't think it ever went anywhere.
Your response is simply getting encapsulated with a parent object called "d". It was introduced in ASP.NET 3.5 web services as a security enhancement to prevent JSON hijacking.
The client proxies generated for your service will strip out the "d" so you will never really even know it was there. But since you're service isn't really going to be consumed for anything other than AJAX requests, you'll have to access your JSON objects through the ".d" property. I would recommend using JSON2 to parse the response, since not all browsers have native JSON support at the time of this writing.
You can read a little more about the security problem here.