You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by fa...@apache.org on 2014/09/14 13:51:16 UTC

svn commit: r1624841 - in /qpid/proton/branches/fadams-javascript-binding: proton-c/bindings/javascript/binding.js tests/javascript/codec.js tests/javascript/message.js

Author: fadams
Date: Sun Sep 14 11:51:15 2014
New Revision: 1624841

URL: http://svn.apache.org/r1624841
Log:
Implement better handling of contentType including adding a mechanism to serialise and deserialise native JavaScript Objects as JSON as an alternative to using the AMQP type system. The contentType handling also transparently converts text MIME types to String on the received message

Modified:
    qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/binding.js
    qpid/proton/branches/fadams-javascript-binding/tests/javascript/codec.js
    qpid/proton/branches/fadams-javascript-binding/tests/javascript/message.js

Modified: qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/binding.js
URL: http://svn.apache.org/viewvc/qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/binding.js?rev=1624841&r1=1624840&r2=1624841&view=diff
==============================================================================
--- qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/binding.js (original)
+++ qpid/proton/branches/fadams-javascript-binding/proton-c/bindings/javascript/binding.js Sun Sep 14 11:51:15 2014
@@ -1199,7 +1199,22 @@ _Message_._preEncode = function() {
 
     body.clear();
     if (this['body']) {
-        body['putObject'](this['body']);
+        var contentType = this['getContentType']();
+        if (contentType) {
+            var value = this['body'];
+            if (contentType === 'application/json' && JSON) { // Optionally encode body as JSON.
+                var json = JSON.stringify(value);
+                value = new Data['Binary'](json);
+            } else if (!(value instanceof Data['Binary'])) { // Construct a Binary from the body
+                value = new Data['Binary'](value);
+            }
+            // As content-type is set we send as an opaque AMQP data section.
+            this['setInferred'](true);
+            body['putBINARY'](value);
+        } else { // By default encode body using the native AMQP type system.
+            this['setInferred'](false);
+            body['putObject'](this['body']);
+        }
     }
 };
 
@@ -1240,6 +1255,15 @@ _Message_._postDecode = function(decodeB
     if (body.next()) {
         this['data'] = body;
         this['body'] = body['getObject']();
+        var contentType = this['getContentType']();
+        if (contentType) {
+            if (contentType === 'application/json' && JSON) {
+                var json = this['body'].toString(); // Convert Binary to String.
+                this['body'] = JSON.parse(json);
+            } else if (contentType.indexOf('text/') === 0) { // It's a text/* MIME type
+                this['body'] = this['body'].toString(); // Convert Binary to String.
+            }
+        }
     } else {
         this['data'] = null;
         this['body'] = null;
@@ -1528,7 +1552,7 @@ _Message_['getUserID'] = function() {
 /**
  * Set the user id for a message. This method takes a {@link proton.Data.Binary}
  * consuming the underlying raw data in the process. For convenience this method
- * also accepts a {@link proton.Data.Uuid} or a string, converting them to a
+ * also accepts a {@link proton.Data.Uuid}, number or string, converting them to a
  * Binary internally. N.B. getUserID always returns a {@link proton.Data.Binary}
  * even if a string or {@link proton.Data.Uuid} has been passed to setUserID.
  * @method setUserID

Modified: qpid/proton/branches/fadams-javascript-binding/tests/javascript/codec.js
URL: http://svn.apache.org/viewvc/qpid/proton/branches/fadams-javascript-binding/tests/javascript/codec.js?rev=1624841&r1=1624840&r2=1624841&view=diff
==============================================================================
--- qpid/proton/branches/fadams-javascript-binding/tests/javascript/codec.js (original)
+++ qpid/proton/branches/fadams-javascript-binding/tests/javascript/codec.js Sun Sep 14 11:51:15 2014
@@ -1,3 +1,4 @@
+#!/usr/bin/env node
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -20,7 +21,10 @@
 
 /**
  * This is a fairly literal JavaScript port of codec.py used to unit test the
- * proton.Data wrapper class.
+ * proton.Data wrapper class. This suite of tests is actually testing the low
+ * level implementation methods used to access the AMQP type system and in
+ * practice most normal users wouldn't need to call these directly, rather users
+ * should simply use the putObject() and getObject() methods.
  */
 
 // Check if the environment is Node.js and if not log an error and exit.
@@ -357,7 +361,7 @@ DataTest.testString = function() {
 
 DataTest.testBigString = function() {
     // Try a 2MB string, this is about as big as we can cope with using the default
-    // emscripten heap size.
+    // emscripten heap size. TODO add run-time mechanism to increase heap size.
     console.log("testBigString");
     var data = "";
     for (var i = 0; i < 2000000; i++) {
@@ -387,7 +391,7 @@ DataTest.testBinary = function() {
     console.log("testBinary");
     this._test("binary", new proton.Data.Binary(["t".char(), "h".char(), "i".char(), "s".char()]),
                new proton.Data.Binary("is"), new proton.Data.Binary("a"), new proton.Data.Binary("test"),
-               new proton.Data.Binary("of"), new proton.Data.Binary("ВИНАРЫ"));
+               new proton.Data.Binary("of"), new proton.Data.Binary("двоичные данные"));
     console.log("OK\n");
 };
 

Modified: qpid/proton/branches/fadams-javascript-binding/tests/javascript/message.js
URL: http://svn.apache.org/viewvc/qpid/proton/branches/fadams-javascript-binding/tests/javascript/message.js?rev=1624841&r1=1624840&r2=1624841&view=diff
==============================================================================
--- qpid/proton/branches/fadams-javascript-binding/tests/javascript/message.js (original)
+++ qpid/proton/branches/fadams-javascript-binding/tests/javascript/message.js Sun Sep 14 11:51:15 2014
@@ -1,3 +1,4 @@
+#!/usr/bin/env node
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -56,20 +57,6 @@ var range = function(start, stop, step) 
     return result;
 };
 
-/**
- * Quick and dirty Object comparison using valueOf(). We need a comparison method.
- * as some of the types we might want to compare are Object types (proton.Data.Uuid,
- * proton.Data.Binary etc.). The approach here is absolutely *not* a robust deep
- * Object comparison method, but it is relatively simple & good enough for the test cases.
- */
-var compare = function(x, y) {
-    if (x === null) {
-        assert(y === x);
-    } else {
-        assert(y.valueOf() === x.valueOf());
-    }
-};
-
 
 // Extend TestCase by creating a new Test class as we're using it in a few places.
 var Test = function() { // Test constructor.
@@ -100,6 +87,22 @@ Test.prototype.tearDown = function() {
 var AccessorsTest = new Test();
 
 AccessorsTest._test = function(name, defaultValue, values) {
+    /**
+     * For the case of Binary values under test we retrieve their toString().
+     * This is because the methods under test "consume" the data, in other
+     * words ownership of the underlying raw data transfers to the Message
+     * object so the sent Binary object becomes "empty" after calling the setter.
+     * In addition Binary values merely contain a "pointer" to the raw data
+     * so even a "deepEqual" comparison won't accurately compare two Binaries.
+     * For these tests we "cheat" and store an array of characters in the
+     * Binary so that we can use their String forms for comparison tests.
+     *
+     * We also get the String value of Uuid for the case of setUserID because
+     * that method transparently creates Binary values from the String form
+     * of non-Binary data passed to it. It's a convenience method, but makes
+     * testing somewhat more fiddly.
+     */
+
     // First get the values passed to the method.
     var values = Array.prototype.slice.apply(arguments, [2]);
     // If the first element of values is actually an Array then use the Array.
@@ -112,23 +115,25 @@ AccessorsTest._test = function(name, def
 
     // Get the message's default value first.
     var d = this.msg[getter]();
+    d = (d instanceof proton.Data.Binary) ? d.toString() : d;
 
     // Compare the message's default with the expected default value passed in the test case.
-    compare(d, defaultValue);
+    assert.deepEqual(d, defaultValue);
 
     for (var i = 0; i < values.length; i++) {
         var v = values[i];
-        /**
-         * For the case of Binary values under test we retrieve their valueOf().
-         * This is because the methods under test "consume" the data, in other
-         * words ownership of the underlying raw data transfers to the Message
-         * object so the v object becomes "empty" after calling the setter.
-         */
-        var value = (v instanceof proton.Data.Binary) ? v.valueOf() : v;
+
+        var value = (v instanceof proton.Data.Binary ||
+                     (name === 'UserID' && v instanceof proton.Data.Uuid)) ? v.toString() : v;
+        value = (v instanceof Date) ? v.valueOf() : v;
 
         this.msg[setter](v); // This call will "consume" Binary data.
+
         var gotten = this.msg[getter]();
-        compare(value, gotten);
+        gotten = (gotten instanceof proton.Data.Binary) ? gotten.toString() : gotten;
+        gotten = (gotten instanceof Date) ? gotten.valueOf() : v;
+
+        assert.deepEqual(value, gotten);
     }
 };
 
@@ -185,7 +190,7 @@ AccessorsTest.testDeliveryCount = functi
 
 AccessorsTest.testUserID = function() {
     console.log("testUserID");
-    this._test("UserID", "", "asdf", "fdsa", new proton.Data.Binary("ВИНАРЫ"), "", new proton.Data.Uuid(), "");
+    this._test("UserID", "", "asdf", "fdsa", 123, new proton.Data.Binary("ВИНАРЫ"), new proton.Data.Uuid(), "");
     console.log("OK\n");
 };
 
@@ -278,27 +283,79 @@ CodecTest.testRoundTrip = function() {
     console.log("OK\n");
 };
 
-/*
-// load and save are deprecated, might to an equivalent using encode/decode
-var LoadSaveTest = new Test();
+/**
+ * This test tests the transparent serialisation and deserialisation of JavaScript
+ * Objects using the AMQP type system (this is the default behaviour).
+ */
+CodecTest.testRoundTripBodyObject = function() {
+    console.log("testRoundTripBodyObject");
+    this.msg.setAddress("address");
+    this.msg.body = {array: [1, 2, 3, 4], object: {name: "John Smith", age: 65}};
 
+    var data = this.msg.encode();
+    var msg2 = new proton.Message();
+    msg2.decode(data);
 
-LoadSaveTest.testIntegral = function() {
-    console.log("testIntegral");
+    assert(this.msg.getAddress() === msg2.getAddress());
+    assert(this.msg.getContentType() === msg2.getContentType());
+    assert.deepEqual(this.msg.body, msg2.body);
 
+    msg2.free();
     console.log("OK\n");
 };
 
-LoadSaveTest.testFloating = function() {
-    console.log("testFloating");
+/**
+ * This test tests the transparent serialisation and deserialisation of JavaScript
+ * Objects as JSON. In this case the "on-the-wire" representation is an AMQP binary
+ * stored in the AMQP data section.
+ */
+CodecTest.testRoundTripBodyObjectAsJSON = function() {
+    console.log("testRoundTripBodyObjectAsJSON");
+    this.msg.setAddress("address");
+    this.msg.setContentType("application/json");
+    this.msg.body = {array: [1, 2, 3, 4], object: {name: "John Smith", age: 65}};
 
+    var data = this.msg.encode();
+    var msg2 = new proton.Message();
+    msg2.decode(data);
+
+    assert(this.msg.getAddress() === msg2.getAddress());
+    assert(this.msg.getContentType() === msg2.getContentType());
+    assert.deepEqual(this.msg.body, msg2.body);
+
+    msg2.free();
+    console.log("OK\n");
+};
+
+/**
+ * By default the API will encode using the AMQP type system, but is the content-type
+ * is set it will encode as an opaque Binary in an AMQP data section. For certain
+ * types however this isn't the most useful thing. For application/json (see
+ * previous test) we convert to and from JavaScript Objects and for text/* MIME
+ * types the API will automatically convert the received Binary into a String.
+ */
+CodecTest.testRoundTripMIMETextObject = function() {
+    console.log("testRoundTripMIMETextObject");
+    this.msg.setAddress("address");
+    this.msg.setContentType("text/plain");
+    this.msg.body = "some text";
+
+    var data = this.msg.encode();
+    var msg2 = new proton.Message();
+    msg2.decode(data);
+
+    assert(this.msg.getAddress() === msg2.getAddress());
+    assert(this.msg.getContentType() === msg2.getContentType());
+    assert.deepEqual(this.msg.body, msg2.body);
+
+    msg2.free();
     console.log("OK\n");
 };
-*/
 
 
+// load and save are deprecated so not implemented in the JavaScript binding.
+
 AccessorsTest.run();
 CodecTest.run();
-//LoadSaveTest.run();
 
 



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org